Browse Source

all tests passing

activeAddress
Ivan Socolsky 10 years ago
parent
commit
ea3d251c0d
  1. 2
      lib/server.js
  2. 56
      lib/storage_mongo.js
  3. 198
      test/integration/server.js

2
lib/server.js

@ -942,7 +942,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) {
* @param {Object} opts.minTs (defaults to 0) * @param {Object} opts.minTs (defaults to 0)
* @param {Object} opts.maxTs (defaults to now) * @param {Object} opts.maxTs (defaults to now)
* @param {Object} opts.limit * @param {Object} opts.limit
* @returns {TxProposal[]} Transaction proposals, first newer * @returns {TxProposal[]} Transaction proposals, newer first
*/ */
WalletService.prototype.getTxs = function(opts, cb) { WalletService.prototype.getTxs = function(opts, cb) {
var self = this; var self = this;

56
lib/storage_mongo.js

@ -12,6 +12,13 @@ var mongodb = require('mongodb');
var Model = require('./model'); var Model = require('./model');
var collections = {
WALLETS: 'wallets',
TXS: 'txs',
ADDRESSES: 'addresses',
NOTIFICATIONS: 'notifications',
};
var Storage = function(opts) { var Storage = function(opts) {
opts = opts || {}; opts = opts || {};
this.db = opts.db; this.db = opts.db;
@ -30,7 +37,7 @@ var Storage = function(opts) {
}; };
Storage.prototype.fetchWallet = function(id, cb) { Storage.prototype.fetchWallet = function(id, cb) {
this.db.collection('wallets').findOne({ this.db.collection(collections.WALLETS).findOne({
id: id id: id
}, function(err, result) { }, function(err, result) {
if (err) return cb(err); if (err) return cb(err);
@ -40,7 +47,7 @@ Storage.prototype.fetchWallet = function(id, cb) {
}; };
Storage.prototype.storeWallet = function(wallet, cb) { Storage.prototype.storeWallet = function(wallet, cb) {
this.db.collection('wallets').update({ this.db.collection(collections.WALLETS).update({
id: wallet.id id: wallet.id
}, wallet, { }, wallet, {
w: 1, w: 1,
@ -53,7 +60,7 @@ Storage.prototype.storeWalletAndUpdateCopayersLookup = function(wallet, cb) {
}; };
Storage.prototype.fetchCopayerLookup = function(copayerId, cb) { Storage.prototype.fetchCopayerLookup = function(copayerId, cb) {
this.db.collection('wallets').findOne({ this.db.collection(collections.WALLETS).findOne({
'copayers.id': copayerId 'copayers.id': copayerId
}, { }, {
fields: { fields: {
@ -91,7 +98,7 @@ Storage.prototype._completeTxData = function(walletId, txs, cb) {
Storage.prototype.fetchTx = function(walletId, txProposalId, cb) { Storage.prototype.fetchTx = function(walletId, txProposalId, cb) {
var self = this; var self = this;
this.db.collection('txs').findOne({ this.db.collection(collections.TXS).findOne({
id: txProposalId, id: txProposalId,
walletId: walletId walletId: walletId
}, function(err, result) { }, function(err, result) {
@ -105,11 +112,11 @@ Storage.prototype.fetchTx = function(walletId, txProposalId, cb) {
Storage.prototype.fetchPendingTxs = function(walletId, cb) { Storage.prototype.fetchPendingTxs = function(walletId, cb) {
var self = this; var self = this;
this.db.collection('txs').find({ this.db.collection(collections.TXS).find({
walletId: walletId, walletId: walletId,
isPending: true isPending: true
}).sort({ }).sort({
createdOn: 1 createdOn: -1
}).toArray(function(err, result) { }).toArray(function(err, result) {
if (err) return cb(err); if (err) return cb(err);
if (!result) return cb(); if (!result) return cb();
@ -145,8 +152,8 @@ Storage.prototype.fetchTxs = function(walletId, opts, cb) {
var mods = {}; var mods = {};
if (_.isNumber(opts.limit)) mods.limit = opts.limit; if (_.isNumber(opts.limit)) mods.limit = opts.limit;
this.db.collection('txs').find(filter, mods).sort({ this.db.collection(collections.TXS).find(filter, mods).sort({
createdOn: 1 createdOn: -1
}).toArray(function(err, result) { }).toArray(function(err, result) {
if (err) return cb(err); if (err) return cb(err);
if (!result) return cb(); if (!result) return cb();
@ -165,6 +172,7 @@ Storage.prototype.fetchTxs = function(walletId, opts, cb) {
* @param opts.minTs * @param opts.minTs
* @param opts.maxTs * @param opts.maxTs
* @param opts.limit * @param opts.limit
* @param opts.reverse
*/ */
Storage.prototype.fetchNotifications = function(walletId, opts, cb) { Storage.prototype.fetchNotifications = function(walletId, opts, cb) {
var self = this; var self = this;
@ -183,8 +191,8 @@ Storage.prototype.fetchNotifications = function(walletId, opts, cb) {
var mods = {}; var mods = {};
if (_.isNumber(opts.limit)) mods.limit = opts.limit; if (_.isNumber(opts.limit)) mods.limit = opts.limit;
this.db.collection('notifications').find(filter, mods).sort({ this.db.collection(collections.NOTIFICATIONS).find(filter, mods).sort({
createdOn: 1 id: opts.reverse ? -1 : 1,
}).toArray(function(err, result) { }).toArray(function(err, result) {
if (err) return cb(err); if (err) return cb(err);
if (!result) return cb(); if (!result) return cb();
@ -198,7 +206,7 @@ Storage.prototype.fetchNotifications = function(walletId, opts, cb) {
// TODO: remove walletId from signature // TODO: remove walletId from signature
Storage.prototype.storeNotification = function(walletId, notification, cb) { Storage.prototype.storeNotification = function(walletId, notification, cb) {
this.db.collection('notifications').insert(notification, { this.db.collection(collections.NOTIFICATIONS).insert(notification, {
w: 1 w: 1
}, cb); }, cb);
}; };
@ -206,7 +214,7 @@ Storage.prototype.storeNotification = function(walletId, notification, cb) {
// TODO: remove walletId from signature // TODO: remove walletId from signature
Storage.prototype.storeTx = function(walletId, txp, cb) { Storage.prototype.storeTx = function(walletId, txp, cb) {
txp.isPending = txp.isPending(); // Persist attribute to use when querying txp.isPending = txp.isPending(); // Persist attribute to use when querying
this.db.collection('txs').update({ this.db.collection(collections.TXS).update({
id: txp.id, id: txp.id,
walletId: walletId walletId: walletId
}, txp, { }, txp, {
@ -216,7 +224,7 @@ Storage.prototype.storeTx = function(walletId, txp, cb) {
}; };
Storage.prototype.removeTx = function(walletId, txProposalId, cb) { Storage.prototype.removeTx = function(walletId, txProposalId, cb) {
this.db.collection('txs').findAndRemove({ this.db.collection(collections.TXS).findAndRemove({
id: txProposalId, id: txProposalId,
walletId: walletId walletId: walletId
}, { }, {
@ -230,22 +238,22 @@ Storage.prototype.removeWallet = function(walletId, cb) {
async.parallel([ async.parallel([
function(next) { function(next) {
this.db.collections('wallets').findAndRemove({ self.db.collection(collections.WALLETS).findAndRemove({
id: walletId id: walletId
}, next); }, next);
}, },
function(next) { function(next) {
this.db.collections('addresses').findAndRemove({ self.db.collection(collections.ADDRESSES).remove({
walletId: walletId walletId: walletId
}, next); }, next);
}, },
function(next) { function(next) {
this.db.collections('txs').findAndRemove({ self.db.collection(collections.TXS).remove({
walletId: walletId walletId: walletId
}, next); }, next);
}, },
function(next) { function(next) {
this.db.collections('notifications').findAndRemove({ self.db.collection(collections.NOTIFICATIONS).remove({
walletId: walletId walletId: walletId
}, next); }, next);
}, },
@ -256,7 +264,7 @@ Storage.prototype.removeWallet = function(walletId, cb) {
Storage.prototype.fetchAddresses = function(walletId, cb) { Storage.prototype.fetchAddresses = function(walletId, cb) {
var self = this; var self = this;
this.db.collection('addresses').find({ this.db.collection(collections.ADDRESSES).find({
walletId: walletId, walletId: walletId,
}).sort({ }).sort({
createdOn: 1 createdOn: 1
@ -272,7 +280,9 @@ Storage.prototype.fetchAddresses = function(walletId, cb) {
Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) { Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) {
var self = this; var self = this;
this.db.collection('addresses').insert([].concat(addresses), { var addresses = [].concat(addresses);
if (addresses.length == 0) return cb();
this.db.collection(collections.ADDRESSES).insert(addresses, {
w: 1 w: 1
}, function(err) { }, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -282,14 +292,16 @@ Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) {
Storage.prototype._dump = function(cb, fn) { Storage.prototype._dump = function(cb, fn) {
fn = fn || console.log; fn = fn || console.log;
cb = cb || function() {};
var self = this; var self = this;
this.db.collections(function(err, collections) { this.db.collections(function(err, collections) {
if (err) return cb(err); if (err) return cb(err);
async.eachSeries(collections, function(col, next) { async.eachSeries(collections, function(col, next) {
fn('--------' + col); col.find().toArray(function(err, items) {
col.find().toArray(function(err, item) { fn('--------', col.s.name);
fn(item); fn(items);
fn('------------------------------------------------------------------\n\n');
next(err); next(err);
}); });
}, cb); }, cb);

198
test/integration/server.js

@ -9,13 +9,14 @@ var sinon = require('sinon');
var should = chai.should(); var should = chai.should();
var levelup = require('levelup'); var levelup = require('levelup');
var memdown = require('memdown'); var memdown = require('memdown');
var mongodb = require('mongodb');
var log = require('npmlog'); var log = require('npmlog');
log.debug = log.verbose; log.debug = log.verbose;
var Utils = require('../../lib/utils'); var Utils = require('../../lib/utils');
var WalletUtils = require('bitcore-wallet-utils'); var WalletUtils = require('bitcore-wallet-utils');
var Bitcore = WalletUtils.Bitcore; var Bitcore = WalletUtils.Bitcore;
var Storage = require('../../lib/storage'); var Storage = require('../../lib/storage_mongo');
var BlockchainMonitor = require('../../lib/blockchainmonitor'); var BlockchainMonitor = require('../../lib/blockchainmonitor');
var Wallet = require('../../lib/model/wallet'); var Wallet = require('../../lib/model/wallet');
@ -208,12 +209,40 @@ helpers.createAddresses = function(server, wallet, main, change, cb) {
var db, storage, blockchainExplorer; var db, storage, blockchainExplorer;
function openDb(cb) {
function dropDb(cb) {
db.dropDatabase(function(err) {
should.not.exist(err);
return cb();
});
};
if (db) {
return dropDb(cb);
} else {
var url = 'mongodb://localhost:27017/bws';
mongodb.MongoClient.connect(url, function(err, _db) {
should.not.exist(err);
db = _db;
return dropDb(cb);
});
}
};
describe('Wallet service', function() { function closeDb(cb) {
beforeEach(function() { if (db) {
db = levelup(memdown, { db.close(true, function(err) {
valueEncoding: 'json' should.not.exist(err);
db = null;
return cb();
}); });
} else {
return cb();
}
};
describe('Wallet service', function() {
beforeEach(function(done) {
openDb(function() {
storage = new Storage({ storage = new Storage({
db: db db: db
}); });
@ -224,8 +253,12 @@ describe('Wallet service', function() {
blockchainExplorer: blockchainExplorer, blockchainExplorer: blockchainExplorer,
}); });
helpers.offset = 0; helpers.offset = 0;
done();
});
});
after(function(done) {
closeDb(done);
}); });
describe('#getInstanceWithAuth', function() { describe('#getInstanceWithAuth', function() {
beforeEach(function() {}); beforeEach(function() {});
@ -1172,6 +1205,7 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, _.range(1, 9), function() { helpers.stubUtxos(server, wallet, _.range(1, 9), function() {
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.not.exist(err); should.not.exist(err);
should.exist(tx); should.exist(tx);
txid = tx.id; txid = tx.id;
@ -1814,9 +1848,7 @@ describe('Wallet service', function() {
var server, wallet, clock; var server, wallet, clock;
beforeEach(function(done) { beforeEach(function(done) {
if (server) return done();
this.timeout(5000); this.timeout(5000);
console.log('\tCreating TXS...');
clock = sinon.useFakeTimers(); clock = sinon.useFakeTimers();
helpers.createAndJoinWallet(1, 1, function(s, w) { helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s; server = s;
@ -1824,7 +1856,7 @@ describe('Wallet service', function() {
helpers.stubUtxos(server, wallet, _.range(10), function() { helpers.stubUtxos(server, wallet, _.range(10), function() {
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.1, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.1, null, TestData.copayers[0].privKey_1H_0);
async.eachSeries(_.range(10), function(i, next) { async.eachSeries(_.range(10), function(i, next) {
clock.tick(10000); clock.tick(10 * 1000);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
next(); next();
}); });
@ -1883,7 +1915,8 @@ describe('Wallet service', function() {
}); });
it('should txs from times 50 to 70', function(done) { it('should txs from times 50 to 70',
function(done) {
server.getTxs({ server.getTxs({
minTs: 50, minTs: 50,
maxTs: 70, maxTs: 70,
@ -2073,62 +2106,110 @@ describe('Wallet service', function() {
}); });
}); });
}); });
it('should delete a wallet', function(done) { it('should delete a wallet', function(done) {
var i = 0;
var count = function() {
return ++i;
};
server.storage._dump(function() {
i.should.above(1);
server.removeWallet({}, function(err) { server.removeWallet({}, function(err) {
i = 0; should.not.exist(err);
server.storage._dump(function() { server.getWallet({}, function(err, w) {
server.storage._dump(); should.exist(err);
i.should.equal(0); err.message.should.equal('Wallet not found');
should.not.exist(w);
async.parallel([
function(next) {
server.storage.fetchAddresses(wallet.id, function(err, items) {
items.length.should.equal(0);
next();
});
},
function(next) {
server.storage.fetchTxs(wallet.id, {}, function(err, items) {
items.length.should.equal(0);
next();
});
},
function(next) {
server.storage.fetchNotifications(wallet.id, {}, function(err, items) {
items.length.should.equal(0);
next();
});
},
], function(err) {
should.not.exist(err);
done(); done();
}, count);
}); });
}, count); });
});
}); });
// creates 2 wallet, and deletes only 1. // creates 2 wallet, and deletes only 1.
it('should delete a wallet, and only that wallet', function(done) { it('should delete a wallet, and only that wallet', function(done) {
var i = 0; var server2, wallet2;
var db = []; async.series([
var cat = function(data) {
db.push(data);
};
server.storage._dump(function() {
var before = _.clone(db);
db.length.should.above(1);
function(next) {
helpers.offset = 1; helpers.offset = 1;
helpers.createAndJoinWallet(2, 3, function(s, w) { helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s; server2 = s;
wallet = w; wallet2 = w;
helpers.stubUtxos(server, wallet, _.range(2), function() { helpers.stubUtxos(server2, wallet2, _.range(1, 3), function() {
var txOpts = { var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.1, 'some message', TestData.copayers[1].privKey_1H_0);
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: helpers.toSatoshi(0.1),
};
async.eachSeries(_.range(2), function(i, next) { async.eachSeries(_.range(2), function(i, next) {
server.createTx(txOpts, function(err, tx) { server2.createTx(txOpts, function(err, tx) {
should.not.exist(err);
next(err);
});
}, next);
});
});
},
function(next) {
server.removeWallet({}, next);
},
function(next) {
server.getWallet({}, function(err, wallet) {
should.exist(err);
err.message.should.contain('not found');
next(); next();
}); });
}, function() { },
server.removeWallet({}, function(err) { function(next) {
db = []; server2.getWallet({}, function(err, wallet) {
server.storage._dump(function() { should.not.exist(err);
var after = _.clone(db); should.exist(wallet);
after.should.deep.equal(before); wallet.id.should.equal(wallet2.id);
done(); next();
}, cat);
}); });
}, cat); },
function(next) {
server2.getMainAddresses({}, function(err, addresses) {
should.not.exist(err);
should.exist(addresses);
addresses.length.should.above(0);
next();
}); });
},
function(next) {
server2.getTxs({}, function(err, txs) {
should.not.exist(err);
should.exist(txs);
txs.length.should.equal(2);
next();
});
},
function(next) {
server2.getNotifications({}, function(err, notifications) {
should.not.exist(err);
should.exist(notifications);
notifications.length.should.above(0);
next();
});
},
], function(err) {
should.not.exist(err);
done();
}); });
}, cat);
}); });
}); });
@ -2967,10 +3048,12 @@ describe('Wallet service', function() {
describe('Blockchain monitor', function() { describe('Blockchain monitor', function() {
var addressSubscriber; var addressSubscriber;
beforeEach(function() { beforeEach(function(done) {
db = levelup(memdown, { addressSubscriber = sinon.stub();
valueEncoding: 'json' addressSubscriber.subscribe = sinon.stub();
}); sinon.stub(BlockchainMonitor.prototype, '_getAddressSubscriber').onFirstCall().returns(addressSubscriber);
openDb(function() {
storage = new Storage({ storage = new Storage({
db: db db: db
}); });
@ -2982,14 +3065,15 @@ describe('Blockchain monitor', function() {
}); });
helpers.offset = 0; helpers.offset = 0;
addressSubscriber = sinon.stub(); done();
addressSubscriber.subscribe = sinon.stub(); });
sinon.stub(BlockchainMonitor.prototype, '_getAddressSubscriber').onFirstCall().returns(addressSubscriber);
}); });
afterEach(function() { afterEach(function() {
BlockchainMonitor.prototype._getAddressSubscriber.restore(); BlockchainMonitor.prototype._getAddressSubscriber.restore();
}); });
after(function(done) {
closeDb(done);
});
it('should subscribe wallet', function(done) { it('should subscribe wallet', function(done) {
var monitor = new BlockchainMonitor(); var monitor = new BlockchainMonitor();

Loading…
Cancel
Save