From a8554c1423c08d2bec300d632a28c93210711f25 Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Sat, 18 Feb 2017 12:45:15 -0500 Subject: [PATCH] CouchDBKeyValueStore ctor to ask for url FAB-2355 Current constructor asks for a client instance, it should instead simply ask for the url and optionally the name of the database. Change-Id: Idfddd1c5f5ca5598ee47cb4bd931adb2e4c1e258 Signed-off-by: Jim Zhang --- .../lib/impl/CouchDBKeyValueStore.js | 46 ++-- .../lib/impl/CryptoSuite_ECDSA_AES.js | 39 ++-- package.json | 1 + test/fixtures/couchdb.json | 2 +- test/integration/couchdb-fabricca-tests.js | 12 +- test/integration/couchdb-util.js | 16 +- test/unit/chain.js | 91 ++++---- test/unit/client.js | 157 +++++++------- test/unit/couchdb-key-value-store.js | 90 ++++++++ test/unit/crypto-key-store.js | 135 +++++++++++- test/unit/cryptosuite-ecdsa-aes.js | 202 ++++++++++-------- test/unit/fabric-ca-client.js | 51 +++-- test/unit/file-key-value-store.js | 26 ++- test/unit/identity.js | 4 +- test/unit/user.js | 15 +- 15 files changed, 556 insertions(+), 331 deletions(-) create mode 100644 test/unit/couchdb-key-value-store.js diff --git a/fabric-client/lib/impl/CouchDBKeyValueStore.js b/fabric-client/lib/impl/CouchDBKeyValueStore.js index e934285b88..ab45bebb11 100644 --- a/fabric-client/lib/impl/CouchDBKeyValueStore.js +++ b/fabric-client/lib/impl/CouchDBKeyValueStore.js @@ -19,6 +19,7 @@ var api = require('../api.js'); var fs = require('fs-extra'); var path = require('path'); +var util = require('util'); var utils = require('../utils'); var nano = require('nano'); @@ -35,37 +36,23 @@ var CouchDBKeyValueStore = class extends api.KeyValueStore { /** * constructor * - * @description options contains a path property which represents a CouchDB client instance. - * The following code snippet shows how to create a nano minimalistic client for CouchDB. For more - * information see github dscape / nano. - *
var nano = require('nano');
-	 * var couchDBClient = nano(couchdb_IP_Address + ':' + couchdb_Port);
- * - *
The following code snippet shows how to create a Cloudant CouchDB client. - * Username and password map to the IBM Bluemix service credentials VCAP_SERVICES environment variables username and password. - * To obtain an instance of Cloudant, see the IBM Bluemix Catalog --> Services --> Data & Analytics at - * Cloudant NoSQL DB. - *
var Cloudant = require('cloudant');
-	 * var cloudantClient = Cloudant({account: username, password: password});
- *
- * - * @param {Object} options Contains two properties: - *
  • path - The CouchDB database client instance. + * @param {Object} options Contains the properties: + *
  • url - The CouchDB instance url. *
  • name - Optional. Identifies the name of the database if different from the default of 'member_db'. */ constructor(options) { logger.debug('constructor, options: ' + options); - if (!options || !options.path) { - throw new Error('Must provide the CouchDB database client instance to store membership data.'); + if (!options || !options.url) { + throw new Error('Must provide the CouchDB database url to store membership data.'); } // Create the keyValStore instance super(); var self = this; - // path is the database client instance - this._path = options.path; + // url is the database instance url + this._url = options.url; // Name of the database, optional if (!options.name) { this._name = 'member_db'; @@ -73,34 +60,37 @@ var CouchDBKeyValueStore = class extends api.KeyValueStore { this._name = options.name; } - logger.debug('options.path - ' + options.path); + logger.debug('options.url - ' + options.url); logger.debug('options.name - ' + options.name); return new Promise(function(resolve, reject) { // Initialize the CouchDB database client - var dbClient = self._path; + var dbClient = nano(self._url); // Check if the database already exists. If not, create it. dbClient.db.get(self._name, function(err, body) { // Check for error if (err) { // Database doesn't exist if (err.error == 'not_found') { - logger.info('No member_db found, creating member_db'); + logger.info(util.format('No %s found, creating %s', self._name, self._name)); + + dbClient.db.create(self._name, function(err, body) { + if (err) { + return reject(new Error(util.format('Failed to create %s database due to error: %s', self._name, err.stack ? err.stack : err))); + } - dbClient.db.create(self._name, function() { - logger.info('Created member_db database'); + logger.info(util.format('Created %s database', self._name)); // Specify it as the database to use self._database = dbClient.use(self._name); resolve(self); }); } else { // Other error - logger.error('ERROR: ' + err); - reject(new Error('Error creating member_db database to store membership data.')); + return reject(new Error(util.format('Error creating %s database to store membership data: %s', self._name, err.stack ? err.stack : err))); } } else { // Database exists - logger.info('member_db already exists'); + logger.info(util.format('%s already exists', self._name)); // Specify it as the database to use self._database = dbClient.use(self._name); resolve(self); diff --git a/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js b/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js index 44a36776c4..c6d5704bbb 100644 --- a/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js +++ b/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js @@ -49,27 +49,41 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite { * constructor * * @param {number} keySize Key size for the ECDSA algorithm, can only be 256 or 384 - * @param {string} kvsPath A path to a directory used by the built-in key store to save private keys + * @param {string} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different + * {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the + * KeyValueStore interface. + * @param {object} opts Implementation-specific options object for the {@link KeyValueStore} class to instantiate an instance */ - constructor(keySize, kvsPath) { + constructor(keySize, KVSImplClass, opts) { if (keySize !== 256 && keySize !== 384) { throw new Error('Illegal key size: ' + keySize + ' - this crypto suite only supports key sizes 256 or 384'); } super(); - if (typeof kvsPath === 'undefined' || kvsPath === null) { - this._storePath = null; + var superClass; + + if (typeof KVSImplClass !== 'function') { + superClass = require(utils.getConfigSetting('key-value-store')); } else { - if (typeof kvsPath !== 'string') { - throw new Error('The "kvsPath" parameter for this constructor, if specified, must be a string specifying a file system path'); - } + superClass = KVSImplClass; + } - this._storePath = kvsPath; + if (KVSImplClass && typeof opts === 'undefined') { + // the function is called with only one argument for the 'opts' + opts = KVSImplClass; + } else if (typeof KVSImplClass === 'undefined' && typeof opts === 'undefined') { + opts = { + path: CryptoSuite_ECDSA_AES.getDefaultKeyStorePath() + }; } this._keySize = keySize; this._store = null; + this._storeConfig = { + superClass: superClass, + opts: opts + }; this._initialize(); } @@ -226,16 +240,15 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite { var self = this; return new Promise((resolve, reject) => { if (self._store === null) { - var storePath = self._storePath ? self._storePath : CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(); - logger.info('This class requires a CryptoKeyStore to save keys, using the store at %s', self._storePath); + logger.info(util.format('This class requires a CryptoKeyStore to save keys, using the store: %j', self._storeConfig)); - CKS({ - path: storePath - }) + CKS(self._storeConfig.superClass, self._storeConfig.opts) .then((ks) => { logger.debug('_getKeyStore returning ks'); self._store = ks; return resolve(self._store); + }).catch((err) => { + reject(err); }); } else { logger.debug('_getKeyStore resolving store'); diff --git a/package.json b/package.json index 86e092213e..c110ca119d 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "intercept-stdout": "^0.1.2", "jsrsasign": "6.2.2", "log4js": "^0.6.38", + "mock-couch": "https://github.com/jimthematrix/mock-couch.git", "nano": "^6.2.0", "require-dir": "^0.3.0", "rewire": "^2.5.2", diff --git a/test/fixtures/couchdb.json b/test/fixtures/couchdb.json index cd37ca64e4..76f2ee7c6d 100644 --- a/test/fixtures/couchdb.json +++ b/test/fixtures/couchdb.json @@ -1,5 +1,5 @@ { "couchdb-ip-addr" : "http://localhost", "couchdb-port" : "5984", - "key-value-store" : "./impl/CouchDBKeyValueStore.js" + "key-value-store" : "fabric-client/lib/impl/CouchDBKeyValueStore.js" } diff --git a/test/integration/couchdb-fabricca-tests.js b/test/integration/couchdb-fabricca-tests.js index d0e027e3fe..b26c5cea67 100644 --- a/test/integration/couchdb-fabricca-tests.js +++ b/test/integration/couchdb-fabricca-tests.js @@ -28,10 +28,14 @@ var couchdbUtil = require('./couchdb-util.js'); // Use the CouchDB specific config file hfc.addConfigFile('test/fixtures/couchdb.json'); -var dbClient = couchdbUtil.getCouchDBClient(); + var keyValueStore = hfc.getConfigSetting('key-value-store'); console.log('Key Value Store = ' + keyValueStore); +var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound'); +var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound'); +var keyValStorePath = couchdbIPAddr + ':' + couchdbPort; + // This test first checks to see if a user has already been enrolled. If so, // the test terminates. If the user is not yet enrolled, the test uses the // FabricCAClientImpl to enroll a user, and saves the enrollment materials into the @@ -49,11 +53,11 @@ test('Use FabricCAServices with a CouchDB KeyValueStore', function(t) { var dbname = 'member_db'; var member; - couchdbUtil.destroy(dbname, dbClient) + couchdbUtil.destroy(dbname, keyValStorePath) .then( function(status) { t.comment('Cleanup of existing ' + dbname + ' returned '+status); t.comment('Initilize the CouchDB KeyValueStore'); - utils.newKeyValueStore({name: dbname, path: dbClient}) + utils.newKeyValueStore({name: dbname, url: keyValStorePath}) .then( function(kvs) { t.comment('Setting client keyValueStore to: ' +kvs); @@ -88,7 +92,7 @@ test('Use FabricCAServices with a CouchDB KeyValueStore', function(t) { }); }, function(err) { - t.fail('Failed to initilize the Fabric CA service: ' + err); + t.fail('Failed to initilize the Fabric CA service: ' + err.stack ? err.stack : err); t.end(); } ) diff --git a/test/integration/couchdb-util.js b/test/integration/couchdb-util.js index 7adc2e9344..d067a84543 100644 --- a/test/integration/couchdb-util.js +++ b/test/integration/couchdb-util.js @@ -25,18 +25,8 @@ module.exports.getCloudantClient = function(configFile) { return Cloudant({account: username, password: password}); }; -module.exports.getCouchDBClient = function(configFile) { - var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound'); - var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound'); - - // Record the CouchDB KeyValueStorePath set by couchdb.json - var keyValStorePath = couchdbIPAddr + ':' + couchdbPort; - console.log('CouchDBClient IP address:port = ' + keyValStorePath); - return nano(keyValStorePath); -}; - -module.exports.destroy = function(name, path) { - this._path = path; +module.exports.destroy = function(name, url) { + this._url = url; this._name = name; // Name of the database, optional if (!name) { @@ -44,7 +34,7 @@ module.exports.destroy = function(name, path) { } var self = this; return new Promise(function(resolve, reject) { - var dbClient = self._path; + var dbClient = nano(self._url); dbClient.db.destroy(self._name, function(err, body) { if (err) { resolve(false); diff --git a/test/unit/chain.js b/test/unit/chain.js index b5c53822a9..74212e967c 100644 --- a/test/unit/chain.js +++ b/test/unit/chain.js @@ -257,6 +257,7 @@ test('\n\n ** Chain - method tests **\n\n', function (t) { test_chain.initializeChain().then( function (response) { t.fail('Chain tests: orderer should have been required'); + t.end(); }, function (error) { if(!error) { @@ -265,13 +266,15 @@ test('\n\n ** Chain - method tests **\n\n', function (t) { else { t.equals(error.toString(),'Error: no primary orderer defined','Chain tests: orederer is required when initializing'); } + + var test_chain2 = new Chain('someTestChain2', {_userContext : {} }); + test_chain2.addOrderer(new Orderer('grpc://somehost.com:1234')); + return test_chain2.initializeChain(); } - ); - var test_chain2 = new Chain('someTestChain2', {_userContext : {} }); - test_chain2.addOrderer(new Orderer('grpc://somehost.com:1234')); - test_chain2.initializeChain().then( + ).then( function (response) { t.fail('Chain tests: transaction should have been required'); + t.end(); }, function (error) { if(!error) { @@ -280,20 +283,24 @@ test('\n\n ** Chain - method tests **\n\n', function (t) { else { t.equals(error.toString(),'Error: Initial transaction id is not defined','Chain tests: transaction id is required when initializing'); } + + var client3 = new Client(); + var test_chain3 = new Chain('someTestChain3', client3); + test_chain3.addOrderer(new Orderer('grpc://somehost.com:1234')); + return test_chain3.initializeChain(); } - ); - var client3 = new Client(); - var test_chain3 = new Chain('someTestChain3', client3); - test_chain3.addOrderer(new Orderer('grpc://somehost.com:1234')); - test_chain3.initializeChain().then(function(response){ - t.fail('Chain tests: no user defined should, throw error, response '+response); - },function(error){ - if (error && error.message && error.message === 'no user defined') - t.pass('Chain tests: no user defined, should throw error'); - else t.fail('Chain tests: no user defined, should have thrown error "no user defined"'); - }); + ).then( + function(response){ + t.fail('Chain tests: no user defined should, throw error, response '+response); + t.end(); + },function(error){ + if (error && error.message && error.message === 'no user defined') + t.pass('Chain tests: no user defined, should throw error'); + else t.fail('Chain tests: no user defined, should have thrown error "no user defined"'); - t.end(); + t.end(); + } + ); }); test('\n\n ** Chain query tests', function(t) { @@ -471,11 +478,12 @@ test('\n\n** Chain packageChaincode tests **\n\n', function(t) { var checkPath = path.join(destDir, 'src', 'github.com', 'example_cc'); t.equal(fs.existsSync(checkPath), true, 'The tar.gz file produced by Chain.packageChaincode() has the "src/github.com/example_cc" folder'); }); + + t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); + t.end(); }); - - t.end(); }); test('\n\n ** Chain sendInstallProposal() tests **\n\n', function (t) { @@ -602,19 +610,17 @@ test('\n\n ** Chain sendInstallProposal() tests **\n\n', function (t) { }); Promise.all([p1, p1a, p3, p4, p6, p7]) - .then( + .then( function (data) { t.end(); } - ).catch( + ).catch( function (err) { t.fail('Chain sendInstallProposal() tests, Promise.all: '); console.log(err.stack ? err.stack : err); t.end(); } - ); - - t.end(); + ); }); test('\n\n ** Chain sendDeploymentProposal() tests **\n\n', function (t) { @@ -771,18 +777,16 @@ test('\n\n ** Chain sendDeploymentProposal() tests **\n\n', function (t) { }); Promise.all([p1, p1a, p2, p3, p4, p6, p7]) - .then( + .then( function (data) { t.end(); } - ).catch( + ).catch( function (err) { t.fail('Chain sendDeploymentProposal() tests, Promise.all: '+err.stack ? err.stack : err); t.end(); } - ); - - t.end(); + ); }); test('\n\n ** Chain sendTransactionProposal() tests **\n\n', function (t) { @@ -902,18 +906,16 @@ test('\n\n ** Chain sendTransactionProposal() tests **\n\n', function (t) { }); Promise.all([p1, p2, p3, p4, p5, p6, p7]) - .then( + .then( function (data) { t.end(); } - ).catch( + ).catch( function (err) { t.fail('Chain sendTransactionProposal() tests, Promise.all: '+err.stack ? err.stack : err); t.end(); } - ); - - t.end(); + ); }); test('\n\n ** Client queryByChaincode() tests **\n\n', function (t) { @@ -1033,19 +1035,17 @@ test('\n\n ** Client queryByChaincode() tests **\n\n', function (t) { }); Promise.all([p1, p2, p3, p4, p5, p6, p7]) - .then( + .then( function (data) { t.end(); } - ).catch( + ).catch( function (err) { t.fail('Client queryByChaincode() tests, Promise.all: '); console.log(err.stack ? err.stack : err); t.end(); } - ); - - t.end(); + ); }); test('\n\n ** Chain sendTransaction() tests **\n\n', function (t) { @@ -1107,18 +1107,16 @@ test('\n\n ** Chain sendTransaction() tests **\n\n', function (t) { }); Promise.all([p1, p2, p3, p4]) - .then( + .then( function (data) { t.end(); } - ).catch( + ).catch( function (err) { t.fail('Chain sendTransaction() tests, Promise.all: '+err.stack ? err.stack : err); t.end(); } - ); - - t.end(); + ); }); // @@ -1161,14 +1159,13 @@ test('\n\n** TEST ** orderer via chain setOrderer/getOrderer', function(t) { var orderers = chain.getOrderers(); if(orderers !== null && orderers.length > 0 && orderers[1].getUrl() === 'grpc://localhost:5152') { t.pass('Successfully retrieved the upated orderer URL from the chain'); - t.end(); } else { t.fail('Failed to retieve the updated orderer URL from the chain'); - t.end(); } - } - catch(err2) { + + t.end(); + } catch(err2) { t.fail('Failed to update the order URL ' + err2); t.end(); } diff --git a/test/unit/client.js b/test/unit/client.js index 53058d64f4..cf28419c0b 100644 --- a/test/unit/client.js +++ b/test/unit/client.js @@ -64,102 +64,100 @@ test('\n\n ** lib/Client.js **\n\n', function (t) { if (response === null) t.pass('Client tests: getUserContext successful null user name.'); else t.fail('Client tests: getUserContext failed null name check'); + + return client.saveUserToStateStore(); }, function(error){ t.fail('Client tests: Unexpected error, getUserContext null name check. ' + error); - }); - - client.saveUserToStateStore() - .then(function(response){ + t.end(); + }).then(function(response){ t.fail('Client tests: got response, but should throw "Cannot save user to state store when userContext is null."'); + t.end(); }, function(error){ if (error.message === 'Cannot save user to state store when userContext is null.') t.pass('Client tests: Should throw "Cannot save user to state store when userContext is null."'); else t.fail('Client tests: Unexpected error message thrown, should throw "Cannot save user to state store when userContext is null." ' + error); - }); - client.setUserContext(null) - .then(function(response){ + return client.setUserContext(null); + }).then(function(response){ t.fail('Client tests: got response, but should throw "Cannot save null userContext."'); + t.end(); }, function(error){ if (error.message === 'Cannot save null userContext.') t.pass('Client tests: Should throw "Cannot save null userContext."'); else t.fail('Client tests: Unexpected error message thrown, should throw "Cannot save null userContext." ' + error); - }); - client.getUserContext('someUser') - .then(function(response){ + return client.getUserContext('someUser'); + }).then(function(response){ if (response == null) t.pass('Client tests: getUserContext with no context in memory or persisted returns null'); else t.fail('Client tests: getUserContext with no context in memory or persisted did not return null'); + + return client.setUserContext(new User('someUser'), true); }, function(error){ t.fail('Client tests: getUserContext with no context in memory or persisted did not returned error. ' + error); - }); - - client.setUserContext(new User('someUser'), true) - .then(function(response){ + t.end(); + }).then(function(response){ if (response && response.getName() === 'someUser') { t.pass('Client tests: successfully setUserContext with skipPersistence.'); return response; } else t.fail('Client tests: failed name check after setUserContext with skipPersistence.'); + + return client.getUserContext('someUser'); }, function(error){ t.fail('Client tests: Unexpected error, failed setUserContext with skipPersistence. ' + error); - }) - .then(function(response){ - client.getUserContext('someUser') - .then(function(response){ - if (response && response.getName() === 'someUser') - t.pass('Client tests: getUserContext not persisted/skipPersistence was successful.'); - else t.fail('Client tests: getUserContext not persisted/skipPersistence was not successful.'); - }, function(error){ - t.fail('Client tests: Unexpected error, getUserContext not persisted/skipPersistence. ' + error); - }); - }); - - client.setUserContext(new User('someUser')) - .then(function(result){ + t.end(); + }).then(function(response){ + if (response && response.getName() === 'someUser') + t.pass('Client tests: getUserContext not persisted/skipPersistence was successful.'); + else t.fail('Client tests: getUserContext not persisted/skipPersistence was not successful.'); + + return client.setUserContext(new User('someUser')); + }, function(error){ + t.fail('Client tests: Unexpected error, getUserContext not persisted/skipPersistence. ' + error); + t.end(); + }).then(function(result){ t.fail('Client tests: setUserContext without skipPersistence and no stateStore should not return result.'); - }, - function(error){ + t.end(); + }, function(error){ if (error.message === 'Cannot save user to state store when stateStore is null.') t.pass('Client tests: Should throw "Cannot save user to state store when stateStore is null"'); else t.fail('Client tests: Unexpected error message thrown, should throw "Cannot save user to state store when stateStore is null." ' + error); - }); - - var chain = client.newChain('someChain'); - t.equals(chain.getName(), 'someChain', 'Checking chain names match'); - t.throws( - function () { - client.newChain('someChain'); - }, - /^Error: Chain someChain already exist/, - 'Client tests: checking that chain already exists.'); - - t.doesNotThrow( - function() { - client.getChain('someChain'); - }, - null, - 'Client tests: getChain()'); - t.throws( + var chain = client.newChain('someChain'); + t.equals(chain.getName(), 'someChain', 'Checking chain names match'); + t.throws( function () { - client.getChain('someOtherChain'); + client.newChain('someChain'); }, - /^Error: Chain not found for name someOtherChain./, - 'Client tests: Should throw Error: Chain not found for name someOtherChain.'); + /^Error: Chain someChain already exist/, + 'Client tests: checking that chain already exists.'); - t.throws( - function() { - client.setStateStore({}); - }, - /The "keyValueStore" parameter must be an object that implements the following methods, which are missing:/, - 'Client tests: checking state store parameter implementing required functions'); + t.doesNotThrow( + function() { + client.getChain('someChain'); + }, + null, + 'Client tests: getChain()'); + + t.throws( + function () { + client.getChain('someOtherChain'); + }, + /^Error: Chain not found for name someOtherChain./, + 'Client tests: Should throw Error: Chain not found for name someOtherChain.'); + + t.throws( + function() { + client.setStateStore({}); + }, + /The "keyValueStore" parameter must be an object that implements the following methods, which are missing:/, + 'Client tests: checking state store parameter implementing required functions'); - testutil.cleanupDir(chainKeyValStorePath); + testutil.cleanupDir(chainKeyValStorePath); - Client.newDefaultKeyValueStore({ path: chainKeyValStorePath }) - .then ( + return Client.newDefaultKeyValueStore({ path: chainKeyValStorePath }); + }).then ( function (kvs) { client.setStateStore(kvs); @@ -170,26 +168,25 @@ test('\n\n ** lib/Client.js **\n\n', function (t) { t.fail('Client setKeyValueStore test: Failed to create new directory: ' + chainKeyValStorePath); var store = client.getStateStore(); - store.setValue('testKey', 'testValue') - .then( - function (result) { - t.pass('Client getStateStore test: Successfully set value, result: ' + result); - - var exists = testutil.existsSync(chainKeyValStorePath, testKey); - if (exists) - t.pass('Client getStateStore test: Verified the file for key ' + testKey + ' does exist'); - else - t.fail('Client getStateStore test: Failed to create file for key ' + testKey); - - t.end(); - } - ).catch( - function (reason) { - t.fail('Client getStateStore test: Failed to set value, reason: ' + reason); - t.end(); - } - ); - }); + return store.setValue('testKey', 'testValue'); + }).then( + function (result) { + t.pass('Client getStateStore test: Successfully set value, result: ' + result); + + var exists = testutil.existsSync(chainKeyValStorePath, testKey); + if (exists) + t.pass('Client getStateStore test: Verified the file for key ' + testKey + ' does exist'); + else + t.fail('Client getStateStore test: Failed to create file for key ' + testKey); + + t.end(); + } + ).catch( + function (reason) { + t.fail('Client getStateStore test: Failed to set value, reason: ' + reason); + t.end(); + } + ); }); /* diff --git a/test/unit/couchdb-key-value-store.js b/test/unit/couchdb-key-value-store.js new file mode 100644 index 0000000000..f4a004eb37 --- /dev/null +++ b/test/unit/couchdb-key-value-store.js @@ -0,0 +1,90 @@ +/** + * Copyright 2017 IBM All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +var tape = require('tape'); +var _test = require('tape-promise'); +var test = _test(tape); +var CouchdbMock = require('mock-couch'); + +var CDBKVS = require('fabric-client/lib/impl/CouchDBKeyValueStore.js'); + +test('\n\n** CouchDBKeyValueStore tests', (t) => { + t.throws( + () => { + new CDBKVS(); + }, + /Must provide the CouchDB database url to store membership data/, + 'Error checking in the constructor: missing opts' + ); + + t.throws( + () => { + new CDBKVS({dummy: 'value'}); + }, + /Must provide the CouchDB database url to store membership data/, + 'Error checking in the constructor: opts object missing required "url"' + ); + + var store; + + new CDBKVS({url: 'http://dummyUrl'}) + .then(() => { + t.fail('Should not have been able to successfully constructed a store from an invalid URL'); + t.end(); + }).catch((err) => { + if (err.message && err.message.indexOf('Error: getaddrinfo ENOTFOUND dummyurl') > 0) { + t.pass('Successfully rejected the construction request due to invalid URL'); + } else { + t.fail('Store construction failed for unknown reason: ' + err.stack ? err.stack : err); + } + + var couchdb = CouchdbMock.createServer(); + couchdb.listen(5985); + + // override t.end function so it'll always disconnect the event hub + t.end = ((context, mockdb, f) => { + return function() { + if (mockdb) { + console.log('Disconnecting the mock couchdb server'); + mockdb.close(); + } + + f.apply(context, arguments); + }; + })(t, couchdb, t.end); + + return new CDBKVS({url: 'http://localhost:5985'}); + }).then((st) => { + store = st; + t.pass('Successfully connected the key value store to couchdb at localhost:5985'); + + t.notEqual(store._database, undefined, 'Check "_database" value of the constructed store object'); + + return store.setValue('someKey', 'someValue'); + }).then((value) => { + t.equal(value, 'someValue', 'Check result of setValue()'); + + return store.getValue('someKey'); + }).then((value) => { + t.equal(value, 'someValue', 'Check result of getValue()'); + t.end(); + }).catch((err) => { + t.fail(err.stack ? err.stack : err); + t.end(); + }); +}); \ No newline at end of file diff --git a/test/unit/crypto-key-store.js b/test/unit/crypto-key-store.js index a8e6413031..9d7d31f1aa 100644 --- a/test/unit/crypto-key-store.js +++ b/test/unit/crypto-key-store.js @@ -26,11 +26,14 @@ var fs = require('fs-extra'); var path = require('path'); var jsrsa = require('jsrsasign'); var KEYUTIL = jsrsa.KEYUTIL; +var CouchdbMock = require('mock-couch'); +var nano = require('nano'); testutil.resetDefaults(); var ecdsaKey = require('fabric-client/lib/impl/ecdsa/key.js'); var CKS = require('fabric-client/lib/impl/CryptoKeyStore.js'); +var CouchDBKeyValueStore = require('fabric-client/lib/impl/CouchDBKeyValueStore.js'); var TEST_KEY_PRIVATE_PEM = '-----BEGIN PRIVATE KEY-----' + 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZYMvf3w5VkzzsTQY' + @@ -52,6 +55,14 @@ var TEST_KEY_PRIVATE_CERT_PEM = '-----BEGIN CERTIFICATE-----' + 'BAHpeA==' + '-----END CERTIFICATE-----'; +var dbname = 'test_keystore'; +var dbclient = nano('http://localhost:5985'); + +var f1 = KEYUTIL.getKey(TEST_KEY_PRIVATE_PEM); +var testPrivKey = new ecdsaKey(f1); +var f2 = KEYUTIL.getKey(TEST_KEY_PRIVATE_CERT_PEM); +var testPubKey = new ecdsaKey(f2); + test('\n\n** CryptoKeyStore tests **\n\n', function(t) { t.throws( () => { @@ -69,11 +80,6 @@ test('\n\n** CryptoKeyStore tests **\n\n', function(t) { 'Test invalid constructor calls: missing "path" property in the "options" parameter' ); - var f1 = KEYUTIL.getKey(TEST_KEY_PRIVATE_PEM); - var testPrivKey = new ecdsaKey(f1); - var f2 = KEYUTIL.getKey(TEST_KEY_PRIVATE_CERT_PEM); - var testPubKey = new ecdsaKey(f2); - var store; CKS({path: '/tmp/hfc-cks'}) .then((st) => { @@ -106,9 +112,124 @@ test('\n\n** CryptoKeyStore tests **\n\n', function(t) { }).then((recoveredKey) => { t.notEqual(recoveredKey, null, 'Successfully read public key from store using SKI'); t.equal(recoveredKey.isPrivate(), false, 'Test if the recovered key is a public key'); + t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); + t.end(); }); +}); + + +test('\n\n** CryptoKeyStore tests - couchdb based store tests - use configSetting **\n\n', function(t) { + utils.setConfigSetting('key-value-store', 'fabric-client/lib/impl/CouchDBKeyValueStore.js'); + + var couchdb = CouchdbMock.createServer(); + couchdb.listen(5985); + + // override t.end function so it'll always disconnect the event hub + t.end = ((context, mockdb, f) => { + return function() { + if (mockdb) { + console.log('Disconnecting the mock couchdb server'); + mockdb.close(); + } + + f.apply(context, arguments); + }; + })(t, couchdb, t.end); - t.end(); -}); \ No newline at end of file + CKS({name: dbname, url: 'http://localhost:5985'}) + .then((store) => { + return testKeyStore(store, t); + }).catch((err) => { + t.fail(err.stack ? err.stack : err); + t.end(); + }).then(() => { + t.end(); + }); +}); + +test('\n\n** CryptoKeyStore tests - couchdb based store tests - use constructor argument **\n\n', function(t) { + var couchdb = CouchdbMock.createServer(); + couchdb.listen(5985); + + // override t.end function so it'll always disconnect the event hub + t.end = ((context, mockdb, f) => { + return function() { + if (mockdb) { + console.log('Disconnecting the mock couchdb server'); + mockdb.close(); + } + + f.apply(context, arguments); + }; + })(t, couchdb, t.end); + + CKS(CouchDBKeyValueStore, {name: dbname, url: 'http://localhost:5985'}) + .then((store) => { + return testKeyStore(store, t); + }).catch((err) => { + t.fail(err.stack ? err.stack : err); + t.end(); + }).then(() => { + t.end(); + }); +}); + +function testKeyStore(store, t) { + var docRev; + + return store.putKey(testPrivKey) + .then((keyPEM) => { + t.pass('Successfully saved private key in store based on couchdb'); + + return new Promise((resolve, reject) => { + dbclient.use(dbname).get(testPrivKey.getSKI() + '-priv', function(err, body) { + if (!err) { + t.pass('Successfully verified private key persisted in couchdb'); + docRev = body._rev; + return resolve(store.getKey(testPrivKey.getSKI())); + } else { + t.fail('Failed to persist private key in couchdb. ' + err.stack ? err.stack : err); + t.end(); + } + }); + }); + }).then((recoveredKey) => { + t.notEqual(recoveredKey, null, 'Successfully read private key from store using SKI'); + t.equal(recoveredKey.isPrivate(), true, 'Test if the recovered key is a private key'); + + return store.putKey(testPubKey); + }).then((keyPEM) => { + return new Promise((resolve, reject) => { + dbclient.use(dbname).get(testPrivKey.getSKI() + '-pub', function(err, body) { + if (!err) { + t.pass('Successfully verified public key persisted in couchdb'); + return resolve(store.getKey(testPubKey.getSKI())); + } else { + t.fail('Failed to persist public key in couchdb. ' + err.stack ? err.stack : err); + t.end(); + } + }); + }); + }).then((recoveredKey) => { + t.notEqual(recoveredKey, null, 'Successfully read public key from store using SKI'); + t.equal(recoveredKey.isPrivate(), true, 'Test if the recovered key is a private key'); + + // delete the private key entry and test if getKey() would return the public key + return new Promise((resolve, reject) => { + dbclient.use(dbname).destroy(testPrivKey.getSKI() + '-priv', docRev, function(err, body) { + if (!err) { + t.comment('Successfully deleted entry for private key'); + return resolve(store.getKey(testPubKey.getSKI())); + } else { + t.fail('Failed to delete private key in couchdb. ' + err.stack ? err.stack : err); + t.end(); + } + }); + }); + }).then((recoveredKey) => { + t.notEqual(recoveredKey, null, 'Successfully read public key from store using SKI'); + t.equal(recoveredKey.isPrivate(), false, 'Test if the recovered key is a public key'); + }); +} diff --git a/test/unit/cryptosuite-ecdsa-aes.js b/test/unit/cryptosuite-ecdsa-aes.js index 8f52200143..cb607688c3 100644 --- a/test/unit/cryptosuite-ecdsa-aes.js +++ b/test/unit/cryptosuite-ecdsa-aes.js @@ -25,13 +25,14 @@ var testutil = require('./util.js'); var utils = require('fabric-client/lib/utils.js'); var path = require('path'); var fs = require('fs-extra'); - -testutil.resetDefaults(); +var util = require('util'); +var os = require('os'); var jsrsa = require('jsrsasign'); var KEYUTIL = jsrsa.KEYUTIL; var ECDSA = jsrsa.ECDSA; +var CouchDBKeyValueStore = require('fabric-client/lib/impl/CouchDBKeyValueStore.js'); var CryptoSuite_ECDSA_AES = require('fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js'); var ecdsaKey = require('fabric-client/lib/impl/ecdsa/key.js'); var api = require('fabric-client/lib/api.js'); @@ -132,20 +133,31 @@ const halfOrdersForCurve = { var _client = new hfc(); test('\n\n** utils.getCryptoSuite tests **\n\n', (t) => { - var cs = utils.getCryptoSuite({keysize: 384, algorithm: 'EC'}, keyValStorePath); + testutil.resetDefaults(); + + let config = { path: keyValStorePath }; + + let cs = utils.getCryptoSuite({keysize: 384, algorithm: 'EC'}, config); t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); t.equal(cs._keySize, 384, 'Returned instance should have keysize of 384'); - t.equal(cs._storePath, keyValStorePath, 'Returned instance should have store path of ' + keyValStorePath); + t.equal(cs._storeConfig.opts, config, util.format('Returned instance should have store config opts of %j', config)); + t.equal(typeof cs._storeConfig.superClass, 'function', 'Returned instance should have store config superClass'); - cs = utils.getCryptoSuite({keysize: 384, algorithm: 'EC'}, keyValStorePath); + cs = utils.getCryptoSuite({keysize: 384}, config); t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Default test: should return an instance of CryptoSuite_ECDSA_AES'); t.equal(cs._keySize, 384, 'Returned instance should have keysize of 384'); - t.equal(cs._storePath, keyValStorePath, 'Returned instance should have store path of ' + keyValStorePath); + t.equal(cs._storeConfig.opts, config, util.format('Returned instance should have store config opts of %j', config)); + + cs = utils.getCryptoSuite({algorithm: 'EC'}, config); + t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); + t.equal(cs._keySize, 256, 'Returned instance should have keysize of 256'); + t.equal(cs._storeConfig.opts, config, util.format('Returned instance should have store config opts of %j', config)); - cs = utils.getCryptoSuite({algorithm: 'EC'}, keyValStorePath); + let defaultKVSPath = path.join(os.homedir(), '.hfc-key-store'); + cs = utils.getCryptoSuite({algorithm: 'EC'}); t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); t.equal(cs._keySize, 256, 'Returned instance should have keysize of 256'); - t.equal(cs._storePath, keyValStorePath, 'Returned instance should have store path of ' + keyValStorePath); + t.equal(cs._storeConfig.opts.path, defaultKVSPath, util.format('Returned instance should have store config opts.path of %s', defaultKVSPath)); // each app instance is expected to use either HSM or software-based key management, as such this question // is answered with a config setting rather than controlled on a case-by-case basis @@ -159,57 +171,77 @@ test('\n\n** utils.getCryptoSuite tests **\n\n', (t) => { ); utils.setConfigSetting('crypto-hsm', false); - t.throws( + t.doesNotThrow( () => { cs = utils.getCryptoSuite({lib: '/usr/local/lib', slot: 0, pin: '1234' }); + cs._getKeyStore() + .then((store) => { + t.fail('Should not have been able to get a valid key store because of invalid store config'); + t.end(); + }).catch((err) => { + t.pass('Successfully rejected _getKeyStore() due to invalid config'); + t.end(); + }); }, - /^Error: The "kvsPath" parameter for this constructor, if specified, must be a string specifying a file system path/, - 'Should attempt to load the CryptoSuite_ECDSA_AES module and fail because of the invalid file store path' + null, + 'Load the CryptoSuite_ECDSA_AES module and pass in an invalid config object' ); - - t.end(); }); test('\n\n ** CryptoSuite_ECDSA_AES - constructor tests **\n\n', function (t) { cleanupFileKeyValueStore(keyValStorePath); - var keyValueStorePromise = utils.newKeyValueStore({ path: getRelativePath(keyValStorePath) }); - - t.throws( - function() { - utils.getCryptoSuite(keyValueStorePromise); - }, - /^Error: The "kvsPath" parameter for this constructor, if specified, must be a string specifying a file system path/, - 'CryptoSuite_ECDSA_AES constructor tests: opts passed as a promise should throw error' - ); var keyValueStore = null; - var cs5; - t.doesNotThrow( - function () { - cs5 = utils.getCryptoSuite(keyValStorePath); - }, - null, - 'CryptoSuite_ECDSA_AES constructor tests: pass in a string as kvs path' - ); + let cs; - cs5._getKeyStore() - .then((store) => { + cs = new CryptoSuite_ECDSA_AES(256, CouchDBKeyValueStore, { name: 'test_db', url: 'http://dummyUrl'}); + cs._getKeyStore() + .then(() => { + t.fail('Should not have been able to get a valid key store because the url was invalid'); + }).catch((err) => { + if (err.message.indexOf('Error creating test_db database to store membership data: Error: getaddrinfo ENOTFOUND dummyurl') >= 0) { + t.pass('Successfully rejected _getKeyStore() because the url was invalid'); + } else { + t.fail(err); + } + + t.doesNotThrow( + () => { + cs = utils.getCryptoSuite(keyValStorePath); + }, + null, + 'CryptoSuite_ECDSA_AES constructor tests: pass in a string as kvs path' + ); + + return cs._getKeyStore(); + }).then(() => { + t.fail('Should not have been able to obtain a proper key store due to invalid config'); + }).catch(() => { + t.pass('Successfully rejected attempt to obtain a proper key store'); + + utils.setConfigSetting('key-value-store', 'fabric-client/lib/impl/FileKeyValueStore.js'); + + let cs1 = utils.getCryptoSuite({ + path: keyValStorePath + }); + + return cs1._getKeyStore(); + }).then((store) => { t.notEqual(store, null, 'Crypto Key Store successfully initialized by CryptoSuite_ECDSA_AES'); t.equal(typeof store.getKey, 'function', 'Crypto key store much have the "getKey()" function'); t.equal(typeof store.putKey, 'function', 'Crypto key store much have the "putKey()" function'); - }); - var cs = new CryptoSuite_ECDSA_AES(256, keyValStorePath); - cs._getKeyStore() - .then((store) => { + let cs2 = new CryptoSuite_ECDSA_AES(256, {path: keyValStorePath}); + return cs2._getKeyStore(); + }).then((store) => { t.notEqual(store, null, 'Crypto Key Store successfully initialized by CryptoSuite_ECDSA_AES'); t.equal(typeof store.getKey, 'function', 'Crypto key store much have the "getKey()" function'); t.equal(typeof store.putKey, 'function', 'Crypto key store much have the "putKey()" function'); + t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); + t.end(); }); - - t.end(); }); test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) { @@ -405,59 +437,51 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) { testVerify(TEST_LONG_MSG_SIGNATURE_SHA2_256, TEST_LONG_MSG, false); // test importKey() - cryptoUtils.importKey(TEST_CERT_PEM) - .then((pubKey) => { - t.equal(pubKey.isPrivate(), false, 'Test imported public key isPrivate()'); - t.equal(pubKey.getSKI(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef', 'Test imported public key SKI'); - - // verify that the pub key has been saved in the key store by the proper key - t.equal( - fs.existsSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef-pub')), - true, - 'Check that the imported public key has been saved in the key store'); - }).catch((err) => { - t.fail(err.stack ? err.stack : err); - }); - - cryptoUtils.importKey(TEST_KEY_PRIVATE_PEM) - .then((privKey) => { - t.equal(privKey.isPrivate(), true, 'Test imported private key isPrivate'); - t.equal(privKey.getSKI(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a', 'Test imported private key SKI'); - t.end(); - - // verify that the imported private key has been saved in the key store by the proper key - t.equal( - fs.existsSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')), - true, - 'Check that the imported private key has been saved in the key store'); - - // verify that the imported key can properly sign messages - var testSig = cryptoUtils.sign(privKey, cryptoUtils.hash(TEST_MSG)); - t.equal( - cryptoUtils.verify(privKey.getPublicKey(), testSig, TEST_MSG), - true, - 'Check that the imported private key can properly sign messages'); - - // manufacture an error condition where the private key does not exist for the SKI, and only the public key does - return cryptoUtils.importKey(TEST_KEY_PRIVATE_CERT_PEM); - }).then((pubKey) => { - fs.removeSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')); - - var poorUser = new User('admin2', _client); - poorUser.fromString(JSON.stringify(TEST_USER_ENROLLMENT)) - .then(() => { - t.fail('Failed to catch missing private key expected from a user enrollment object'); - }).catch((err) => { - t.pass('Successfully caught missing private key expected from a user enrollment object'); - }); - }).catch((err) => { - t.fail(err.stack ? err.stack : err); - }); + return cryptoUtils.importKey(TEST_CERT_PEM); + }).then((pubKey) => { + t.equal(pubKey.isPrivate(), false, 'Test imported public key isPrivate()'); + t.equal(pubKey.getSKI(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef', 'Test imported public key SKI'); + + // verify that the pub key has been saved in the key store by the proper key + t.equal( + fs.existsSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef-pub')), + true, + 'Check that the imported public key has been saved in the key store'); + + return cryptoUtils.importKey(TEST_KEY_PRIVATE_PEM); + }).then((privKey) => { + t.equal(privKey.isPrivate(), true, 'Test imported private key isPrivate'); + t.equal(privKey.getSKI(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a', 'Test imported private key SKI'); + t.end(); + // verify that the imported private key has been saved in the key store by the proper key + t.equal( + fs.existsSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')), + true, + 'Check that the imported private key has been saved in the key store'); + + // verify that the imported key can properly sign messages + var testSig = cryptoUtils.sign(privKey, cryptoUtils.hash(TEST_MSG)); + t.equal( + cryptoUtils.verify(privKey.getPublicKey(), testSig, TEST_MSG), + true, + 'Check that the imported private key can properly sign messages'); + + // manufacture an error condition where the private key does not exist for the SKI, and only the public key does + return cryptoUtils.importKey(TEST_KEY_PRIVATE_CERT_PEM); + }).then((pubKey) => { + fs.removeSync(path.join(CryptoSuite_ECDSA_AES.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')); + + var poorUser = new User('admin2', _client); + return poorUser.fromString(JSON.stringify(TEST_USER_ENROLLMENT)); + }).then(() => { + t.fail('Failed to catch missing private key expected from a user enrollment object'); t.end(); - }) - .catch(function (err) { - t.fail('Unexpected error: ' + err.stack ? err.stack : err); + },(err) => { + t.pass('Successfully caught missing private key expected from a user enrollment object'); + t.end(); + }).catch((err) => { + t.fail(err.stack ? err.stack : err); t.end(); }); }); diff --git a/test/unit/fabric-ca-client.js b/test/unit/fabric-ca-client.js index 1af0808a0f..e7f01a5255 100644 --- a/test/unit/fabric-ca-client.js +++ b/test/unit/fabric-ca-client.js @@ -220,18 +220,20 @@ test('FabricCAClient: Test enroll with missing parameters', function (t) { port: 7054 }); - // - return client.enroll() - .then(function (csr) { - t.fail('Enrollment must fail when missing required parameters'); - }) - .catch(function (err) { - if (err.message.startsWith('Missing required parameters')) { - t.pass('Enrollment should fail when missing required parameters'); - } else { - t.fail('Enrollment should have failed with \'Missing required parameters\''); - } - }); + client.enroll() + .then(function (csr) { + t.fail('Enrollment must fail when missing required parameters'); + t.end(); + }) + .catch(function (err) { + if (err.message.startsWith('Missing required parameters')) { + t.pass('Enrollment should fail when missing required parameters'); + } else { + t.fail('Enrollment should have failed with \'Missing required parameters\''); + } + + t.end(); + }); }); /** @@ -245,15 +247,18 @@ test('FabricCAClient: Test register with missing parameters', function (t) { port: 7054 }); - return client.register() - .then(function (token) { - t.fail('Register must fail when missing required parameters'); - }) - .catch(function (err) { - if (err.message.startsWith('Missing required parameters')) { - t.pass('Register should fail when missing required parameters'); - } else { - t.fail('Register should have failed with \'Missing required parameters\''); - } - }); + client.register() + .then(function (token) { + t.fail('Register must fail when missing required parameters'); + t.end(); + }) + .catch(function (err) { + if (err.message.startsWith('Missing required parameters')) { + t.pass('Register should fail when missing required parameters'); + } else { + t.fail('Register should have failed with \'Missing required parameters\''); + } + + t.end(); + }); }); \ No newline at end of file diff --git a/test/unit/file-key-value-store.js b/test/unit/file-key-value-store.js index 40140fc21a..edd66164db 100644 --- a/test/unit/file-key-value-store.js +++ b/test/unit/file-key-value-store.js @@ -141,13 +141,15 @@ test('\n\n ** FileKeyValueStore - constructor setValue getValue test store1 **\n t.fail('FileKeyValueStore read and write test store1: get value ' + val + ' does not equal testValue of ' + testValue); else t.pass('FileKeyValueStore read and write test store1: Successfully retrieved value'); + + t.end(); } ).catch ( - function(err) { - t.fail('FileKeyValueStore store1 setValue test store1, caught err: ' + err); - } - ); - t.end(); + function(err) { + t.fail('FileKeyValueStore store1 setValue test store1, caught err: ' + err); + t.end(); + } + ); }); test('\n\n ** FileKeyValueStore - constructor setValue getValue test store2 **\n\n', function (t) { @@ -245,18 +247,14 @@ test('\n\n** FileKeyValueStore error check tests **\n\n', function (t) { } else { t.fail('FileKeyValueStore error check tests: Delete store & getValue test. getValue successfully retrieved value: ' + val); } + + cleanupFileKeyValueStore(keyValStorePath4); + return new FileKeyValueStore({ path: getRelativePath(keyValStorePath4) }); }, function (reason) { t.fail('FileKeyValueStore error check tests: Delete store & getValue test. getValue caught unexpected error: ' + reason); - }) - .catch( - function (err) { - t.fail('Failed with unexpected error: ' + err.stack ? err.stack : err); - t.end(); - }); - - cleanupFileKeyValueStore(keyValStorePath4); - var promise4 = new FileKeyValueStore({ path: getRelativePath(keyValStorePath4) }) + } + ) .then( function (store) { store4 = store; diff --git a/test/unit/identity.js b/test/unit/identity.js index b0598a7f1d..9bb748ee8f 100644 --- a/test/unit/identity.js +++ b/test/unit/identity.js @@ -233,9 +233,9 @@ test('\n\n ** Identity class tests **\n\n', function (t) { var sig = signingID.sign(TEST_MSG); t.equal(cryptoUtils.verify(pubKey, sig, TEST_MSG), true, 'Test SigningIdentity sign() method'); t.equal(signingID.verify(TEST_MSG, sig), true, 'Test Identity verify() method'); + t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); + t.end(); }); - - t.end(); }); \ No newline at end of file diff --git a/test/unit/user.js b/test/unit/user.js index e40e253416..43977a1928 100644 --- a/test/unit/user.js +++ b/test/unit/user.js @@ -118,19 +118,14 @@ test('\n\n ** User - constructor set get tests **\n\n', function (t) { cryptoUtils.generateKey() .then(function (key) { // the private key and cert don't match, but it's ok, the code doesn't check - member2.setEnrollment(key, TEST_CERT_PEM) - .then(() => { - var id = member2.getIdentity(); + return member2.setEnrollment(key, TEST_CERT_PEM); + }).then(() => { + var id = member2.getIdentity(); - t.equal(id._publicKey._key.pubKeyHex, '0452a75e1ee105da7ab3d389fda69d8a04f5cf65b305b49cec7cdbdeb91a585cf87bef5a96aa9683d96bbabfe60d8cc6f5db9d0bc8c58d56bb28887ed81c6005ac', 'User class setEnrollment() test'); - t.end(); - }); - - // TODO: test SigningIdentity + t.equal(id._publicKey._key.pubKeyHex, '0452a75e1ee105da7ab3d389fda69d8a04f5cf65b305b49cec7cdbdeb91a585cf87bef5a96aa9683d96bbabfe60d8cc6f5db9d0bc8c58d56bb28887ed81c6005ac', 'User class setEnrollment() test'); t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); + t.end(); }); - - t.end(); }); \ No newline at end of file