Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit 0b9981d

Browse files
jimthematrixGerrit Code Review
authored andcommitted
Merge "FAB-837 Add support and test for cloudant database"
2 parents f61aad3 + 707e9ba commit 0b9981d

File tree

7 files changed

+193
-25
lines changed

7 files changed

+193
-25
lines changed

build/tasks/doc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ gulp.task('doc', function () {
2323
'hfc/index.js',
2424
'hfc/lib/api.js',
2525
'hfc/lib/impl/FileKeyValueStore.js',
26+
'hfc/lib/impl/CouchDBKeyValueStore.js',
2627
'hfc/lib/impl/CryptoSuite_ECDSA_AES.js',
2728
'hfc/lib/impl/ecdsa/key.js',
2829
'hfc/lib/Chain.js',

hfc/lib/impl/CouchDBKeyValueStore.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var logger = utils.getLogger('CouchDBKeyValueStore.js');
2626

2727
/**
2828
* This is a sample database implementation of the [KeyValueStore]{@link module:api.KeyValueStore} API.
29-
* It uses a local CouchDB database instance to store the keys.
29+
* It uses a local or remote CouchDB database instance to store the keys.
3030
*
3131
* @class
3232
*/
@@ -35,22 +35,36 @@ var CouchDBKeyValueStore = class extends api.KeyValueStore {
3535
/**
3636
* constructor
3737
*
38-
* @param {Object} options contains two properties: 'path', which points to the CouchDB database instance
39-
* and 'name', which identifies the name of the database if different from the default of 'member_db'.
40-
* The 'name' parameter is optional.
38+
* @description <b>options</b> contains a path property which represents a CouchDB client instance.
39+
* The following code snippet shows how to create a nano minimalistic client for CouchDB. For more
40+
* information see <a href='https://github.com/dscape/nano'>github dscape / nano</a>.
41+
* <pre><code>var nano = require('nano');
42+
* var couchDBClient = nano(couchdb_IP_Address + ':' + couchdb_Port);</code></pre>
43+
*
44+
* <br>The following code snippet shows how to create a Cloudant CouchDB client.
45+
* Username and password map to the IBM Bluemix service credentials VCAP_SERVICES environment variables username and password.
46+
* To obtain an instance of Cloudant, see the IBM Bluemix Catalog --> Services --> Data & Analytics at
47+
* <a href='https://console.ng.bluemix.net/catalog/services/cloudant-nosql-db'>Cloudant NoSQL DB</a>.
48+
* <pre><code>var Cloudant = require('cloudant');
49+
* var cloudantClient = Cloudant({account: username, password: password});</code></pre>
50+
* <br>
51+
*
52+
* @param {Object} options Contains two properties:
53+
* <li>path - The CouchDB database client instance.
54+
* <li>name - Optional. Identifies the name of the database if different from the default of 'member_db'.
4155
*/
4256
constructor(options) {
43-
logger.debug('constructor, options: ' + JSON.stringify(options));
57+
logger.debug('constructor, options: ' + options);
4458

4559
if (!options || !options.path) {
46-
throw new Error('Must provide the path to the CouchDB database instance to store membership data.');
60+
throw new Error('Must provide the CouchDB database client instance to store membership data.');
4761
}
4862

4963
// Create the keyValStore instance
5064
super();
5165

5266
var self = this;
53-
// path pointer to the database
67+
// path is the database client instance
5468
this._path = options.path;
5569
// Name of the database, optional
5670
if (!options.name) {
@@ -64,7 +78,7 @@ var CouchDBKeyValueStore = class extends api.KeyValueStore {
6478

6579
return new Promise(function(resolve, reject) {
6680
// Initialize the CouchDB database client
67-
var dbClient = nano(options.path);
81+
var dbClient = self._path;
6882
// Check if the database already exists. If not, create it.
6983
dbClient.db.get(self._name, function(err, body) {
7084
// Check for error

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"devDependencies": {
1919
"bn.js": "^4.11.6",
2020
"bunyan": "^1.8.1",
21+
"cloudant": "^1.7.0",
2122
"elliptic": "^6.3.2",
2223
"gulp": "^3.9.1",
2324
"gulp-debug": "^3.0.0",

test/fixtures/cloudant.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cloudant-username" : "1421acc7-6faa-491a-8e10-951e2e190684-bluemix",
3+
"cloudant-password" : "7179ef7a72602189243deeabe207889bde1c2fada173ae1022b5592e5a79dacc",
4+
"key-value-store" : "./impl/CouchDBKeyValueStore.js"
5+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/**
2+
* Copyright 2016 IBM All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
var tape = require('tape');
18+
var _test = require('tape-promise');
19+
var test = _test(tape);
20+
21+
var hfc = require('hfc');
22+
var Client = hfc;
23+
var User = require('hfc/lib/User.js');
24+
var FabricCOPServices = require('hfc-cop/lib/FabricCOPImpl');
25+
26+
var utils = require('hfc/lib/utils.js');
27+
var couchdbUtil = require('./couchdb-util.js');
28+
29+
// Use the Cloudant specific config file
30+
hfc.addConfigFile('test/fixtures/cloudant.json');
31+
var dbClient = couchdbUtil.getCloudantClient();
32+
var keyValueStore = hfc.getConfigSetting('key-value-store');
33+
console.log('Key Value Store = ' + keyValueStore);
34+
35+
// This test first checks to see if a user has already been enrolled. If so,
36+
// the test terminates. If the user is not yet enrolled, the test uses the
37+
// FabricCOPImpl to enroll a user, and saves the enrollment materials into the
38+
// CouchDB KeyValueStore. Then the test uses the Chain class to load the member
39+
// from the key value store.
40+
test('Use FabricCOPServices wih a Cloudant CouchDB KeyValueStore', function(t) {
41+
42+
//var user = new User();
43+
var client = new Client();
44+
45+
// Set the relevant configuration values
46+
utils.setConfigSetting('crypto-keysize', 256);
47+
48+
// Clean up the couchdb test database
49+
var dbname = 'member_db';
50+
51+
//ccd next needs to be changed
52+
couchdbUtil.destroy(dbname, dbClient)
53+
.then( function(status) {
54+
t.comment('Cleanup of existing ' + dbname + ' returned '+status);
55+
t.comment('Initilize the CouchDB KeyValueStore');
56+
utils.newKeyValueStore({name: dbname, path: dbClient})
57+
.then(
58+
function(kvs) {
59+
t.comment('Setting client keyValueStore to: ' + kvs);
60+
client.setStateStore(kvs);
61+
if (client.getStateStore() === kvs) {
62+
t.pass('Successfully set CouchDB KeyValueStore for client');
63+
} else {
64+
t.pass('CouchDB KeyValStore is not set successfully on this client!');
65+
t.end();
66+
process.exit(1);
67+
}
68+
t.comment('Initialize the COP server connection and KeyValueStore');
69+
return new FabricCOPServices('http://localhost:8888', kvs);
70+
},
71+
function(err) {
72+
console.log(err);
73+
t.fail('Error initializing CouchDB KeyValueStore. Exiting.');
74+
t.end();
75+
process.exit(1);
76+
})
77+
.then(
78+
function(copService) {
79+
console.log('ADD: copService - ' + copService);
80+
t.pass('Successfully initialized the Fabric COP service.');
81+
82+
client.setCryptoSuite(copService.getCrypto());
83+
t.comment('Set cryptoSuite on client');
84+
t.comment('Begin copService.enroll');
85+
return copService.enroll({
86+
enrollmentID: 'admin2',
87+
enrollmentSecret: 'adminpw2'
88+
});
89+
},
90+
function(err) {
91+
t.fail('Failed to initilize the Fabric COP service: ' + err);
92+
t.end();
93+
}
94+
)
95+
.then(
96+
function(admin2) {
97+
t.pass('Successfully enrolled admin2 with COP server');
98+
99+
// Persist the user state
100+
var member = new User('admin2', client);
101+
member.setEnrollment(admin2.key, admin2.certificate);
102+
if (member.isEnrolled()) {
103+
t.pass('Member isEnrolled successfully.');
104+
} else {
105+
t.fail('Member isEnrolled failed.');
106+
}
107+
return client.setUserContext(member);
108+
},
109+
function(err) {
110+
t.fail('Failed to enroll admin2 with COP server. Error: ' + err);
111+
t.end();
112+
})
113+
.then(
114+
function(user) {
115+
return client.loadUserFromStateStore('admin2');
116+
}
117+
).then(
118+
function(user) {
119+
if (user && user.getName() === 'admin2') {
120+
t.pass('Successfully loaded the user from key value store');
121+
t.end();
122+
} else {
123+
t.fail('Failed to load the user from key value store');
124+
t.end();
125+
}
126+
},
127+
function(err) {
128+
t.fail('Failed to load the user admin2 from key value store. Error: ' + err);
129+
t.end();
130+
}
131+
).catch(
132+
function(err) {
133+
t.fail('Failed couchdb-fabriccop-test with error:' + err.stack ? err.stack : err);
134+
t.end();
135+
}
136+
);
137+
});
138+
});

test/unit/couchdb-fabriccop-tests.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,18 @@ var FabricCOPServices = require('hfc-cop/lib/FabricCOPImpl');
2626
var utils = require('hfc/lib/utils.js');
2727
var couchdbUtil = require('./couchdb-util.js');
2828

29-
// Add the CouchDB specific config file
29+
// Use the CouchDB specific config file
3030
hfc.addConfigFile('test/fixtures/couchdb.json');
31-
32-
// Record the CouchDB KeyValueStore location set by couchdb.json
31+
var dbClient = couchdbUtil.getCouchDBClient();
3332
var keyValueStore = hfc.getConfigSetting('key-value-store');
3433
console.log('Key Value Store = ' + keyValueStore);
3534

36-
var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound');
37-
var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound');
38-
39-
// Record the CouchDB KeyValueStorePath set by couchdb.json
40-
var keyValStorePath = couchdbIPAddr + ':' + couchdbPort;
41-
console.log('Key Value Store Path = ' + keyValStorePath);
42-
4335
// This test first checks to see if a user has already been enrolled. If so,
4436
// the test terminates. If the user is not yet enrolled, the test uses the
4537
// FabricCOPImpl to enroll a user, and saves the enrollment materials into the
4638
// CouchDB KeyValueStore. Then the test uses the Chain class to load the member
4739
// from the key value store.
48-
test('Use FabricCOPServices wih a CouchDB KeyValueStore', function(t) {
40+
test('Use FabricCOPServices with a CouchDB KeyValueStore', function(t) {
4941

5042
//var user = new User();
5143
var client = new Client();
@@ -55,14 +47,14 @@ test('Use FabricCOPServices wih a CouchDB KeyValueStore', function(t) {
5547

5648
// Clean up the couchdb test database
5749
var dbname = 'member_db';
58-
couchdbUtil.destroy(dbname, keyValStorePath)
50+
couchdbUtil.destroy(dbname, dbClient)
5951
.then( function(status) {
6052
t.comment('Cleanup of existing ' + dbname + ' returned '+status);
6153
t.comment('Initilize the CouchDB KeyValueStore');
62-
utils.newKeyValueStore({name: dbname, path: keyValStorePath})
54+
utils.newKeyValueStore({name: dbname, path: dbClient})
6355
.then(
6456
function(kvs) {
65-
t.comment('Setting client keyValueStore to: ' + JSON.stringify(kvs));
57+
t.comment('Setting client keyValueStore to: ' +kvs);
6658
client.setStateStore(kvs);
6759
if (client.getStateStore() === kvs) {
6860
t.pass('Successfully set CouchDB KeyValueStore for client');

test/unit/couchdb-util.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,26 @@
1414
* limitations under the License.
1515
*/
1616

17+
var hfc = require('hfc');
1718
var nano = require('nano');
19+
var Cloudant = require('cloudant');
20+
21+
module.exports.getCloudantClient = function(configFile) {
22+
var username = hfc.getConfigSetting('cloudant-username', 'notfound');
23+
var password = hfc.getConfigSetting('cloudant-password', 'notfound');
24+
console.log('CloudantClient username = ' + username + ', password: ' + password);
25+
return Cloudant({account: username, password: password});
26+
};
27+
28+
module.exports.getCouchDBClient = function(configFile) {
29+
var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound');
30+
var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound');
31+
32+
// Record the CouchDB KeyValueStorePath set by couchdb.json
33+
var keyValStorePath = couchdbIPAddr + ':' + couchdbPort;
34+
console.log('CouchDBClient IP address:port = ' + keyValStorePath);
35+
return nano(keyValStorePath);
36+
};
1837

1938
module.exports.destroy = function(name, path) {
2039
this._path = path;
@@ -25,9 +44,7 @@ module.exports.destroy = function(name, path) {
2544
}
2645
var self = this;
2746
return new Promise(function(resolve, reject) {
28-
// Initialize the CouchDB database client
29-
var dbClient = nano(self._path);
30-
// Check if the database already exists. If not, create it.
47+
var dbClient = self._path;
3148
dbClient.db.destroy(self._name, function(err, body) {
3249
if (err) {
3350
resolve(false);

0 commit comments

Comments
 (0)