getLatestNotifications + tests

This commit is contained in:
Ivan Socolsky 2015-10-15 15:14:29 -03:00
parent 2cc71c7b71
commit b23f412bf3
4 changed files with 101 additions and 38 deletions

View File

@ -32,6 +32,7 @@ Notification.create = function(opts) {
x.version = '1.0.0';
var now = Date.now();
x.createdOn = Math.floor(now / 1000);
x.id = _.padLeft(now, 14, '0') + _.padLeft(opts.ticker || 0, 4, '0');
x.type = opts.type || 'general';

View File

@ -1658,6 +1658,24 @@ WalletService.prototype.getNotifications = function(opts, cb) {
});
};
/**
* Retrieves notifications after a specific id or from a given ts (whichever is more recent).
*
* @param {Object} opts
* @param {Object} opts.notificationId (optional)
* @param {Object} opts.minTs (optional) - default now - 60 sec.
* @returns {Notification[]} Notifications
*/
WalletService.prototype.getLatestNotifications = function(opts, cb) {
var self = this;
opts = opts || {};
var minTs = _.isNumber(opts.minTs) ? opts.minTs : +Date.now() - (60 * 1000);
self.storage.fetchLatestNotifications(self.walletId, opts.notificationId, minTs, function(err, notifications) {
if (err) return cb(err);
return cb(null, notifications);
});
};
WalletService.prototype._normalizeTxHistory = function(txs) {
var now = Math.floor(Date.now() / 1000);

View File

@ -315,6 +315,44 @@ Storage.prototype.fetchNotifications = function(walletId, opts, cb) {
});
};
/**
* Retrieves notifications after a specific id or from a given ts (whichever is more recent).
*
* @param {String} notificationId
* @param {Number} minTs
* @returns {Notification[]} Notifications
*/
Storage.prototype.fetchLatestNotifications = function(walletId, notificationId, minTs, cb) {
function makeId(timestamp) {
return _.padLeft(timestamp, 14, '0') + _.repeat('0', 4);
};
var self = this;
var minId = makeId(minTs);
if (notificationId) {
minId = notificationId > minId ? notificationId : minId;
}
this.db.collection(collections.NOTIFICATIONS)
.find({
walletId: walletId,
id: {
$gt: minId,
},
})
.sort({
id: 1
})
.toArray(function(err, result) {
if (err) return cb(err);
if (!result) return cb();
var notifications = _.map(result, function(notification) {
return Model.Notification.fromObj(notification);
});
return cb(null, notifications);
});
};
// TODO: remove walletId from signature
Storage.prototype.storeNotification = function(walletId, notification, cb) {

View File

@ -3876,72 +3876,78 @@ describe('Wallet service', function() {
});
describe('Notifications', function() {
var clock;
var server, wallet;
beforeEach(function(done) {
clock = sinon.useFakeTimers(10 * 1000, 'Date');
helpers.createAndJoinWallet(1, 1, function(s, w) {
server = s;
wallet = w;
helpers.stubUtxos(server, wallet, _.range(4), function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.01, TestData.copayers[0].privKey_1H_0);
async.eachSeries(_.range(3), function(i, next) {
clock.tick(25 * 1000);
server.createTx(txOpts, function(err, tx) {
should.not.exist(err);
next();
});
}, function(err) {
clock.tick(20 * 1000);
return done(err);
});
});
});
});
afterEach(function() {
clock.restore();
});
it('should pull the last 4 notifications after 3 TXs', function(done) {
server.getNotifications({
limit: 4,
reverse: true,
it('should pull all notifications', function(done) {
server.getLatestNotifications({
minTs: 0
}, function(err, notifications) {
should.not.exist(err);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['NewTxProposal', 'NewTxProposal', 'NewTxProposal', 'NewAddress']);
types.should.deep.equal(['NewCopayer', 'NewAddress', 'NewAddress', 'NewTxProposal', 'NewTxProposal', 'NewTxProposal']);
var walletIds = _.uniq(_.pluck(notifications, 'walletId'));
walletIds.length.should.equal(1);
walletIds[0].should.equal(wallet.id);
var creators = _.uniq(_.pluck(notifications, 'creatorId'));
var creators = _.uniq(_.compact(_.pluck(notifications, 'creatorId')));
creators.length.should.equal(1);
creators[0].should.equal(wallet.copayers[0].id);
done();
});
});
it('should pull the last 4 notifications, using now', function(done) {
server.getNotifications({
limit: 4,
reverse: true,
maxTs: Date.now() / 1000,
minTs: Date.now() / 1000 - 1000,
}, function(err, notifications) {
it('should pull notifications in the last 60 seconds', function(done) {
server.getLatestNotifications({}, function(err, notifications) {
should.not.exist(err);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['NewTxProposal', 'NewTxProposal', 'NewTxProposal', 'NewAddress']);
types.should.deep.equal(['NewTxProposal', 'NewTxProposal']);
done();
});
});
it('should pull all notifications after wallet creation', function(done) {
server.getNotifications({
minTs: 0,
it('should pull notifications after a given notification id', function(done) {
server.getLatestNotifications({
minTs: 0
}, function(err, notifications) {
should.not.exist(err);
var types = _.pluck(notifications, 'type');
types[0].should.equal('NewCopayer');
types[types.length - 1].should.equal('NewTxProposal');
done();
var from = _.first(_.takeRight(notifications, 2)).id; // second to last
server.getLatestNotifications({
notificationId: from
}, function(err, res) {
should.not.exist(err);
res.length.should.equal(1);
res[0].id.should.equal(_.first(_.takeRight(notifications)).id);
done();
});
});
});
it('should contain walletId & creatorId on NewCopayer', function(done) {
server.getNotifications({
server.getLatestNotifications({
minTs: 0,
}, function(err, notifications) {
should.not.exist(err);
@ -3962,13 +3968,13 @@ describe('Wallet service', function() {
txProposalId: tx.id,
signatures: signatures,
}, function(err) {
server.getNotifications({
limit: 3,
reverse: true,
server.getLatestNotifications({
minTs: Date.now(),
}, function(err, notifications) {
should.not.exist(err);
notifications.length.should.equal(2);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['TxProposalFinallyAccepted', 'TxProposalAcceptedBy', 'NewTxProposal']);
types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted']);
done();
});
});
@ -3982,13 +3988,13 @@ describe('Wallet service', function() {
txProposalId: tx.id,
}, function(err) {
should.not.exist(err);
server.getNotifications({
limit: 2,
reverse: true,
server.getLatestNotifications({
minTs: Date.now(),
}, function(err, notifications) {
should.not.exist(err);
notifications.length.should.equal(2);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['TxProposalFinallyRejected', 'TxProposalRejectedBy']);
types.should.deep.equal(['TxProposalRejectedBy', 'TxProposalFinallyRejected']);
done();
});
});
@ -4010,13 +4016,13 @@ describe('Wallet service', function() {
txProposalId: tx.id
}, function(err, txp) {
should.not.exist(err);
server.getNotifications({
limit: 3,
reverse: true,
server.getLatestNotifications({
minTs: Date.now(),
}, function(err, notifications) {
should.not.exist(err);
notifications.length.should.equal(3);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['NewOutgoingTx', 'TxProposalFinallyAccepted', 'TxProposalAcceptedBy']);
types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted', 'NewOutgoingTx']);
done();
});
});
@ -4042,13 +4048,13 @@ describe('Wallet service', function() {
txProposalId: tx.id
}, function(err, txp) {
should.not.exist(err);
server.getNotifications({
limit: 3,
reverse: true,
server.getLatestNotifications({
minTs: Date.now(),
}, function(err, notifications) {
should.not.exist(err);
notifications.length.should.equal(3);
var types = _.pluck(notifications, 'type');
types.should.deep.equal(['NewOutgoingTxByThirdParty', 'TxProposalFinallyAccepted', 'TxProposalAcceptedBy']);
types.should.deep.equal(['TxProposalAcceptedBy', 'TxProposalFinallyAccepted', 'NewOutgoingTxByThirdParty']);
done();
});
});