'use strict' ; import * as vscode from 'vscode' ; import * as chai from 'chai' ; import * as sinon from 'sinon' ; import * as sinonChai from 'sinon-chai' ; import { TestUtil } from '../TestUtil' ; 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 { Reporter } from '../../extension/util/Reporter' ; import { FabricEnvironmentManager , ConnectedState } from '../../extension/fabric/environments/FabricEnvironmentManager' ; import { FabricEnvironmentRegistryEntry , FabricRuntimeUtil , LogType , EnvironmentType , FabricSmartContractDefinition } from 'ibm-blockchain-platform-common' ; import { SettingConfigurations } from '../../extension/configurations' ; import { ExtensionUtil } from '../../extension/util/ExtensionUtil' ; chai . use ( sinonChai ) ; describe ( 'ApproveCommand' , ( ) => { const mySandBox = sinon . createSandbox ( ) ; before ( async ( ) => { await TestUtil . setupTests ( mySandBox ) ; } ) ; describe ( 'approveSmartContract' , ( ) => { let fabricRuntimeMock ; let executeCommandStub ; let logSpy ; let dockerLogsOutputSpy ; let sendTelemetryEventStub ; let environmentConnectionStub ; let environmentRegistryStub ; let getSettingsStub ; let getConfigurationStub ; beforeEach ( async ( ) => { executeCommandStub = mySandBox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . withArgs ( ExtensionCommands . CONNECT_TO_ENVIRONMENT ) . resolves ( ) ; executeCommandStub . withArgs ( ExtensionCommands . REFRESH_GATEWAYS ) . resolves ( ) ; executeCommandStub . withArgs ( ExtensionCommands . REFRESH_ENVIRONMENTS ) . resolves ( ) ; executeCommandStub . callThrough ( ) ; fabricRuntimeMock = mySandBox . createStubInstance ( FabricEnvironmentConnection ) ; fabricRuntimeMock . connect . resolves ( ) ; fabricRuntimeMock . approveSmartContractDefinition . resolves ( true ) ; 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 ( ) } ) ; environmentConnectionStub = mySandBox . stub ( FabricEnvironmentManager . instance ( ) , 'getConnection' ) . returns ( ( fabricRuntimeMock ) ) ; 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 ) ; mySandBox . stub ( FabricEnvironmentManager . instance ( ) , 'getState' ) . returns ( ConnectedState . CONNECTED ) ; logSpy = mySandBox . spy ( VSCodeBlockchainOutputAdapter . instance ( ) , 'log' ) ; dockerLogsOutputSpy = mySandBox . spy ( VSCodeBlockchainDockerOutputAdapter . instance ( FabricRuntimeUtil . LOCAL_FABRIC ) , 'show' ) ; sendTelemetryEventStub = mySandBox . stub ( Reporter . instance ( ) , 'sendTelemetryEvent' ) ; } ) ; afterEach ( async ( ) => { mySandBox . restore ( ) ; } ) ; it ( 'should approve the smart contract through the command' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; orgMap . set ( 'Org2MSP' , [ 'peerTwo' , 'peerThree' ] ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . getCall ( 0 ) . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; fabricRuntimeMock . approveSmartContractDefinition . getCall ( 1 ) . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerTwo' , 'peerThree' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully approved smart contract definition' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; it ( 'should approve 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 ( ) } ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . getCall ( 0 ) . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , undefined ) ; fabricRuntimeMock . approveSmartContractDefinition . getCall ( 1 ) . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerTwo' , 'peerThree' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , undefined ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully approved smart contract definition' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; it ( 'should approve the smart contract through the command with endorsement policy' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' , `OR('Org1.member', 'Org2.member')` ) ) ; fabricRuntimeMock . approveSmartContractDefinition . should . have . been . calledOnceWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' , `OR('Org1.member', 'Org2.member')` ) , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully approved smart contract definition' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; it ( 'should approve the smart contract through the command when not connected' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; environmentConnectionStub . resetHistory ( ) ; environmentConnectionStub . onFirstCall ( ) . returns ( undefined ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully approved smart contract definition' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; 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 ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; dockerLogsOutputSpy . should . not . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . SUCCESS , 'Successfully approved smart contract definition' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; it ( 'should return if no connection' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; environmentConnectionStub . returns ( undefined ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . should . not . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; } ) ; it ( 'should handle error from approving smart contract' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; const error = new Error ( 'some error' ) ; fabricRuntimeMock . approveSmartContractDefinition . throws ( error ) ; await ExtensionUtil . executeCommandInternal ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) . should . eventually . be . rejectedWith ( /some error/ ) ; fabricRuntimeMock . approveSmartContractDefinition . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . ERROR , `Error approving smart contract: ${ error . message }` , `Error approving smart contract: ${ error . toString ( ) }` ) ; sendTelemetryEventStub . should . not . have . been . called ; } ) ; it ( 'should inform user if smart contract already approved and ready for commit' , async ( ) => { const orgMap = new Map < string , string [ ] > ( ) ; orgMap . set ( 'Org1MSP' , [ 'peerOne' ] ) ; environmentConnectionStub . resetHistory ( ) ; environmentConnectionStub . onFirstCall ( ) . returns ( undefined ) ; fabricRuntimeMock . approveSmartContractDefinition . resolves ( false ) ; await vscode . commands . executeCommand ( ExtensionCommands . APPROVE_SMART_CONTRACT , 'myOrderer' , 'mychannel' , orgMap , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) ) ; fabricRuntimeMock . approveSmartContractDefinition . should . have . been . calledWithExactly ( 'myOrderer' , 'mychannel' , [ 'peerOne' ] , new FabricSmartContractDefinition ( 'mySmartContract' , '0.0.1' , 1 , 'myPackageId' ) , 9000000 ) ; dockerLogsOutputSpy . should . have . been . called ; logSpy . getCall ( 0 ) . should . have . been . calledWith ( LogType . INFO , undefined , 'approveSmartContract' ) ; logSpy . getCall ( 1 ) . should . have . been . calledWith ( LogType . INFO , 'Smart contract definition alreay approved by organisation Org1MSP' ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT ) ; executeCommandStub . should . have . not . been . calledWith ( ExtensionCommands . REFRESH_GATEWAYS ) ; executeCommandStub . should . have . not . been . calledWith ( ExtensionCommands . REFRESH_ENVIRONMENTS ) ; sendTelemetryEventStub . should . have . been . calledOnceWithExactly ( 'approveCommand' ) ; } ) ; } ) ; } ) ;