From 058d51a5e977b2e7ee90831d4b6970e233106118 Mon Sep 17 00:00:00 2001 From: Bret Harrison Date: Wed, 9 Jan 2019 17:22:51 -0500 Subject: [PATCH] FABN-1083 NodeSDK allow commit/endorse handler Document how to use the commit and endorse handlers. The sendTransaction method will be enhanced to call the commit handler when defined and initialized. The sendTransactionProposal method will be enhanced to call the endorsement handler when defined and initialized. Change-Id: I579ecfe446886f92380e5ec125554d7147d4da43 Signed-off-by: Bret Harrison --- docs/tutorials/discovery.md | 71 ++-------- docs/tutorials/handlers.md | 124 ++++++++++++++++++ docs/tutorials/tutorials.json | 3 + fabric-client/lib/Channel.js | 68 ++++++---- fabric-client/lib/CommitHandler.js | 6 +- fabric-client/lib/EndorsementHandler.js | 4 +- fabric-client/lib/impl/BasicCommitHandler.js | 4 +- .../lib/impl/DiscoveryEndorsementHandler.js | 14 +- test/integration/discovery.js | 29 ++++ test/unit/channel.js | 29 ++++ 10 files changed, 255 insertions(+), 97 deletions(-) create mode 100644 docs/tutorials/handlers.md diff --git a/docs/tutorials/discovery.md b/docs/tutorials/discovery.md index 6c412031ba..0a0257f3f3 100644 --- a/docs/tutorials/discovery.md +++ b/docs/tutorials/discovery.md @@ -26,7 +26,10 @@ To use the service the application will have to connect with just one peer. * `channel.initialize()` - This method has been enhanced by adding an option to query a peer using the new service discovery to initialize the channel object. This method may be call at anytime to reinitialize the channel. When using discovery, -this may be used to assign a new target peer providing the discover service. +this may be used to assign a new target peer providing the discover service. +The initialize() method is also required to instantiate the handlers, by default +the handlers shipped with the fabric-client are designed to use the discovery +results. * `channel.sendTransactionProposal()` - This method has been enhanced to use the discovered peers to send the endorsement proposal. * `channel.sendTransaction()` - This method has been enhanced to use the discovered @@ -65,42 +68,6 @@ a custom handler to be used. This handler is used in the `sendTransaction` metho to determine the orderers and how to send the transaction to be committed. (default 'fabric-client/lib/impl/BasicCommitHandler.js') -### new `EndorsementHandler` -The sending of a proposal to be endorsed may be done using custom code. The -fabric-client will use by default the file called `DiscoveryEndorsementHandler`. -A different endorsement handler may be used by changing the configuration setting -"endorsement-handler" with the `setConfigSetting()` or placing a new line -in configuration JSON file that application has applied to the fabric-client -configuration. This will instantiate a handler -located at the path provide in the attribute for all channels initialized -after the call. -The handler may also be changed using the `endorsementHandler` attribute on the -`channel.initialize()` request call parameter. This will instantiate a handler -located at the path provide in the attribute just for this channel. -``` -// set value in memory -Client.setConfigSetting('endorsement-handler', '/path/to/the/handler.js'); ---or-- -// the path to an additional config file -Client.addConfigFile('/path/to/config.json'); -// the json file contains the following line -// "endorsement-handler": "/path/to/the/handler.js" ---or-- -const request = { - target: peer, - discovery: true, - endorsementHandler: "/path/to/the/handler.js", - ... -} -// request object contains the path to the handler -channel.initialize(request); -``` -A endorsement handler must implement the `api.EndorsementHandler`. When the -channel is instantiated, the channel will read the path setting and create an -instance of the handler for use by the new channel instance. - - - #### How the `DiscoveryEndorsementHandler` works The `sendTransactionProposal` will use the peers included in the "targets" to endorse the proposal. If there is no "targets" parameter, the endorsement request @@ -164,26 +131,6 @@ selected will likely change on every request. Note: If the above behavior does not meet the needs of your organization a custom handler may be used. -### new `CommitHandler` -The sending of the endorsements to be committed may be done using custom code. -The fabric-client will use by default the file called `BasicCommitHandler`. -The commit handler may be changed by changing the configuration setting -"commit-handler" by doing a `setConfigSetting()` or placing a new line -in configuration JSON file that application has applied to the fabric-client -configuration. -``` -// set the config value in memory -Client.setConfigSetting('commit-handler', '/path/to/the/handler.js'); ---or-- -// path of an additional config file -Client.addConfigFile('/path/to/config.json'); -// the json file contains the following line -// "commit-handler": "/path/to/the/handler.js" -``` -A commit handler must implement the `api.CommitHandler`. When the -channel is instantiated, the channel will read the path setting and create an -instance of the handler for use by the new channel instance. - #### How the `BasicCommitHandler` works The default handler that comes with the fabric-client will send to one orderer at a time until it receives a successful submission of the transaction. Sending @@ -193,17 +140,19 @@ sender has the authority to send the request. The response from the orderer will indicate that the orderer has accepted the request. The `sendTransaction` has an optional parameter `orderer` that indicates the orderer to send the transaction. The handler will use the orderer as specified with the `orderer` -parameter and send to any other orderers. If no orderer is specified the handler +parameter and not send to any other orderers. If no orderer is specified the handler will get the list of orderers assigned to the channel. These orderers may have been assigned manually to the channel with a `channel.addOrderer()` call or -automatically when using the service discovery. +assigned automatically when using the service discovery. ### To Initialize - - By default the fabric-client will not use the service discovery. To enable the use of the service, set the config setting to true or use the discover parameter on the `initialize()` call. + +note: {@link Channel#initialize} must be run to both enable discovery and to +startup the handlers. + ``` Client.setConfigSetting('initialize-with-discovery', true); --or-- diff --git a/docs/tutorials/handlers.md b/docs/tutorials/handlers.md new file mode 100644 index 0000000000..e563d5f2fc --- /dev/null +++ b/docs/tutorials/handlers.md @@ -0,0 +1,124 @@ + +This tutorial illustrates the use of the handlers by the Hyperledger Fabric Node.js Client as of 1.3. + +For more information on: +* getting started with Hyperledger Fabric see +[Building your first network](http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html). +* the configuration of a channel in Hyperledger Fabric and the internal +process of creating and updating see +[Hyperledger Fabric channel configuration](http://hyperledger-fabric.readthedocs.io/en/latest/configtx.html) +* [Service Discovery](https://hyperledger-fabric.readthedocs.io/en/latest/discovery-overview.html) + +The following assumes an understanding of the Hyperledger Fabric network +(orderers and peers), +and of Node application development, including the use of the +Javascript `promise` and `async await`. + +### Overview +The fabric-client provides the ability for custom code that will handle the +endorsement process and the submitting of endorsements to the orderer. +There are two plug points defined, one on the {@link Channel#sendTransactionProposal} +and one on the {@link Channel#sendTransaction}. The fabric-client will pass +control to the handler to complete the processing. The custom code may +decide to retry, try another end point, or use discovery to complete the +task. + +see {@tutorial discovery} on how the default handlers are +used with discovery. + +#### Modified API's that will use handlers +* `channel.initialize()` - This method has been enhanced to instantiate +instances of the handlers for use by the channel. The method will get the +paths from the system configuration settings to create and initialize them. +* `channel.sendTransactionProposal()` - This method has been enhanced to use +an `endorsement-handler` if one has been instantiated and initialized. +* `channel.sendTransaction()` - This method has been enhanced to use +a `commit-handler` if one has been instantiated and initialized. + + + +#### New configuration settings +* `endorsement-handler` - string - The path to the endorsement handler. Allows for a +custom handler to be used. This handler is used in the +{@linkcode Channel#sendTransactionProposal sendTransactionProposal()} +method to determine the target peers and how to send the proposal. +(default 'fabric-client/lib/impl/DiscoveryEndorsementHandler.js') +* `commit-handler` - string - The path to the commit handler. Allows for +a custom handler to be used. This handler is used in the +{@linkcode Channel#sendTransaction sendTransaction()} method +to determine the orderers and how to send the transaction to be committed. +(default 'fabric-client/lib/impl/BasicCommitHandler.js') + +### new Endorsement Handler +The sending of a proposal to be endorsed may be done using custom code. The +fabric-client will use by default the file called `DiscoveryEndorsementHandler`. +A different endorsement handler may be used by changing the configuration setting +"endorsement-handler" with the `setConfigSetting()` or placing a new line +in configuration JSON file that application has applied to the fabric-client +configuration. This will instantiate a handler +located at the path provide in the attribute for all channels initialized +after the call. +The default handler was designed to be used with discovery to provided automatic +selection of peers and fail over. When used without discovery the handler will +only send to the peers as defined in the targets parameter without fail over. +The handler may also be changed using the `endorsementHandler` attribute on the +`channel.initialize()` request call parameter. This will instantiate a handler +located at the path provide in the attribute just for this channel. +``` +// set value in memory +Client.setConfigSetting('endorsement-handler', '/path/to/the/handler.js'); +--or-- +// the path to an additional config file +Client.addConfigFile('/path/to/config.json'); +// the json file contains the following line +// "endorsement-handler": "/path/to/the/handler.js" +--or-- +const request = { + ... + endorsementHandler: "/path/to/the/handler.js", + ... +} +// initialize must be run to use handlers. +channel.initialize(request); +``` +A endorsement handler should extend the {@link EndorsementHandler}. When the +channel is initialized, the channel will read the path setting and create an +instance of the handler for use by the new channel instance. + +### new `CommitHandler` +The sending of the endorsements to be committed may be done using custom code. +The fabric-client will use by default the file called `BasicCommitHandler`. +The commit handler may be changed by changing the configuration setting +"commit-handler" by doing a `setConfigSetting()` or placing a new line +in configuration JSON file that application has applied to the fabric-client +configuration. +The default handler was designed to be used with discovery to provided automatic +selection of orderers and fail over. When used without discovery the handler will +still provide fail over to all orderers assigned to the channel, sending to +each one in orderer until an orderer response successfully to the transaction +submission. +The handler may also be changed using the `commitHandler` attribute on the +`channel.initialize()` request call parameter. This will instantiate a handler +located at the path provide in the attribute just for this channel. +``` +// set the config value in memory +Client.setConfigSetting('commit-handler', '/path/to/the/handler.js'); +--or-- +// path of an additional config file +Client.addConfigFile('/path/to/config.json'); +// the json file contains the following line +// "commit-handler": "/path/to/the/handler.js" +--or-- +const request = { + ... + commitHandler: "/path/to/the/handler.js", + ... +} +// initialize must be run to use handlers. +channel.initialize(request); +``` +A commit handler should extend the {@link CommitHandler}. When the +channel is initialized, the channel will read the path setting and create an +instance of the handler for use by the new channel instance. + +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. diff --git a/docs/tutorials/tutorials.json b/docs/tutorials/tutorials.json index 0eb397af7f..455eacdf90 100644 --- a/docs/tutorials/tutorials.json +++ b/docs/tutorials/tutorials.json @@ -37,5 +37,8 @@ }, "grpc-settings": { "title": "fabric-client: How to set gRPC settings" + }, + "handlers": { + "title": "fabric-client: How to use the endorsement and commit handlers" } } diff --git a/fabric-client/lib/Channel.js b/fabric-client/lib/Channel.js index a925255d93..cb38627705 100755 --- a/fabric-client/lib/Channel.js +++ b/fabric-client/lib/Channel.js @@ -108,7 +108,7 @@ const Channel = class { this._last_discover_timestamp = null; this._use_discovery = sdk_utils.getConfigSetting('initialize-with-discovery', false); this._as_localhost = sdk_utils.getConfigSetting('discovery-as-localhost', true); - this._endorsement_handler = null; // will be setup during initialization + this._endorsement_handler = null; this._commit_handler = null; logger.debug('Constructed Channel instance: name - %s, network mode: %s', this._name, !this._devMode); @@ -134,7 +134,7 @@ const Channel = class { * When used with `targets` parameter, the peer referenced here will be * added to the `targets` array. * Default is to use the first ChannelPeer assigned to this channel. - * @property {Array.<(Peer | ChannelPeer)>} targets - Optional. The target peers to be used + * @property {string[] | Peer[] | ChannelPeer[]} targets - Optional. The target peers to be used * to make the initialization requests for configuration information. * When used with `target` parameter, the peer referenced there will be * added to the `targets` array. @@ -165,6 +165,10 @@ const Channel = class { * This method retrieves the configuration from the orderer if no "config" parameter is passed in. * Optionally a configuration may be passed in to initialize this channel without making the call * to the orderer. + *

+ * This method will also automatically load orderers and peers that represent + * the fabric network when using discovery. This application must provide a + * peer running the fabric discovery service. * * @param {InitializeRequest} request - Optional. a {@link InitializeRequest} * @return {Promise} A Promise that will resolve when the action is complete @@ -210,25 +214,9 @@ const Channel = class { } } - // setup the endorsement handler - if (!endorsement_handler_path && this._use_discovery) { - endorsement_handler_path = sdk_utils.getConfigSetting('endorsement-handler'); - logger.debug('%s - using config setting for endorsement handler ::%s', method, endorsement_handler_path); - } - if (endorsement_handler_path) { - this._endorsement_handler = require(endorsement_handler_path).create(this); - await this._endorsement_handler.initialize(); - } - - // setup the commit handler - if (!commit_handler_path) { - commit_handler_path = sdk_utils.getConfigSetting('commit-handler'); - logger.debug('%s - using config setting for commit handler ::%s', method, commit_handler_path); - } - if (commit_handler_path) { - this._commit_handler = require(commit_handler_path).create(this); - await this._commit_handler.initialize(); - } + // setup the handlers + this._endorsement_handler = await this._build_handler(endorsement_handler_path, 'endorsement-handler'); + this._commit_handler = await this._build_handler(commit_handler_path, 'commit-handler'); let results = null; try { @@ -2698,7 +2686,12 @@ const Channel = class { logAndThrow(method, 'Missing "args" in Transaction proposal request'); } - if (!request.targets && this._endorsement_handler) { + // convert any names into peer objects or if empty find all + // endorsing peers added to this channel + request.targets = this._getTargets(request.targets, Constants.NetworkConfig.ENDORSING_PEER_ROLE); + + // always use the handler if available (may not be just for discovery) + if (this._endorsement_handler) { logger.debug('%s - running with endorsement handler', method); const proposal = Channel._buildSignedProposal(request, this._name, this._clientContext); @@ -2713,7 +2706,8 @@ const Channel = class { request: request, signed_proposal: proposal.signed, timeout: timeout, - endorsement_hint: endorsement_hint + endorsement_hint: endorsement_hint, + use_discovery: this._use_discovery }; const responses = await this._endorsement_handler.endorse(params); @@ -2721,7 +2715,6 @@ const Channel = class { return [responses, proposal.source]; } else { logger.debug('%s - running without endorsement handler', method); - request.targets = this._getTargets(request.targets, Constants.NetworkConfig.ENDORSING_PEER_ROLE); return Channel.sendTransactionProposal(request, this._name, this._clientContext, timeout); } @@ -2829,7 +2822,7 @@ const Channel = class { * to the orderer for further processing. This is the 2nd phase of the transaction * lifecycle in the fabric. The orderer will globally order the transactions in the * context of this channel and deliver the resulting blocks to the committing peers for - * validation against the chaincode's endorsement policy. When the committering peers + * validation against the chaincode's endorsement policy. When the committing peers * successfully validate the transactions, it will mark the transaction as valid inside * the block. After all transactions in a block have been validated, and marked either as * valid or invalid (with a [reason code]{@link https://github.com/hyperledger/fabric/blob/v1.0.0/protos/peer/transaction.proto#L125}), @@ -2838,7 +2831,6 @@ const Channel = class { * The caller of this method must use the proposal responses returned from the endorser along * with the original proposal that was sent to the endorser. Both of these objects are contained * in the {@link ProposalResponseObject} returned by calls to any of the following methods: - *
  • [installChaincode()]{@link Client#installChaincode} *
  • [sendInstantiateProposal()]{@link Channel#sendInstantiateProposal} *
  • [sendUpgradeProposal()]{@link Channel#sendUpgradeProposal} *
  • [sendTransactionProposal()]{@link Channel#sendTransactionProposal} @@ -2898,9 +2890,15 @@ const Channel = class { const envelope = Channel.buildEnvelope(this._clientContext, chaincodeProposal, endorsements, proposalResponse, use_admin_signer); if (this._commit_handler) { + // protect the users input + const param_request = Object.assign({}, request); + if (param_request.orderer) { + // check and convert to orderer object if a name + param_request.orderer = this._clientContext.getTargetOrderer(param_request.orderer, this.getOrderers(), this._name); + } const params = { signed_envelope: envelope, - request: request, + request: param_request, timeout: timeout }; return this._commit_handler.commit(params); @@ -3503,6 +3501,22 @@ const Channel = class { return JSON.stringify(state).toString(); } + async _build_handler(_handler_path, handler_name) { + const method = '_build_handler'; + let handler_path = _handler_path; + let handler = null; + if (!handler_path) { + handler_path = sdk_utils.getConfigSetting(handler_name); + logger.debug('%s - using path %s for %s', method, handler_path, handler_name); + } + if (handler_path) { + handler = require(handler_path).create(this); + await handler.initialize(); + logger.debug('%s - create instance of %s', method, handler_name); + } + return handler; + } + }; // internal utility method to decode and get the write set diff --git a/fabric-client/lib/CommitHandler.js b/fabric-client/lib/CommitHandler.js index bd229fcfba..abcf087c68 100644 --- a/fabric-client/lib/CommitHandler.js +++ b/fabric-client/lib/CommitHandler.js @@ -36,9 +36,9 @@ class CommitHandler { * the channel. The handler is expected to preform failover and use all available * orderers to send the endorsed transaction. * - * @param {CommitHandlerParameters} params - A {@link EndorsementHandlerParameters} + * @param {CommitHandlerParameters} params - A {@link CommitHandlerParameters} * @returns {Promise} A Promise for the {@link ProposalResponseObject}, the - * same results as calling the {@link Channel} 'sendTransactionProposal' + * same results as calling the {@link Channel#sendTransaction} * method directly. */ commit(params) { @@ -49,7 +49,7 @@ class CommitHandler { } /** - * This method will be called by the channel when the channel is initialzied. + * This method will be called by the channel when the channel is initialized. */ initialize() { throw new Error('The "initialize" method must be implemented'); diff --git a/fabric-client/lib/EndorsementHandler.js b/fabric-client/lib/EndorsementHandler.js index 14c51a7060..11bd4ed9be 100644 --- a/fabric-client/lib/EndorsementHandler.js +++ b/fabric-client/lib/EndorsementHandler.js @@ -41,7 +41,7 @@ class EndorsementHandler { * a {@link ChaincodeInvokeRequest} to be sent using the included channel * with the {@link Channel} 'sendTransactionProposal' method. * @returns {Promise} A Promise for the {@link ProposalResponseObject}, the - * same results as calling the {@link Channel} 'sendTransactionProposal' + * same results as calling the {@link Channel#sendTransactionProposal} * method directly. */ endorse(params) { @@ -52,7 +52,7 @@ class EndorsementHandler { } /** - * This method will be called by the channel when the channel is initialzied. + * This method will be called by the channel when the channel is initialized. */ initialize() { throw new Error('The "initialize" method must be implemented'); diff --git a/fabric-client/lib/impl/BasicCommitHandler.js b/fabric-client/lib/impl/BasicCommitHandler.js index 5631ffbfb5..badbaeb9d8 100644 --- a/fabric-client/lib/impl/BasicCommitHandler.js +++ b/fabric-client/lib/impl/BasicCommitHandler.js @@ -14,12 +14,12 @@ const logger = utils.getLogger('BasicCommitHandler'); /** - * This is an implementation of the [CommitHandler]{@link module:api.CommitHandler} API. + * This is an implementation of the [CommitHandler]{@link CommitHandler} API. * It will submit transactions to be committed to one orderer at time from a provided * list or a list currently assigned to the channel. * * @class - * @extends module:api.CommitHandler + * @extends CommitHandler */ class BasicCommitHandler extends CommitHandler { diff --git a/fabric-client/lib/impl/DiscoveryEndorsementHandler.js b/fabric-client/lib/impl/DiscoveryEndorsementHandler.js index e291a4fd58..ccf02a2913 100644 --- a/fabric-client/lib/impl/DiscoveryEndorsementHandler.js +++ b/fabric-client/lib/impl/DiscoveryEndorsementHandler.js @@ -13,6 +13,8 @@ const util = require('util'); const utils = require('../utils'); const EndorsementHandler = require('../EndorsementHandler'); const logger = utils.getLogger('DiscoveryEndorsementHandler'); +const client_utils = require('fabric-client/lib/client-utils.js'); + const BLOCK_HEIGHT = 'ledgerHeight'; const RANDOM = 'random'; @@ -20,12 +22,12 @@ const DEFAULT = 'default'; /** - * This is an implementation of the [EndorsementHandler]{@link module:api.EndorsementHandler} API. + * This is an implementation of the [EndorsementHandler]{@link EndorsementHandler} API. * It will submit transactions to be endorsed to a target list generated from the * results of service discovery. * * @class - * @extends module:api.EndorsementHandler + * @extends EndorsementHandler */ class DiscoveryEndorsementHandler extends EndorsementHandler { @@ -96,6 +98,14 @@ class DiscoveryEndorsementHandler extends EndorsementHandler { timeout = params.timeout; } + // when not using discovery + if (!params.use_discovery) { + logger.debug('%s - running without discovery', method); + const responses = await client_utils.sendPeersProposal(params.request.targets, params.signed_proposal, timeout); + + return responses; + } + let endorsement_plan = null; try { // this will check the age of the results and get a new plan if needed diff --git a/test/integration/discovery.js b/test/integration/discovery.js index 4063e0a9d4..b4bd7c3500 100644 --- a/test/integration/discovery.js +++ b/test/integration/discovery.js @@ -210,6 +210,18 @@ test('\n\n***** D I S C O V E R Y *****\n\n', async (t) => { const bad_orderer = client_org1.newOrderer('grpc://somebadhost:1000'); channel_org1.addOrderer(bad_orderer); // will put this orderer first on the list + if (channel_org1._endorsement_handler === null) { + t.pass('Successfully checked channel does not have handler'); + } else { + t.fail('Failed- Channel already has handler'); + } + + if (channel_org1._commit_handler === null) { + t.pass('Successfully checked channel does not have handler'); + } else { + t.fail('Failed- Channel already has handler'); + } + // This will call the discovery under the covers and load the channel with msps, orderers, and peers results = await channel_org1.initialize({asLocalhost: true, discover: true, target: peer_org1}); t.equal(channel_org1.getOrderers().length, 2, 'Checking that there are two orderers assigned to the channel'); @@ -223,6 +235,18 @@ test('\n\n***** D I S C O V E R Y *****\n\n', async (t) => { // after it fails with the bad peer results = await channel_org1.initialize({asLocalhost: true, discover: true, targets: [peer_bad, peer_org1]}); + if (channel_org1._endorsement_handler !== null) { + t.pass('Successfully checked channel has the handler'); + } else { + t.fail('Failed- Channel does not have handler'); + } + + if (channel_org1._commit_handler !== null) { + t.pass('Successfully checked channel has the handler'); + } else { + t.fail('Failed- Channel does not have handler'); + } + t.equal(channel_org1.getOrderers().length, 2, 'Checking that there are two orderers assigned to the channel'); const msps = channel_org1.getMSPManager().getMSPs(); t.equals(msps.Org1MSP._id, 'Org1MSP', 'Check that the MSP was loaded by initialize'); @@ -325,7 +349,10 @@ test('\n\n***** D I S C O V E R Y *****\n\n', async (t) => { ]} }; try { + // setup to test if the endorsement handler will be built by the sendTransactionProposal method + results = await channel_org1.sendTransactionProposal(collections_request); + if (testUtil.checkGoodResults(t, results)) { t.pass('Successfully endorsed chaincode to chaincode with collections'); } else { @@ -381,6 +408,7 @@ async function installChaincode(t, client, channel, peer, chaincode_id, chaincod async function startChaincode(t, client, channel, orderer, peers, chaincode_id, chaincode_ver) { try { + // reset the testing const tx_id = client.newTransactionID(true); const policy = { @@ -436,6 +464,7 @@ async function startChaincode(t, client, channel, orderer, peers, chaincode_id, proposal: proposal_results[1], txId : tx_id }; + const commit_results = await channel.sendTransaction(commit_request); if (commit_results && commit_results.status === 'SUCCESS') { await testUtil.sleep(10000); // let the discovery catch up diff --git a/test/unit/channel.js b/test/unit/channel.js index 987d36b707..1b26b50244 100644 --- a/test/unit/channel.js +++ b/test/unit/channel.js @@ -1141,6 +1141,35 @@ test('\n\n ** Channel Discovery tests **\n\n', async (t) => { } } + try { + await channel.initialize({ + target: peer, + commitHandler: 'no.where' + }); + t.fail('able to initialize channel with a bad commit handler path'); + } catch (error) { + if (error.message.includes('Cannot find module')) { + t.pass('Check Failed to initialize channel with bad commit handler path'); + } else { + t.fail('1.2 - Receive other failure ' + error.toString()); + } + } + + try { + await channel.initialize({ + target: peer, + endorsementHandler: 'fabric-client/lib/impl/BasicCommitHandler.js', + discover: false + }); + t.fail('able to initialize channel with a good commit handler path'); + } catch (error) { + if (error.message.includes('Failed to connect before the deadline')) { + t.pass('Check Failed to initialize channel with good commit handler path'); + } else { + t.fail('2.1 - Receive other failure ' + error.toString()); + } + } + const handler_path_temp = client.getConfigSetting('endorsement-handler'); try { client.setConfigSetting('endorsement-handler', 'bad.path');