'use strict' ; import * as vscode from 'vscode' ; import * as chai from 'chai' ; import * as sinon from 'sinon' ; import * as sinonChai from 'sinon-chai' ; import * as path from 'path' ; import * as tmp from 'tmp' ; import { TestUtil } from '../TestUtil' ; import { VSCodeBlockchainOutputAdapter } from '../../extension/logging/VSCodeBlockchainOutputAdapter' ; import { UserInputUtil } from '../../extension/commands/UserInputUtil' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { FabricWallet } from 'ibm-blockchain-platform-wallet' ; import { FabricWalletRegistry , FabricWalletRegistryEntry , FileConfigurations , LogType , FabricEnvironmentRegistry , FabricEnvironmentRegistryEntry , EnvironmentType } from 'ibm-blockchain-platform-common' ; const should = chai . should ( ) ; chai . use ( sinonChai ) ; describe ( 'AddWalletCommand' , ( ) => { let mySandBox ; let logSpy ; let showInputBoxStub ; let browseStub ; let choseWalletAddMethod ; let uri ; let getIdentitiesStub ; let executeCommandStub ; let migrateToV2WalletStub ; before ( async ( ) => { mySandBox = sinon . createSandbox ( ) ; await TestUtil . setupTests ( mySandBox ) ; } ) ; beforeEach ( async ( ) => { logSpy = mySandBox . spy ( VSCodeBlockchainOutputAdapter . instance ( ) , 'log' ) ; await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; await FabricWalletRegistry . instance ( ) . clear ( ) ; showInputBoxStub = mySandBox . stub ( vscode . window , 'showInputBox' ) ; browseStub = mySandBox . stub ( UserInputUtil , 'browse' ) ; choseWalletAddMethod = mySandBox . stub ( UserInputUtil , 'showAddWalletOptionsQuickPick' ) ; uri = vscode . Uri . file ( tmp . dirSync ( ) . name ) ; getIdentitiesStub = mySandBox . stub ( FabricWallet . prototype , 'getIdentityNames' ) ; migrateToV2WalletStub = mySandBox . stub ( FabricWallet . prototype , 'migrateToV2Wallet' ) . resolves ( ) ; } ) ; afterEach ( async ( ) => { mySandBox . restore ( ) ; } ) ; it ( 'should handle the user cancelling selecting a method to add a new wallet' , async ( ) => { choseWalletAddMethod . resolves ( ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; showInputBoxStub . should . not . have . been . called ; browseStub . should . not . have . been . called ; logSpy . should . not . have . been . calledWith ( LogType . SUCCESS ) ; } ) ; describe ( 'via providing a wallet path' , async ( ) => { it ( 'should add a new wallet by providing a wallet path' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( uri ) ; getIdentitiesStub . resolves ( [ 'someName' , 'anotherName' ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; result . name . should . equal ( path . basename ( uri . fsPath ) ) ; showInputBoxStub . should . not . have . been . called ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : path . basename ( uri . fsPath ) , walletPath : uri . fsPath } ) ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; it ( 'should handle the user cancelling providing a wallet path' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; logSpy . should . not . have . been . calledWith ( LogType . SUCCESS ) ; showInputBoxStub . should . not . have . been . called ; } ) ; it ( 'should not allow the user to add an empty directory as a wallet' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( uri ) ; getIdentitiesStub . resolves ( [ ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; logSpy . should . have . been . calledWith ( LogType . ERROR , `Failed to add a new wallet: No identities found in wallet: ${ uri . fsPath }` , `Failed to add a new wallet: No identities found in wallet: ${ uri . fsPath }` ) ; } ) ; it ( 'should error if an imported wallet with the same name already exists' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( uri ) ; mySandBox . stub ( FabricWalletRegistry . instance ( ) , 'exists' ) . resolves ( true ) ; await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; showInputBoxStub . should . not . have . been . called ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 0 ) ; logSpy . should . have . been . calledWith ( LogType . ERROR , `A wallet with this name already exists.` ) ; } ) ; it ( 'should add wallet with environmentGroup property' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( uri ) ; getIdentitiesStub . resolves ( [ 'someName' , 'anotherName' ] ) ; const myEnvironment = new FabricEnvironmentRegistryEntry ( ) ; myEnvironment . name = 'myEnvironment' ; myEnvironment . environmentType = EnvironmentType . ENVIRONMENT ; await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; await FabricEnvironmentRegistry . instance ( ) . add ( myEnvironment ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET , false , myEnvironment . name ) ; result . name . should . equal ( path . basename ( uri . fsPath ) ) ; showInputBoxStub . should . not . have . been . called ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : path . basename ( uri . fsPath ) , walletPath : uri . fsPath , environmentGroups : [ myEnvironment . name ] } ) ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; it ( 'should add a new wallet if able to convert v1 into v2 idendities' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . IMPORT_WALLET ) ; browseStub . resolves ( uri ) ; getIdentitiesStub . onFirstCall ( ) . resolves ( [ ] ) ; getIdentitiesStub . onSecondCall ( ) . resolves ( [ 'someName' , 'anotherName' ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; result . name . should . equal ( path . basename ( uri . fsPath ) ) ; showInputBoxStub . should . not . have . been . called ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : path . basename ( uri . fsPath ) , walletPath : uri . fsPath } ) ; migrateToV2WalletStub . should . have . been . calledOnce ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; } ) ; describe ( 'by adding an identity' , async ( ) => { it ( 'should add a new wallet by creating a new identity' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . callThrough ( ) ; executeCommandStub . withArgs ( ExtensionCommands . ADD_WALLET_IDENTITY , sinon . match . instanceOf ( FabricWalletRegistryEntry ) ) . resolves ( ) ; getIdentitiesStub . resolves ( [ 'someName' , 'anotherName' ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; result . name . should . equal ( 'someWalletName' ) ; browseStub . should . not . have . been . called ; showInputBoxStub . should . have . been . calledOnce ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : 'someWalletName' , walletPath : path . join ( TestUtil . EXTENSION_TEST_DIR , 'v2' , FileConfigurations . FABRIC_WALLETS , 'someWalletName' ) } ) ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; it ( 'should add a new wallet but not create an identity' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . callThrough ( ) ; getIdentitiesStub . resolves ( [ 'someName' , 'anotherName' ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET , false ) ; result . name . should . equal ( 'someWalletName' ) ; browseStub . should . not . have . been . called ; showInputBoxStub . should . have . been . calledOnce ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . ADD_WALLET_IDENTITY ) ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : 'someWalletName' , walletPath : path . join ( TestUtil . EXTENSION_TEST_DIR , 'v2' , FileConfigurations . FABRIC_WALLETS , 'someWalletName' ) } ) ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; it ( 'should handle the user cancelling providing a wallet name' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; browseStub . should . not . have . been . called ; logSpy . should . not . have . been . calledWith ( LogType . SUCCESS ) ; } ) ; it ( 'should no nothing if the addWalletIdentity command was cancelled' , async ( ) => { const deleteSpy = mySandBox . spy ( FabricWalletRegistry . instance ( ) , 'delete' ) ; choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . callThrough ( ) ; executeCommandStub . withArgs ( ExtensionCommands . ADD_WALLET_IDENTITY , sinon . match . any ) . resolves ( ) ; getIdentitiesStub . resolves ( [ ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; deleteSpy . should . have . been . calledWith ( 'someWalletName' ) ; browseStub . should . not . have . been . called ; showInputBoxStub . should . have . been . calledOnce ; logSpy . should . not . have . been . calledWith ( LogType . SUCCESS ) ; } ) ; it ( 'should handle errors thrown from addWalletIdentity command' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . callThrough ( ) ; executeCommandStub . withArgs ( ExtensionCommands . ADD_WALLET_IDENTITY , sinon . match . any ) . rejects ( { message : 'some issue importing identity' } ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; should . not . exist ( result ) ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 0 ) ; logSpy . should . have . been . calledWith ( LogType . ERROR , 'Failed to add a new wallet: some issue importing identity' , 'Failed to add a new wallet: some issue importing identity' ) ; } ) ; it ( 'should error if a new wallet with the same name already exists' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; mySandBox . stub ( FabricWalletRegistry . instance ( ) , 'exists' ) . resolves ( true ) ; await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET ) ; browseStub . should . not . have . been . called ; showInputBoxStub . should . have . been . calledOnce ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 0 ) ; logSpy . should . have . been . calledWith ( LogType . ERROR , `A wallet with this name already exists.` ) ; } ) ; it ( 'should add wallet with environmentGroup property' , async ( ) => { choseWalletAddMethod . resolves ( UserInputUtil . WALLET_NEW_ID ) ; showInputBoxStub . resolves ( 'someWalletName' ) ; executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . callThrough ( ) ; executeCommandStub . withArgs ( ExtensionCommands . ADD_WALLET_IDENTITY , sinon . match . instanceOf ( FabricWalletRegistryEntry ) ) . resolves ( ) ; getIdentitiesStub . resolves ( [ 'someName' , 'anotherName' ] ) ; const myEnvironment = new FabricEnvironmentRegistryEntry ( ) ; myEnvironment . name = 'myEnvironment' ; myEnvironment . environmentType = EnvironmentType . ENVIRONMENT ; await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; await FabricEnvironmentRegistry . instance ( ) . add ( myEnvironment ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . ADD_WALLET , false , myEnvironment . name ) ; result . name . should . equal ( 'someWalletName' ) ; browseStub . should . not . have . been . called ; showInputBoxStub . should . have . been . calledOnce ; const wallets = await FabricWalletRegistry . instance ( ) . getAll ( ) ; wallets . length . should . equal ( 1 ) ; wallets [ 0 ] . should . deep . equal ( { name : 'someWalletName' , walletPath : path . join ( TestUtil . EXTENSION_TEST_DIR , 'v2' , FileConfigurations . FABRIC_WALLETS , 'someWalletName' ) , environmentGroups : [ myEnvironment . name ] } ) ; logSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully added a new wallet' ) ; } ) ; } ) ; } ) ;