diff --git a/examples/cactus-example-supply-chain-backend/src/main/typescript/infrastructure/supply-chain-app-dummy-infrastructure.ts b/examples/cactus-example-supply-chain-backend/src/main/typescript/infrastructure/supply-chain-app-dummy-infrastructure.ts index ea476b6469..97110b1b26 100644 --- a/examples/cactus-example-supply-chain-backend/src/main/typescript/infrastructure/supply-chain-app-dummy-infrastructure.ts +++ b/examples/cactus-example-supply-chain-backend/src/main/typescript/infrastructure/supply-chain-app-dummy-infrastructure.ts @@ -33,6 +33,7 @@ import { } from "@hyperledger/cactus-plugin-ledger-connector-fabric"; import { DiscoveryOptions } from "fabric-network"; import { SHIPMENT_CONTRACT_GO_SOURCE } from "../../go/shipment"; +import { IPluginKeychain } from "@hyperledger/cactus-core-api"; export const org1Env = { CORE_PEER_LOCALMSPID: "Org1MSP", @@ -47,6 +48,7 @@ export const org1Env = { export interface ISupplyChainAppDummyInfrastructureOptions { logLevel?: LogLevelDesc; + keychain?: IPluginKeychain; } /** @@ -66,9 +68,10 @@ export class SupplyChainAppDummyInfrastructure { public readonly besu: BesuTestLedger; public readonly quorum: QuorumTestLedger; public readonly fabric: FabricTestLedgerV1; + public readonly keychain: IPluginKeychain; private readonly log: Logger; - private _quorumAccount: Account | undefined; - private _besuAccount: Account | undefined; + private _quorumAccount?: Account; + private _besuAccount?: Account; public get quorumAccount(): Account { if (!this._quorumAccount) { @@ -107,6 +110,19 @@ export class SupplyChainAppDummyInfrastructure { imageName: "hyperledger/cactus-fabric-all-in-one", imageVersion: "2021-03-02-ssh-hotfix", }); + + if (this.options.keychain) { + this.keychain = this.options.keychain; + this.log.info("Reusing the provided keychain plugin..."); + } else { + this.log.info("Instantiating new keychain plugin..."); + this.keychain = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId: uuidv4(), + logLevel: this.options.logLevel || "INFO", + }); + } + this.log.info("KeychainID=%o", this.keychain.getKeychainId()); } public async stop(): Promise { @@ -147,16 +163,11 @@ export class SupplyChainAppDummyInfrastructure { let bookshelfRepository: IEthContractDeployment; let shipmentRepository: IFabricContractDeployment; - const keychainPlugin = new PluginKeychainMemory({ - instanceId: uuidv4(), - keychainId: uuidv4(), - logLevel: this.options.logLevel || "INFO", - }); - keychainPlugin.set( + await this.keychain.set( BookshelfRepositoryJSON.contractName, BookshelfRepositoryJSON, ); - keychainPlugin.set( + await this.keychain.set( BambooHarvestRepositoryJSON.contractName, BambooHarvestRepositoryJSON, ); @@ -165,7 +176,7 @@ export class SupplyChainAppDummyInfrastructure { const rpcApiHttpHost = await this.quorum.getRpcApiHttpHost(); const pluginRegistry = new PluginRegistry(); - pluginRegistry.add(keychainPlugin); + pluginRegistry.add(this.keychain); const connector = new PluginLedgerConnectorQuorum({ instanceId: "PluginLedgerConnectorQuorum_Contract_Deployment", rpcApiHttpHost, @@ -182,7 +193,7 @@ export class SupplyChainAppDummyInfrastructure { secret: this.quorumAccount.privateKey, type: Web3SigningCredentialType.PrivateKeyHex, }, - keychainId: keychainPlugin.getKeychainId(), + keychainId: this.keychain.getKeychainId(), }); const { transactionReceipt: { contractAddress }, @@ -193,7 +204,7 @@ export class SupplyChainAppDummyInfrastructure { address: contractAddress as string, bytecode: BambooHarvestRepositoryJSON.bytecode, contractName: BambooHarvestRepositoryJSON.contractName, - keychainId: keychainPlugin.getKeychainId(), + keychainId: this.keychain.getKeychainId(), }; } @@ -203,7 +214,7 @@ export class SupplyChainAppDummyInfrastructure { const rpcApiWsHost = await this.besu.getRpcApiWsHost(); const pluginRegistry = new PluginRegistry(); - pluginRegistry.add(keychainPlugin); + pluginRegistry.add(this.keychain); const connector = new PluginLedgerConnectorBesu({ instanceId: "PluginLedgerConnectorBesu_Contract_Deployment", rpcApiHttpHost, @@ -223,7 +234,7 @@ export class SupplyChainAppDummyInfrastructure { secret: this.besuAccount.privateKey, type: Web3SigningCredentialType.PrivateKeyHex, }, - keychainId: keychainPlugin.getKeychainId(), + keychainId: this.keychain.getKeychainId(), }); const { transactionReceipt: { contractAddress }, @@ -234,7 +245,7 @@ export class SupplyChainAppDummyInfrastructure { address: contractAddress as string, bytecode: BookshelfRepositoryJSON.bytecode, contractName: BookshelfRepositoryJSON.contractName, - keychainId: keychainPlugin.getKeychainId(), + keychainId: this.keychain.getKeychainId(), }; } @@ -247,7 +258,7 @@ export class SupplyChainAppDummyInfrastructure { }; const pluginRegistry = new PluginRegistry(); - pluginRegistry.add(keychainPlugin); + pluginRegistry.add(this.keychain); const connector = new PluginLedgerConnectorFabric({ instanceId: "PluginLedgerConnectorFabric_Contract_Deployment", dockerBinary: "/usr/local/bin/docker", diff --git a/examples/cactus-example-supply-chain-backend/src/main/typescript/public-api.ts b/examples/cactus-example-supply-chain-backend/src/main/typescript/public-api.ts index 137c6ced42..13e91cce55 100755 --- a/examples/cactus-example-supply-chain-backend/src/main/typescript/public-api.ts +++ b/examples/cactus-example-supply-chain-backend/src/main/typescript/public-api.ts @@ -1,2 +1,3 @@ export { SupplyChainApp } from "./supply-chain-app"; +export { ISupplyChainAppOptions } from "./supply-chain-app"; export { launchApp } from "./supply-chain-app-cli"; diff --git a/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app-cli.ts b/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app-cli.ts index 7881767c6a..fa0868d4e3 100755 --- a/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app-cli.ts +++ b/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app-cli.ts @@ -4,9 +4,12 @@ import { ConfigService } from "@hyperledger/cactus-cmd-api-server"; import { LoggerProvider } from "@hyperledger/cactus-common"; import { ISupplyChainAppOptions, SupplyChainApp } from "./supply-chain-app"; -export async function launchApp(): Promise { +export async function launchApp( + env?: NodeJS.ProcessEnv, + args?: string[], +): Promise { const configService = new ConfigService(); - const config = configService.getOrCreate(); + const config = configService.getOrCreate({ args, env }); const serverOptions = config.getProperties(); LoggerProvider.setLogLevel(serverOptions.logLevel); @@ -24,5 +27,5 @@ export async function launchApp(): Promise { } if (require.main === module) { - launchApp(); + launchApp(process.env, process.argv); } diff --git a/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app.ts b/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app.ts index edaa0478e0..1584c70338 100644 --- a/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app.ts +++ b/examples/cactus-example-supply-chain-backend/src/main/typescript/supply-chain-app.ts @@ -7,10 +7,10 @@ import exitHook, { IAsyncExitHookDoneCallback } from "async-exit-hook"; import { CactusNode, - Configuration, Consortium, ConsortiumDatabase, ConsortiumMember, + IPluginKeychain, Ledger, LedgerType, } from "@hyperledger/cactus-core-api"; @@ -50,11 +50,17 @@ import { SupplyChainAppDummyInfrastructure, org1Env, } from "./infrastructure/supply-chain-app-dummy-infrastructure"; +import { + Configuration, + DefaultApi as SupplyChainApi, +} from "@hyperledger/cactus-example-supply-chain-business-logic-plugin"; import { SupplyChainCactusPlugin } from "@hyperledger/cactus-example-supply-chain-business-logic-plugin"; import { DiscoveryOptions } from "fabric-network"; export interface ISupplyChainAppOptions { + disableSignalHandlers?: true; logLevel?: LogLevelDesc; + keychain?: IPluginKeychain; } export type ShutdownHook = () => Promise; @@ -63,6 +69,34 @@ export class SupplyChainApp { private readonly log: Logger; private readonly shutdownHooks: ShutdownHook[]; private readonly ledgers: SupplyChainAppDummyInfrastructure; + public readonly keychain: IPluginKeychain; + private _besuApiClient?: BesuApi; + private _quorumApiClient?: QuorumApi; + private _fabricApiClient?: FabricApi; + + public get besuApiClientOrThrow(): BesuApi { + if (this._besuApiClient) { + return this._besuApiClient; + } else { + throw new Error("Invalid state: ledgers were not started yet."); + } + } + + public get quorumApiClientOrThrow(): QuorumApi { + if (this._quorumApiClient) { + return this._quorumApiClient; + } else { + throw new Error("Invalid state: ledgers were not started yet."); + } + } + + public get fabricApiClientOrThrow(): FabricApi { + if (this._fabricApiClient) { + return this._fabricApiClient; + } else { + throw new Error("Invalid state: ledgers were not started yet."); + } + } public constructor(public readonly options: ISupplyChainAppOptions) { const fnTag = "SupplyChainApp#constructor()"; @@ -72,20 +106,39 @@ export class SupplyChainApp { } const { logLevel } = options; - this.ledgers = new SupplyChainAppDummyInfrastructure({ logLevel }); - this.shutdownHooks = []; - const level = logLevel || "INFO"; const label = "supply-chain-app"; this.log = LoggerProvider.getOrCreate({ level, label }); + + if (this.options.keychain) { + this.keychain = this.options.keychain; + this.log.info("Reusing the provided keychain plugin..."); + } else { + this.log.info("Instantiating new keychain plugin..."); + this.keychain = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId: uuidv4(), + logLevel: this.options.logLevel || "INFO", + }); + } + this.log.info("KeychainID=%o", this.keychain.getKeychainId()); + + this.ledgers = new SupplyChainAppDummyInfrastructure({ + logLevel, + keychain: this.keychain, + }); + this.shutdownHooks = []; } - public async start(): Promise { + public async start(): Promise { this.log.debug(`Starting SupplyChainApp...`); - exitHook((callback: IAsyncExitHookDoneCallback) => { - this.stop().then(callback); - }); + if (!this.options.disableSignalHandlers) { + exitHook((callback: IAsyncExitHookDoneCallback) => { + this.stop().then(callback); + }); + this.log.debug(`Registered signal handlers for graceful auto-shutdown`); + } await this.ledgers.start(); this.onShutdown(() => this.ledgers.stop()); @@ -93,17 +146,16 @@ export class SupplyChainApp { const contractsInfo = await this.ledgers.deployContracts(); const besuAccount = await this.ledgers.besu.createEthTestAccount(); + await this.keychain.set(besuAccount.address, besuAccount.privateKey); const quorumAccount = await this.ledgers.quorum.createEthTestAccount(); + await this.keychain.set(quorumAccount.address, quorumAccount.privateKey); const enrollAdminOut = await this.ledgers.fabric.enrollAdmin(); const adminWallet = enrollAdminOut[1]; const [userIdentity] = await this.ledgers.fabric.enrollUser(adminWallet); - const keychainEntryKey = "user2"; - const keychainEntryValue = JSON.stringify(userIdentity); - - const keychainIdA = "PluginKeychainMemory_A"; - const keychainIdB = "PluginKeychainMemory_B"; - const keychainIdC = "PluginKeychainMemory_C"; + const fabricUserKeychainKey = "user2"; + const fabricUserKeychainValue = JSON.stringify(userIdentity); + await this.keychain.set(fabricUserKeychainKey, fabricUserKeychainValue); // Reserve the ports where the Cactus nodes will run API servers, GUI const httpApiA = await Servers.startOnPort(4000, "0.0.0.0"); @@ -178,15 +230,11 @@ export class SupplyChainApp { fabricApiClient, web3SigningCredential: { keychainEntryKey: besuAccount.address, - keychainId: keychainIdA, + keychainId: this.keychain.getKeychainId(), type: Web3SigningCredentialType.CactusKeychainRef, }, }), - new PluginKeychainMemory({ - instanceId: uuidv4(), - keychainId: keychainIdA, - backend: new Map([[besuAccount.address, besuAccount.privateKey]]), - }), + this.keychain, ], }); @@ -200,7 +248,7 @@ export class SupplyChainApp { registryA.add(connectorBesu); - await this.startNode(httpApiA, httpGuiA, registryA); + const apiServerA = await this.startNode(httpApiA, httpGuiA, registryA); this.log.info(`Configuring Cactus Node for Ledger B...`); @@ -222,15 +270,11 @@ export class SupplyChainApp { fabricApiClient, web3SigningCredential: { keychainEntryKey: quorumAccount.address, - keychainId: keychainIdB, + keychainId: this.keychain.getKeychainId(), type: Web3SigningCredentialType.CactusKeychainRef, }, }), - new PluginKeychainMemory({ - instanceId: uuidv4(), - keychainId: keychainIdB, - backend: new Map([[quorumAccount.address, quorumAccount.privateKey]]), - }), + this.keychain, ], }); @@ -243,7 +287,7 @@ export class SupplyChainApp { registryB.add(quorumConnector); - await this.startNode(httpApiB, httpGuiB, registryB); + const apiServerB = await this.startNode(httpApiB, httpGuiB, registryB); this.log.info(`Configuring Cactus Node for Ledger C...`); @@ -265,11 +309,7 @@ export class SupplyChainApp { fabricApiClient, fabricEnvironment: org1Env, }), - new PluginKeychainMemory({ - instanceId: uuidv4(), - keychainId: keychainIdC, - backend: new Map([[keychainEntryKey, keychainEntryValue]]), - }), + this.keychain, ], }); @@ -296,7 +336,25 @@ export class SupplyChainApp { registryC.add(fabricConnector); - await this.startNode(httpApiC, httpGuiC, registryC); + const apiServerC = await this.startNode(httpApiC, httpGuiC, registryC); + + return { + apiServerA, + apiServerB, + apiServerC, + besuApiClient, + fabricApiClient, + quorumApiClient, + supplyChainApiClientA: new SupplyChainApi( + new Configuration({ basePath: nodeApiHostA }), + ), + supplyChainApiClientB: new SupplyChainApi( + new Configuration({ basePath: nodeApiHostA }), + ), + supplyChainApiClientC: new SupplyChainApi( + new Configuration({ basePath: nodeApiHostA }), + ), + }; } public async stop(): Promise { @@ -455,3 +513,15 @@ export class SupplyChainApp { return apiServer; } } + +export interface IStartInfo { + readonly apiServerA: ApiServer; + readonly apiServerB: ApiServer; + readonly apiServerC: ApiServer; + readonly besuApiClient: BesuApi; + readonly quorumApiClient: QuorumApi; + readonly fabricApiClient: FabricApi; + readonly supplyChainApiClientA: SupplyChainApi; + readonly supplyChainApiClientB: SupplyChainApi; + readonly supplyChainApiClientC: SupplyChainApi; +} diff --git a/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-backend-api-calls.test.ts b/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-backend-api-calls.test.ts new file mode 100644 index 0000000000..f9b77c8a90 --- /dev/null +++ b/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-backend-api-calls.test.ts @@ -0,0 +1,137 @@ +import test, { Test } from "tape-promise/tape"; +import { LogLevelDesc } from "@hyperledger/cactus-common"; +import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; +import { AuthorizationProtocol } from "@hyperledger/cactus-cmd-api-server"; +import { IAuthorizationConfig } from "@hyperledger/cactus-cmd-api-server"; +import { ConfigService } from "@hyperledger/cactus-cmd-api-server"; + +import * as publicApi from "../../../main/typescript/public-api"; +import { ISupplyChainAppOptions } from "../../../main/typescript/public-api"; +import { SupplyChainApp } from "../../../main/typescript/public-api"; + +const testCase = + "can launch via CLI with generated API server .config.json file"; +const logLevel: LogLevelDesc = "TRACE"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); + +test("Supply chain backend API calls can be executed", async (t: Test) => { + t.ok(publicApi, "Public API of the package imported OK"); + + const configService = new ConfigService(); + t.ok(configService, "Instantiated ConfigService truthy OK"); + + const exampleConfig = configService.newExampleConfig(); + t.ok(exampleConfig, "configService.newExampleConfig() truthy OK"); + + // FIXME - this hack should not be necessary, we need to re-think how we + // do configuration parsing. The convict library may not be the path forward. + exampleConfig.authorizationConfigJson = (JSON.stringify( + exampleConfig.authorizationConfigJson, + ) as unknown) as IAuthorizationConfig; + exampleConfig.authorizationProtocol = AuthorizationProtocol.NONE; + + const convictConfig = configService.newExampleConfigConvict(exampleConfig); + t.ok(convictConfig, "configService.newExampleConfigConvict() truthy OK"); + + const env = configService.newExampleConfigEnv(convictConfig.getProperties()); + + const config = configService.getOrCreate({ env }); + const apiSrvOpts = config.getProperties(); + const { logLevel } = apiSrvOpts; + + const appOptions: ISupplyChainAppOptions = { + logLevel, + disableSignalHandlers: true, + }; + const app = new SupplyChainApp(appOptions); + test.onFinish(() => app.stop()); + + // Node A => Besu + // Node B => Quorum + // Node C => Fabric 1.4.x + const startResult = await app.start(); + const { apiServerA, apiServerB, apiServerC } = startResult; + t.ok(apiServerA, "ApiServerA truthy OK"); + t.ok(apiServerB, "ApiServerB truthy OK"); + t.ok(apiServerC, "ApiServerC truthy OK"); + + const httpSrvApiA = apiServerA.getHttpServerApi(); + t.ok(httpSrvApiA, "httpSrvApiA truthy OK"); + const httpSrvApiB = apiServerB.getHttpServerApi(); + t.ok(httpSrvApiB, "httpSrvApiB truthy OK"); + const httpSrvApiC = apiServerC.getHttpServerApi(); + t.ok(httpSrvApiC, "httpSrvApiC truthy OK"); + + t.true(httpSrvApiA.listening, "httpSrvApiA.listening true OK"); + t.true(httpSrvApiB.listening, "httpSrvApiB.listening true OK"); + t.true(httpSrvApiC.listening, "httpSrvApiC.listening true OK"); + + const { besuApiClient, fabricApiClient, quorumApiClient } = startResult; + + const metricsResB = await besuApiClient.getPrometheusExporterMetricsV1(); + t.ok(metricsResB, "besu metrics res truthy OK"); + t.true(metricsResB.status > 199, "metricsResB.status > 199 true OK"); + t.true(metricsResB.status < 300, "metricsResB.status < 300 true OK"); + + const metricsResF = await fabricApiClient.getPrometheusExporterMetricsV1(); + t.ok(metricsResF, "fabric metrics res truthy OK"); + t.true(metricsResF.status > 199, "metricsResF.status > 199 true OK"); + t.true(metricsResF.status < 300, "metricsResF.status < 300 true OK"); + + const metricsResQ = await quorumApiClient.getPrometheusExporterMetricsV1(); + t.ok(metricsResQ, "quorum metrics res truthy OK"); + t.true(metricsResQ.status > 199, "metricsResQ.status > 199 true OK"); + t.true(metricsResQ.status < 300, "metricsResQ.status < 300 true OK"); + + const { + supplyChainApiClientA, + supplyChainApiClientB, + supplyChainApiClientC, + } = startResult; + + const listBambooHarvestRes = await supplyChainApiClientA.apiV1ListBambooHarvest(); + t.ok(listBambooHarvestRes, "listBambooHarvestRes truthy OK"); + t.true( + listBambooHarvestRes.status > 199, + "listBambooHarvestRes status > 199 truthy OK", + ); + t.true( + listBambooHarvestRes.status < 300, + "listBambooHarvestRes status < 300 truthy OK", + ); + + const listBookshelfRes = await supplyChainApiClientB.apiV1ListBookshelf(); + t.ok(listBookshelfRes, "listBookshelfRes truthy OK"); + t.true( + listBookshelfRes.status > 199, + "listBookshelfRes status > 199 truthy OK", + ); + t.true( + listBookshelfRes.status < 300, + "listBookshelfRes status < 300 truthy OK", + ); + + const listShipmentRes = await supplyChainApiClientC.apiV1ListShipment(); + t.ok(listShipmentRes, "listShipmentRes truthy OK"); + t.true( + listShipmentRes.status > 199, + "listShipmentRes status > 199 truthy OK", + ); + t.true( + listShipmentRes.status < 300, + "listShipmentRes status < 300 truthy OK", + ); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); diff --git a/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-cli-via-npm-script.test.ts b/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-cli-via-npm-script.test.ts new file mode 100644 index 0000000000..82d6cb1385 --- /dev/null +++ b/examples/cactus-example-supply-chain-backend/src/test/typescript/integration/supply-chain-cli-via-npm-script.test.ts @@ -0,0 +1,71 @@ +import path from "path"; +import { spawn } from "child_process"; +import test, { Test } from "tape-promise/tape"; +import { LogLevelDesc } from "@hyperledger/cactus-common"; +import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; +import * as publicApi from "../../../main/typescript/public-api"; + +const testCase = + "can launch via CLI with generated API server .config.json file"; +const logLevel: LogLevelDesc = "TRACE"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); + +test("Supply chain backend API calls can be executed", async (t: Test) => { + t.ok(publicApi, "Public API of the package imported OK"); + + const projectRoot = path.join(__dirname, "../../../../../../"); + + const child = spawn("npm", ["run", "start:example-supply-chain"], { + cwd: projectRoot, + }); + + const logs = []; + for await (const data of child.stdout) { + console.log(`[child]: ${data}`); + logs.push(data); + } + + for await (const data of child.stderr) { + console.error(`[child]: ${data}`); + logs.push(data); + } + + const childProcessPromise = new Promise((resolve, reject) => { + child.once("exit", (code: number, signal: NodeJS.Signals) => { + if (code === 0) { + resolve(); + } else { + const msg = `Child process crashed. exitCode=${code}, signal=${signal}`; + reject(new Error(msg)); + } + t.comment(`EVENT:exit signal=${signal}`); + t.comment(`EVENT:exit exitCode=${code}`); + }); + child.on("close", (code: number, signal: NodeJS.Signals) => { + t.comment(`EVENT:close signal=${signal}`); + t.comment(`EVENT:close exitCode=${code}`); + }); + child.on("disconnect", (code: number, signal: NodeJS.Signals) => { + t.comment(`EVENT:disconnect signal=${signal}`); + t.comment(`EVENT:disconnect exitCode=${code}`); + }); + child.on("error", (ex: Error) => { + t.comment(`EVENT:error ${ex.stack}`); + }); + }); + + await t.doesNotReject(childProcessPromise, "childProcessPromise resolves OK"); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); diff --git a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts index d5695750d5..e0adb0b48b 100644 --- a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts +++ b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts @@ -1,6 +1,7 @@ +import type { Server } from "http"; +import type { Server as SecureServer } from "https"; import { Optional } from "typescript-optional"; import { Express } from "express"; - import { Logger, Checks, @@ -126,11 +127,13 @@ export class SupplyChainCactusPlugin const insertShipment = new InsertShipmentEndpoint({ logLevel: this.options.logLevel, fabricApi: this.options.fabricApiClient, + keychainId: this.options.contracts.bookshelfRepository.keychainId, }); const listShipment = new ListShipmentEndpoint({ logLevel: this.options.logLevel, fabricApi: this.options.fabricApiClient, + keychainId: this.options.contracts.bookshelfRepository.keychainId, }); this.endpoints = [ @@ -144,7 +147,7 @@ export class SupplyChainCactusPlugin return this.endpoints; } - public getHttpServer(): Optional { + public getHttpServer(): Optional { return Optional.empty(); } diff --git a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/insert-shipment-endpoint.ts b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/insert-shipment-endpoint.ts index d358c9faa7..24fe108860 100644 --- a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/insert-shipment-endpoint.ts +++ b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/insert-shipment-endpoint.ts @@ -25,11 +25,13 @@ import OAS from "../../../json/openapi.json"; export interface IInsertShipmentEndpointOptions { logLevel?: LogLevelDesc; fabricApi: FabricApi; + keychainId: string; } export class InsertShipmentEndpoint implements IWebServiceEndpoint { public static readonly CLASS_NAME = "InsertShipmentEndpoint"; private readonly log: Logger; + private readonly keychainId: string; public get className(): string { return InsertShipmentEndpoint.CLASS_NAME; @@ -39,9 +41,12 @@ export class InsertShipmentEndpoint implements IWebServiceEndpoint { const fnTag = `${this.className}#constructor()`; Checks.truthy(opts, `${fnTag} arg options`); Checks.truthy(opts.fabricApi, `${fnTag} options.fabricApi`); + Checks.truthy(opts.keychainId, `${fnTag} options.keychain`); const level = this.opts.logLevel || "INFO"; const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); + + this.keychainId = opts.keychainId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -92,7 +97,7 @@ export class InsertShipmentEndpoint implements IWebServiceEndpoint { this.log.debug(`${tag} %o`, shipment); const request: RunTransactionRequest = { signingCredential: { - keychainId: "PluginKeychainMemory_C", + keychainId: this.keychainId, keychainRef: "user2", }, channelName: "mychannel", diff --git a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/list-shipment-endpoint.ts b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/list-shipment-endpoint.ts index 05f6f0238d..0a08d7fc8b 100644 --- a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/list-shipment-endpoint.ts +++ b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/web-services/list-shipment-endpoint.ts @@ -23,13 +23,15 @@ import { import OAS from "../../../json/openapi.json"; export interface IListShipmentEndpointOptions { - logLevel?: LogLevelDesc; - fabricApi: FabricApi; + readonly logLevel?: LogLevelDesc; + readonly fabricApi: FabricApi; + readonly keychainId: string; } export class ListShipmentEndpoint implements IWebServiceEndpoint { public static readonly CLASS_NAME = "ListShipmentEndpoint"; private readonly log: Logger; + private readonly keychainId: string; public get className(): string { return ListShipmentEndpoint.CLASS_NAME; @@ -59,9 +61,12 @@ export class ListShipmentEndpoint implements IWebServiceEndpoint { const fnTag = `${this.className}#constructor()`; Checks.truthy(opts, `${fnTag} arg options`); Checks.truthy(opts.fabricApi, `${fnTag} options.fabricApi`); + Checks.truthy(opts.keychainId, `${fnTag} options.keychainId`); const level = this.opts.logLevel || "INFO"; const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); + + this.keychainId = opts.keychainId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -91,7 +96,7 @@ export class ListShipmentEndpoint implements IWebServiceEndpoint { this.log.debug(`${tag}`); const request: RunTransactionRequest = { signingCredential: { - keychainId: "PluginKeychainMemory_C", + keychainId: this.keychainId, keychainRef: "user2", }, channelName: "mychannel",