import * as vscode from 'vscode' ; import * as chai from 'chai' ; import * as sinon from 'sinon' ; import * as sinonChai from 'sinon-chai' ; import { VSCodeBlockchainOutputAdapter } from '../../extension/logging/VSCodeBlockchainOutputAdapter' ; import { FabricEnvironmentConnection } from 'ibm-blockchain-platform-environment-v1' ; import { FabricDebugConfigurationProvider } from '../../extension/debug/FabricDebugConfigurationProvider' ; import { FabricSmartContractDefinition , FabricEnvironmentRegistryEntry , FabricRuntimeUtil , LogType , FabricEnvironmentRegistry , EnvironmentType , FabricGatewayRegistry , FabricGatewayRegistryEntry } from 'ibm-blockchain-platform-common' ; import { FabricEnvironmentManager } from '../../extension/fabric/environments/FabricEnvironmentManager' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { TestUtil } from '../TestUtil' ; import { SettingConfigurations } from '../../extension/configurations' ; import { UserInputUtil } from '../../extension/commands/UserInputUtil' ; import { ExtensionUtil } from '../../extension/util/ExtensionUtil' ; import { EnvironmentFactory } from '../../extension/fabric/environments/EnvironmentFactory' ; import { FabricGatewayConnectionManager } from '../../extension/fabric/FabricGatewayConnectionManager' ; import { FabricGatewayConnection } from 'ibm-blockchain-platform-gateway-v1' ; import { LocalMicroEnvironment } from '../../extension/fabric/environments/LocalMicroEnvironment' ; import { LocalMicroEnvironmentManager } from '../../extension/fabric/environments/LocalMicroEnvironmentManager' ; const should = chai . should ( ) ; chai . use ( sinonChai ) ; class TestFabricDebugConfigurationProvider extends FabricDebugConfigurationProvider { public chaincodeName : string = 'mySmartContract' ; public chaincodeVersion : string = '0.0.1' ; protected async getChaincodeNameAndVersion ( ) { const version = this . chaincodeVersion ; const name = this . chaincodeName ; return { name , version } ; } protected async resolveDebugConfigurationInner ( folder , config ) { const chaincodeAddress = await this . getChaincodeAddress ( ) ; return Object . assign ( config , { type : 'fake' , name : 'Fake Debug' + folder . name , request : 'launch' , args : [ chaincodeAddress ] } ) ; } } describe ( 'FabricDebugConfigurationProvider' , ( ) => { let mySandbox ; let getExtensionLocalFabricSetting ; before ( async ( ) => { mySandbox = sinon . createSandbox ( ) ; await TestUtil . setupTests ( mySandbox ) ; } ) ; describe ( 'resolveDebugConfiguration' , ( ) => { let fabricDebugConfig ; let workspaceFolder ; let debugConfig ; let commandStub ; let mockRuntimeConnection ; let getConnectionStub ; let startDebuggingStub ; let logSpy ; let getEnvironmentRegistryStub ; let environmentRegistry ; let getName ; let getPeerChaincodeURL ; let isRunning ; let killChaincode ; let getGateways ; let showQuickPickItemStub ; let connectToGatewayStub ; beforeEach ( async ( ) => { await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; await TestUtil . startLocalFabric ( ) ; getExtensionLocalFabricSetting = mySandbox . stub ( ExtensionUtil , 'getExtensionLocalFabricSetting' ) ; getExtensionLocalFabricSetting . returns ( true ) ; fabricDebugConfig = new TestFabricDebugConfigurationProvider ( ) ; getName = mySandbox . stub ( LocalMicroEnvironment . prototype , 'getName' ) ; getName . returns ( FabricRuntimeUtil . LOCAL_FABRIC ) ; getPeerChaincodeURL = mySandbox . stub ( LocalMicroEnvironment . prototype , 'getPeerChaincodeURL' ) ; getPeerChaincodeURL . resolves ( 'grpc://127.0.0.1:54321' ) ; isRunning = mySandbox . stub ( LocalMicroEnvironment . prototype , 'isRunning' ) ; isRunning . resolves ( true ) ; killChaincode = mySandbox . stub ( LocalMicroEnvironment . prototype , 'killChaincode' ) ; killChaincode . resolves ( ) ; getGateways = mySandbox . stub ( LocalMicroEnvironment . prototype , 'getGateways' ) ; getGateways . resolves ( [ { name : 'myGateway' , path : 'myPath' } ] ) ; mySandbox . stub ( LocalMicroEnvironmentManager . instance ( ) , 'getRuntime' ) . returns ( { getName , getPeerChaincodeURL , isRunning , killChaincode , getGateways } ) ; workspaceFolder = { name : 'myFolder' , uri : vscode . Uri . file ( 'myPath' ) } ; debugConfig = { type : 'fabric:fake' , name : 'Launch Program' } ; commandStub = mySandbox . stub ( vscode . commands , 'executeCommand' ) ; mockRuntimeConnection = mySandbox . createStubInstance ( FabricEnvironmentConnection ) ; mockRuntimeConnection . getAllPeerNames . resolves ( [ 'peerOne' ] ) ; const instantiatedChaincodes = [ { name : 'myOtherContract' , version : 'vscode-debug-13232112018' , sequence : 2 } , { name : 'cake-network' , version : 'vscode-debug-174758735087' , sequence : 1 } ] ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . resolves ( instantiatedChaincodes ) ; getConnectionStub = mySandbox . stub ( FabricEnvironmentManager . instance ( ) , 'getConnection' ) ; getConnectionStub . returns ( mockRuntimeConnection ) ; environmentRegistry = await FabricEnvironmentRegistry . instance ( ) . get ( FabricRuntimeUtil . LOCAL_FABRIC ) ; getEnvironmentRegistryStub = mySandbox . stub ( FabricEnvironmentManager . instance ( ) , 'getEnvironmentRegistryEntry' ) . returns ( environmentRegistry ) ; startDebuggingStub = mySandbox . stub ( vscode . debug , 'startDebugging' ) ; logSpy = mySandbox . spy ( VSCodeBlockchainOutputAdapter . instance ( ) , 'log' ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub = mySandbox . stub ( UserInputUtil , 'showQuickPickItem' ) . resolves ( { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ) ; connectToGatewayStub = mySandbox . stub ( FabricDebugConfigurationProvider , 'connectToGateway' ) ; connectToGatewayStub . resolves ( true ) ; } ) ; afterEach ( ( ) => { mySandbox . restore ( ) ; } ) ; it ( 'should create a new debug configuration' , async ( ) => { const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should show all running microfab environments to debug for (1 & 2 Org)' , async ( ) => { getName . restore ( ) ; isRunning . onCall ( 2 ) . resolves ( false ) ; const otherLocalEntry = { name : 'OtherLocalEnv' , managedRuntime : true , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , numberOfOrgs : 1 } ; const twoOrgEntry = { name : 'twoOrgEnvironment' , managedRuntime : true , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , numberOfOrgs : 2 } ; await FabricEnvironmentRegistry . instance ( ) . add ( otherLocalEntry ) ; await FabricEnvironmentRegistry . instance ( ) . add ( { name : 'stoppedLocalEnv' , managedRuntime : true , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , numberOfOrgs : 1 } ) ; await FabricEnvironmentRegistry . instance ( ) . add ( twoOrgEntry ) ; await FabricEnvironmentRegistry . instance ( ) . add ( { url : 'some_website' , environmentType : 3 , name : 'consoleEnv' } ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; const otherLocalEnvironment = EnvironmentFactory . getEnvironment ( otherLocalEntry ) as LocalMicroEnvironment ; const twoOrgEnvironment = EnvironmentFactory . getEnvironment ( twoOrgEntry ) as LocalMicroEnvironment ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } , { label : 'OtherLocalEnv' , data : otherLocalEnvironment } , { label : 'twoOrgEnvironment' , data : twoOrgEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( `should return if user doesn't select an environment` , async ( ) => { getName . restore ( ) ; const otherEntry = { name : 'OtherLocalEnv' , managedRuntime : true , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , numberOfOrgs : 1 } ; const twoOrgEntry = { name : 'twoOrgEnvironment' , managedRuntime : true , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , numberOfOrgs : 2 } ; await FabricEnvironmentRegistry . instance ( ) . add ( otherEntry ) ; await FabricEnvironmentRegistry . instance ( ) . add ( twoOrgEntry ) ; await FabricEnvironmentRegistry . instance ( ) . add ( { url : 'some_website' , environmentType : 3 , name : 'consoleEnv' } ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; const otherLocalEnvironment = EnvironmentFactory . getEnvironment ( otherEntry ) as LocalMicroEnvironment ; const twoOrgEnvironment = EnvironmentFactory . getEnvironment ( twoOrgEntry ) as LocalMicroEnvironment ; showQuickPickItemStub . resolves ( ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } , { label : 'OtherLocalEnv' , data : otherLocalEnvironment } , { label : 'twoOrgEnvironment' , data : twoOrgEnvironment } ] ) ; startDebuggingStub . should . not . have . been . called ; commandStub . should . not . have . been . calledWith ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should return if there are no environments to select' , async ( ) => { await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; showQuickPickItemStub . should . not . have . been . called ; startDebuggingStub . should . not . have . been . called ; commandStub . should . not . have . been . calledWith ( 'setContext' , 'blockchain-debug' , true ) ; logSpy . should . have . been . calledOnceWithExactly ( LogType . ERROR , `No local environments found for debugging.` ) ; } ) ; it ( 'should create a new debug configuration if smart contract has a scoped name' , async ( ) => { const scopedDebugConfig = new TestFabricDebugConfigurationProvider ( ) ; scopedDebugConfig . chaincodeName = '@removeThis/mySmartContract' ; const config = await scopedDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should disconnect and connect to local fabric' , async ( ) => { const otherEnvironentRegistry = new FabricEnvironmentRegistryEntry ( ) ; otherEnvironentRegistry . name = 'myFabric' ; otherEnvironentRegistry . managedRuntime = false ; getEnvironmentRegistryStub . resetHistory ( ) ; getEnvironmentRegistryStub . onFirstCall ( ) . returns ( otherEnvironentRegistry ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; commandStub . should . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; commandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistry ) ; } ) ; it ( 'should connect if no connection' , async ( ) => { getConnectionStub . resetHistory ( ) ; getConnectionStub . onFirstCall ( ) . returns ( undefined ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; commandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistry ) ; } ) ; it ( 'should add in env properties if not defined' , async ( ) => { debugConfig . env = null ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should add CORE_CHAINCODE_ID_NAME to an existing env' , async ( ) => { debugConfig . env = { myProperty : 'myValue' } ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` , myProperty : 'myValue' } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should use CORE_CHAINCODE_ID_NAME if defined' , async ( ) => { debugConfig . env = { CORE_CHAINCODE_ID_NAME : 'mySmartContract:myVersion' } ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:myVersion` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should return if cannot connect' , async ( ) => { getConnectionStub . returns ( undefined ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . not . exist ( config ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; commandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistry ) ; } ) ; it ( 'should not run if the chaincode name is not provided' , async ( ) => { fabricDebugConfig . chaincodeName = undefined ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . not . have . been . called ; commandStub . should . not . have . been . calledWith ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should restore from a previous debug session and use the last instantiated package of the same name' , async ( ) => { const instantiatedChaincodes = [ { name : 'mySmartContract' , version : '0.0.1' , sequence : 1 } , { name : 'cake-network' , version : '0.0.2' , sequence : 1 } ] ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . resolves ( instantiatedChaincodes ) ; isRunning . onFirstCall ( ) . resolves ( true ) ; isRunning . onSecondCall ( ) . resolves ( false ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : `mySmartContract:0.0.1` } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; isRunning . should . have . been . calledWith ( [ 'mySmartContract' , '0.0.1' ] ) ; killChaincode . should . not . have . been . called ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should kill the container if there is a container running with the smart contract already' , async ( ) => { const instantiatedChaincodes = [ { name : 'mySmartContract' , version : '0.0.1' , sequence : 1 } , { name : 'cake-network' , version : '0.0.2' , sequence : 1 } ] ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . resolves ( instantiatedChaincodes ) ; isRunning . resolves ( true ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . have . been . calledOnceWithExactly ( sinon . match . any , { type : 'fake' , request : 'launch' , env : { CORE_CHAINCODE_ID_NAME : 'mySmartContract:0.0.1' } , args : [ '127.0.0.1:54321' ] , debugEvent : FabricDebugConfigurationProvider . debugEvent } ) ; killChaincode . should . have . been . called ; commandStub . should . have . been . calledWithExactly ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should handle errors with the debug session failing to start' , async ( ) => { const error = new Error ( 'whoops - failed' ) ; commandStub . withArgs ( 'setContext' , 'blockchain-debug' , true ) . rejects ( error ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; logSpy . should . have . been . calledOnceWithExactly ( LogType . ERROR , `Failed to launch debug: ${ error . message }` ) ; } ) ; it ( `should error if local fabric functionality is not enabled` , async ( ) => { mySandbox . stub ( UserInputUtil , 'showConfirmationWarningMessage' ) . withArgs ( `Toggling this feature will remove the world state and ledger data for all local runtimes. Do you want to continue?` ) . resolves ( true ) ; getExtensionLocalFabricSetting . returns ( false ) ; await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; showQuickPickItemStub . should . not . have . been . called ; logSpy . should . have . been . calledOnceWithExactly ( LogType . ERROR , `Setting '${ SettingConfigurations . EXTENSION_LOCAL_FABRIC }' must be set to 'true' to enable debugging.` ) ; } ) ; it ( 'should not start debug if not connected to the correct gateway' , async ( ) => { connectToGatewayStub . resolves ( false ) ; const config = await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; should . equal ( config , undefined ) ; const localEnvironment = EnvironmentFactory . getEnvironment ( environmentRegistry ) as LocalMicroEnvironment ; showQuickPickItemStub . should . have . been . calledOnceWithExactly ( 'Select a local environment to debug' , [ { label : FabricRuntimeUtil . LOCAL_FABRIC , data : localEnvironment } ] ) ; startDebuggingStub . should . not . have . been . called ; commandStub . should . not . have . been . calledWith ( 'setContext' , 'blockchain-debug' , true ) ; } ) ; it ( 'should do nothing and report a warning on Eclipse Che' , async ( ) => { mySandbox . stub ( ExtensionUtil , 'isChe' ) . returns ( true ) ; await fabricDebugConfig . resolveDebugConfiguration ( workspaceFolder , debugConfig ) ; logSpy . should . have . been . calledOnceWithExactly ( LogType . ERROR , sinon . match ( /not supported/ ) ) ; } ) ; } ) ; describe ( 'connectToGateway' , ( ) => { let getConnectionStub ; let getGatewayRegistryEntryStub ; let executeCommandStub ; let fabricClientConnectionMock ; beforeEach ( async ( ) => { await FabricEnvironmentRegistry . instance ( ) . clear ( ) ; await FabricGatewayRegistry . instance ( ) . clear ( ) ; await TestUtil . startLocalFabric ( ) ; getConnectionStub = mySandbox . stub ( FabricGatewayConnectionManager . instance ( ) , 'getConnection' ) ; getGatewayRegistryEntryStub = mySandbox . stub ( FabricGatewayConnectionManager . instance ( ) , 'getGatewayRegistryEntry' ) ; fabricClientConnectionMock = mySandbox . createStubInstance ( FabricGatewayConnection ) ; executeCommandStub = mySandbox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . withArgs ( ExtensionCommands . CONNECT_TO_GATEWAY , sinon . match . any ) . resolves ( ) ; executeCommandStub . withArgs ( ExtensionCommands . DISCONNECT_GATEWAY ) . resolves ( ) ; } ) ; afterEach ( ( ) => { mySandbox . restore ( ) ; } ) ; it ( 'should return true if not connected, and connecting to gateway is successful' , async ( ) => { getConnectionStub . onCall ( 0 ) . returns ( undefined ) ; getConnectionStub . onCall ( 1 ) . returns ( fabricClientConnectionMock ) ; getGatewayRegistryEntryStub . resolves ( undefined ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; FabricDebugConfigurationProvider . orgName = 'Org1' ; const connected = await FabricDebugConfigurationProvider . connectToGateway ( ) ; connected . should . equal ( true ) ; getConnectionStub . should . have . been . calledTwice ; } ) ; it ( 'should return false if not connected, and connecting to gateway is unsuccessful' , async ( ) => { getConnectionStub . onCall ( 0 ) . returns ( undefined ) ; getConnectionStub . onCall ( 1 ) . returns ( undefined ) ; getGatewayRegistryEntryStub . resolves ( undefined ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; FabricDebugConfigurationProvider . orgName = 'Org1' ; const connected = await FabricDebugConfigurationProvider . connectToGateway ( ) ; connected . should . equal ( false ) ; getConnectionStub . should . have . been . calledTwice ; } ) ; it ( 'should return true if connected to wrong gateway, and reconnecting to correct gateway is successful' , async ( ) => { getConnectionStub . onCall ( 0 ) . returns ( fabricClientConnectionMock ) ; getConnectionStub . onCall ( 1 ) . returns ( fabricClientConnectionMock ) ; getGatewayRegistryEntryStub . resolves ( { name : `${ FabricRuntimeUtil . LOCAL_FABRIC } - Org2 Gateway` } as FabricGatewayRegistryEntry ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; FabricDebugConfigurationProvider . orgName = 'Org1' ; const localGateway = await FabricGatewayRegistry . instance ( ) . get ( `${ FabricDebugConfigurationProvider . environmentName } - ${ FabricDebugConfigurationProvider . orgName } Gateway` ) ; should . exist ( localGateway ) ; const connected = await FabricDebugConfigurationProvider . connectToGateway ( ) ; connected . should . equal ( true ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . DISCONNECT_GATEWAY ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_GATEWAY , localGateway ) ; getConnectionStub . should . have . been . calledTwice ; } ) ; it ( 'should return false if connected to wrong gateway, and reconnecting to correct gateway is unsuccessful' , async ( ) => { getConnectionStub . onCall ( 0 ) . returns ( fabricClientConnectionMock ) ; getConnectionStub . onCall ( 1 ) . returns ( undefined ) ; getGatewayRegistryEntryStub . resolves ( { name : `${ FabricRuntimeUtil . LOCAL_FABRIC } - Org2 Gateway` } as FabricGatewayRegistryEntry ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; FabricDebugConfigurationProvider . orgName = 'Org1' ; const localGateway = await FabricGatewayRegistry . instance ( ) . get ( `${ FabricDebugConfigurationProvider . environmentName } - ${ FabricDebugConfigurationProvider . orgName } Gateway` ) ; should . exist ( localGateway ) ; const connected = await FabricDebugConfigurationProvider . connectToGateway ( ) ; connected . should . equal ( false ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . DISCONNECT_GATEWAY ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_GATEWAY , localGateway ) ; getConnectionStub . should . have . been . calledTwice ; } ) ; it ( 'should return true if connected to correct gateway' , async ( ) => { const localGateway = await FabricGatewayRegistry . instance ( ) . get ( `${ FabricDebugConfigurationProvider . environmentName } - ${ FabricDebugConfigurationProvider . orgName } Gateway` ) ; should . exist ( localGateway ) ; getConnectionStub . onCall ( 0 ) . returns ( fabricClientConnectionMock ) ; getConnectionStub . onCall ( 1 ) . returns ( fabricClientConnectionMock ) ; getGatewayRegistryEntryStub . resolves ( localGateway ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; FabricDebugConfigurationProvider . orgName = 'Org1' ; const connected = await FabricDebugConfigurationProvider . connectToGateway ( ) ; connected . should . equal ( true ) ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . DISCONNECT_GATEWAY ) ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . CONNECT_TO_GATEWAY , localGateway ) ; getConnectionStub . should . have . been . calledOnce ; } ) ; } ) ; describe ( 'getInstantiatedChaincode' , ( ) => { let mockRuntimeConnection ; let getConnectionStub ; let environmentRegistryEntry ; let getEnvironmentRegistryStub ; let executeCommandStub ; beforeEach ( async ( ) => { mockRuntimeConnection = mySandbox . createStubInstance ( FabricEnvironmentConnection ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . resolves ( [ { name : 'chaincode1' , version : '0.0.1' } , { name : 'chaincode2' , version : '0.0.2' } , { name : 'chaincode3' , version : '0.0.3' } ] ) ; getConnectionStub = mySandbox . stub ( FabricEnvironmentManager . instance ( ) , 'getConnection' ) ; getConnectionStub . returns ( mockRuntimeConnection ) ; environmentRegistryEntry = await FabricEnvironmentRegistry . instance ( ) . get ( FabricRuntimeUtil . LOCAL_FABRIC ) ; getEnvironmentRegistryStub = mySandbox . stub ( FabricEnvironmentManager . instance ( ) , 'getEnvironmentRegistryEntry' ) . returns ( environmentRegistryEntry ) ; executeCommandStub = mySandbox . stub ( vscode . commands , 'executeCommand' ) ; executeCommandStub . withArgs ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) . resolves ( ) ; executeCommandStub . withArgs ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , sinon . match . any ) . resolves ( ) ; FabricDebugConfigurationProvider . environmentName = FabricRuntimeUtil . LOCAL_FABRIC ; } ) ; afterEach ( ( ) => { mySandbox . restore ( ) ; } ) ; it ( 'should get contract if already connected to correct environment' , async ( ) => { const chaincode = await FabricDebugConfigurationProvider . getInstantiatedChaincode ( 'chaincode2' ) ; chaincode . should . deep . equal ( { name : 'chaincode2' , version : '0.0.2' } ) ; getConnectionStub . should . have . been . calledTwice ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . should . have . been . calledOnce ; } ) ; it ( 'should get contract if already connected to another environment with different name' , async ( ) => { getEnvironmentRegistryStub . returns ( { name : 'otherEnvironment' , environmentType : EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT , managedRuntime : true , numberOfOrgs : 1 } as FabricEnvironmentRegistryEntry ) ; const fabricEnvironmentRegistryGetSpy = mySandbox . spy ( FabricEnvironmentRegistry . instance ( ) , 'get' ) ; const chaincode = await FabricDebugConfigurationProvider . getInstantiatedChaincode ( 'chaincode2' ) ; chaincode . should . deep . equal ( { name : 'chaincode2' , version : '0.0.2' } ) ; getConnectionStub . should . have . been . calledTwice ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; fabricEnvironmentRegistryGetSpy . should . have . been . calledOnceWithExactly ( FabricDebugConfigurationProvider . environmentName ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistryEntry ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . should . have . been . calledOnce ; } ) ; it ( 'should get contract if already connected to another environment with different environment type' , async ( ) => { getEnvironmentRegistryStub . returns ( { name : 'userEnvironment' , environmentType : EnvironmentType . ENVIRONMENT } as FabricEnvironmentRegistryEntry ) ; const fabricEnvironmentRegistryGetSpy = mySandbox . spy ( FabricEnvironmentRegistry . instance ( ) , 'get' ) ; const chaincode = await FabricDebugConfigurationProvider . getInstantiatedChaincode ( 'chaincode2' ) ; chaincode . should . deep . equal ( { name : 'chaincode2' , version : '0.0.2' } ) ; getConnectionStub . should . have . been . calledTwice ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; fabricEnvironmentRegistryGetSpy . should . have . been . calledOnceWithExactly ( FabricDebugConfigurationProvider . environmentName ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistryEntry ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . should . have . been . calledOnce ; } ) ; it ( 'should get contract if not already connected' , async ( ) => { getConnectionStub . onCall ( 0 ) . returns ( undefined ) ; const fabricEnvironmentRegistryGetSpy = mySandbox . spy ( FabricEnvironmentRegistry . instance ( ) , 'get' ) ; const chaincode = await FabricDebugConfigurationProvider . getInstantiatedChaincode ( 'chaincode2' ) ; chaincode . should . deep . equal ( { name : 'chaincode2' , version : '0.0.2' } ) ; getConnectionStub . should . have . been . calledTwice ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; fabricEnvironmentRegistryGetSpy . should . have . been . calledOnceWithExactly ( FabricDebugConfigurationProvider . environmentName ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistryEntry ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . should . have . been . calledOnce ; } ) ; it ( 'should error if unable to connect to environment' , async ( ) => { getConnectionStub . returns ( undefined ) ; const fabricEnvironmentRegistryGetSpy = mySandbox . spy ( FabricEnvironmentRegistry . instance ( ) , 'get' ) ; await FabricDebugConfigurationProvider . getInstantiatedChaincode ( 'chaincode2' ) . should . be . rejectedWith ( `Could not create connection to ${ FabricDebugConfigurationProvider . environmentName }` ) ; getConnectionStub . should . have . been . calledTwice ; executeCommandStub . should . not . have . been . calledWith ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; fabricEnvironmentRegistryGetSpy . should . have . been . calledOnceWithExactly ( FabricDebugConfigurationProvider . environmentName ) ; executeCommandStub . should . have . been . calledWith ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentRegistryEntry ) ; mockRuntimeConnection . getAllCommittedSmartContractDefinitions . should . not . have . been . called ; } ) ; } ) ; } ) ;