'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 { TestUtil } from '../TestUtil' ; import { PackageRegistryEntry } from '../../extension/registries/PackageRegistryEntry' ; import { VSCodeBlockchainOutputAdapter } from '../../extension/logging/VSCodeBlockchainOutputAdapter' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { VSCodeBlockchainDockerOutputAdapter } from '../../extension/logging/VSCodeBlockchainDockerOutputAdapter' ; import { FabricEnvironmentConnection } from 'ibm-blockchain-platform-environment-v1' ; import { FabricEnvironmentManager , ConnectedState } from '../../extension/fabric/environments/FabricEnvironmentManager' ; import { FabricEnvironmentRegistryEntry , FabricRuntimeUtil , LogType , EnvironmentType } from 'ibm-blockchain-platform-common' ; import { SettingConfigurations } from '../../extension/configurations' ; chai . use ( sinonChai ) ; const should = chai . should ( ) ; describe ( 'InstallCommand' , ( ) => { const TEST_PACKAGE_DIRECTORY = path . join ( path . dirname ( __dirname ) , '../../test/data/packageDir' ) ; const mySandBox = sinon . createSandbox ( ) ; before ( async ( ) => { await TestUtil . setupTests ( mySandBox ) ; } ) ; after ( async ( ) => { await vscode . workspace . getConfiguration ( ) . update ( SettingConfigurations . EXTENSION_DIRECTORY , TestUtil . EXTENSION_TEST_DIR , vscode . ConfigurationTarget . Global ) ; } ) ; describe ( 'InstallSmartContract' , ( ) => { let fabricRuntimeMock ; let executeCommandStub ; let packageRegistryEntry ; let getRuntimeConnectionStub ; let logOutputSpy ; let dockerLogsOutputSpy ; let environmentRegistryStub ; let getSettingsStub ; let getConfigurationStub ; let packageLabel ; beforeEach ( async ( ) => { executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . withArgs ( ExtensionCommands . CONNECT_TO_GATEWAY ) . resolves ( ) ; executeCommandStub . withArgs ( ExtensionCommands . CONNECT_TO_ENVIRONMENT ) . resolves ( ) ; executeCommandStub . callThrough ( ) ; fabricRuntimeMock = mySandBox . createStubInstance ( FabricEnvironmentConnection ) ; fabricRuntimeMock . connect . resolves ( ) ; fabricRuntimeMock . installSmartContract . resolves ( 'myPackageId' ) ; getSettingsStub = mySandBox . stub ( ) ; getSettingsStub . withArgs ( SettingConfigurations . FABRIC_CLIENT_TIMEOUT ) . returns ( 9000 ) ; getConfigurationStub = mySandBox . stub ( vscode . workspace , 'getConfiguration' ) ; getConfigurationStub . returns ( { get : getSettingsStub , update : mySandBox . stub ( ) . callThrough ( ) } ) ; getRuntimeConnectionStub = mySandBox . stub ( FabricEnvironmentManager . instance ( ) , 'getConnection' ) . returns ( ( fabricRuntimeMock as any ) ) ; mySandBox . stub ( FabricEnvironmentManager . instance ( ) , 'getState' ) . returns ( ConnectedState . CONNECTED ) ; const environmentRegistryEntry = new FabricEnvironmentRegistryEntry ( ) ; environmentRegistryEntry . name = FabricRuntimeUtil . LOCAL_FABRIC ; environmentRegistryEntry . managedRuntime = true ; environmentRegistryEntry . environmentType = EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT ; environmentRegistryStub = mySandBox . stub ( FabricEnvironmentManager . instance ( ) , 'getEnvironmentRegistryEntry' ) . returns ( environmentRegistryEntry ) ; packageRegistryEntry = new PackageRegistryEntry ( { name : 'vscode-pkg-1' , path : path . join ( TEST_PACKAGE_DIRECTORY , 'vscode-pkg-1@0.0.1.tar.gz' ) , version : '0.0.1' , sizeKB : 23.45 } ) ; packageLabel = `${ packageRegistryEntry . name }_${ packageRegistryEntry . version }` ; logOutputSpy = mySandBox . spy ( VSCodeBlockchainOutputAdapter . instance ( ) , 'log' ) ; dockerLogsOutputSpy = mySandBox . spy ( VSCodeBlockchainDockerOutputAdapter . instance ( FabricRuntimeUtil . LOCAL_FABRIC ) , 'show' ) ; logOutputSpy . resetHistory ( ) ; } ) ; afterEach ( async ( ) => { await vscode . commands . executeCommand ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; mySandBox . restore ( ) ; } ) ; it ( 'should install the smart contract through the command' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; orgMap . set ( 'Org2MSP' , [ 'peerTwo' , 'peerThree' ] ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; result [ 0 ] . should . equal ( 'myPackageId' ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerThree' , packageLabel , 9000000 ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerOne' , packageLabel , 9000000 ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerTwo' , packageLabel , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerThree' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerOne' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerTwo' ) ; } ) ; it ( 'should install the smart contract through the command when timeout is not provided in user settings' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; orgMap . set ( 'Org2MSP' , [ 'peerTwo' , 'peerThree' ] ) ; getSettingsStub . withArgs ( SettingConfigurations . FABRIC_CLIENT_TIMEOUT ) . returns ( undefined ) ; getConfigurationStub . returns ( { get : getSettingsStub , update : mySandBox . stub ( ) . callThrough ( ) } ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; result [ 0 ] . should . equal ( 'myPackageId' ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerThree' , packageLabel , undefined ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerOne' , packageLabel , undefined ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerTwo' , packageLabel , undefined ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerThree' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerOne' ) ; logOutputSpy . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerTwo' ) ; } ) ; it ( 'should install the smart contract through the command and connect if no connection' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; getRuntimeConnectionStub . resetHistory ( ) ; getRuntimeConnectionStub . onFirstCall ( ) . returns ( undefined ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; result [ 0 ] . should . equal ( 'myPackageId' ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerOne' , packageLabel , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerOne' ) ; } ) ; it ( 'should not show docker logs if not managed runtime' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; const registryEntry = new FabricEnvironmentRegistryEntry ( ) ; registryEntry . name = 'myFabric' ; registryEntry . managedRuntime = false ; environmentRegistryStub . returns ( registryEntry ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; result [ 0 ] . should . equal ( 'myPackageId' ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerOne' , packageLabel , 9000000 ) ; dockerLogsOutputSpy . should . not . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerOne' ) ; } ) ; it ( 'should return if cannot make connection' , async ( ) => { const peers = [ 'peerOne' ] ; getRuntimeConnectionStub . returns ( undefined ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , peers , packageRegistryEntry ) ; should . not . exist ( result [ 0 ] ) ; fabricRuntimeMock . installSmartContract . should . not . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; } ) ; it ( 'should handle error from installing smart contract' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; const error = new Error ( 'some error' ) ; fabricRuntimeMock . installSmartContract . rejects ( error ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; should . not . exist ( result [ 0 ] ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWith ( packageRegistryEntry . path , 'peerOne' ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . ERROR , `Failed to install on peer peerOne with reason: ${ error . message }` , `Failed to install on peer peerOne with reason: ${ error . toString ( ) }` ) ; } ) ; it ( 'should handle timeout error from installing smart contract' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; const error = new Error ( 'some REQUEST TIMEOUT error' ) ; fabricRuntimeMock . installSmartContract . rejects ( error ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; should . not . exist ( result [ 0 ] ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWith ( packageRegistryEntry . path , 'peerOne' ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . ERROR , `Failed to install on peer peerOne with reason: ${ error . message }` , `Failed to install on peer peerOne with reason: ${ error . toString ( ) }` ) ; } ) ; it ( 'should still install on other peers if one fails' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' , 'peerTwo' ] ) ; const error = new Error ( 'some error' ) ; fabricRuntimeMock . installSmartContract . onFirstCall ( ) . rejects ( error ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; should . not . exist ( result [ 0 ] ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerOne' , packageLabel , 9000000 ) ; fabricRuntimeMock . installSmartContract . should . have . been . calledWithExactly ( packageRegistryEntry . path , 'peerTwo' , packageLabel , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . ERROR , `Failed to install on peer peerOne with reason: ${ error . message }` , `Failed to install on peer peerOne with reason: ${ error . toString ( ) }` ) ; logOutputSpy . getCall ( 2 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully installed on peer peerTwo' ) ; } ) ; it ( 'should handle peer failing to install' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; fabricRuntimeMock . installSmartContract . onFirstCall ( ) . rejects ( { message : 'failed to install for some reason' } ) ; const result = await vscode . commands . executeCommand ( ExtensionCommands . INSTALL_SMART_CONTRACT , orgMap , packageRegistryEntry ) ; should . not . exist ( result [ 0 ] ) ; dockerLogsOutputSpy . should . have . been . called ; logOutputSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'installSmartContract' ) ; logOutputSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . ERROR , 'Failed to install on peer peerOne with reason: failed to install for some reason' ) ; } ) ; } ) ; } ) ;