diff --git a/lib/lock.js b/lib/lock.js index 1713907..6ca71a4 100644 --- a/lib/lock.js +++ b/lib/lock.js @@ -1,13 +1,14 @@ var _ = require('lodash'); +var $ = require('preconditions').singleton(); var locks = {}; -var Lock = function () { +var Lock = function() { this.taken = false; this.queue = []; }; -Lock.prototype.free = function () { +Lock.prototype.free = function() { if (this.queue.length > 0) { var f = this.queue.shift(); f(this); @@ -16,7 +17,7 @@ Lock.prototype.free = function () { } }; -Lock.get = function (key, callback) { +Lock.get = function(key, callback) { if (_.isUndefined(locks[key])) { locks[key] = new Lock(); } diff --git a/lib/server.js b/lib/server.js index 07ba841..86e6fa1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1230,9 +1230,9 @@ WalletService.prototype.startScan = function(opts, cb) { setTimeout(function() { self.scan(opts, scanFinished); - }, 0); + }, 100); - return cb() + return cb(); }); }); }; diff --git a/test/integration/server.js b/test/integration/server.js index fd31c01..cf65be4 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -23,6 +23,7 @@ var TxProposal = require('../../lib/model/txproposal'); var Address = require('../../lib/model/address'); var Copayer = require('../../lib/model/copayer'); var WalletService = require('../../lib/server'); +var NotificationBroadcaster = require('../../lib/notificationbroadcaster'); var TestData = require('../testdata'); var helpers = {}; @@ -2636,6 +2637,100 @@ describe('Wallet service', function() { }); + describe('#startScan', function() { + var server, wallet; + var scanConfigOld = WalletService.scanConfig; + beforeEach(function(done) { + this.timeout(5000); + WalletService.scanConfig.SCAN_WINDOW = 2; + WalletService.scanConfig.DERIVATION_DELAY = 0; + + helpers.createAndJoinWallet(1, 2, function(s, w) { + server = s; + wallet = w; + done(); + }); + }); + afterEach(function() { + WalletService.scanConfig = scanConfigOld; + NotificationBroadcaster.removeAllListeners(); + }); + + it('should start an asynchronous scan', function(done) { + helpers.stubAddressActivity(['3K2VWMXheGZ4qG35DyGjA2dLeKfaSr534A']); + var expectedPaths = [ + 'm/2147483647/0/0', + 'm/2147483647/0/1', + 'm/2147483647/0/2', + 'm/2147483647/0/3', + 'm/2147483647/1/0', + 'm/2147483647/1/1', + ]; + WalletService.onNotification(function(n) { + if (n.type == 'ScanFinished') { + should.not.exist(n.creatorId); + server.storage.fetchAddresses(wallet.id, function(err, addresses) { + should.exist(addresses); + addresses.length.should.equal(expectedPaths.length); + var paths = _.pluck(addresses, 'path'); + _.difference(paths, expectedPaths).length.should.equal(0); + server.createAddress({}, function(err, address) { + should.not.exist(err); + address.path.should.equal('m/2147483647/0/4'); + done(); + }); + }) + } + }); + server.startScan({}, function(err) { + should.not.exist(err); + }); + }); + it('should start multiple asynchronous scans for different wallets', function(done) { + helpers.stubAddressActivity(['3K2VWMXheGZ4qG35DyGjA2dLeKfaSr534A']); + WalletService.scanConfig.SCAN_WINDOW = 1; + + var scans = 0; + WalletService.onNotification(function(n) { + if (n.type == 'ScanFinished') { + scans++; + if (scans == 2) done(); + } + }); + + // Create a second wallet + var server2 = new WalletService(); + var opts = { + name: 'second wallet', + m: 1, + n: 1, + pubKey: TestData.keyPair.pub, + }; + server2.createWallet(opts, function(err, walletId) { + should.not.exist(err); + var copayerOpts = helpers.getSignedCopayerOpts({ + walletId: walletId, + name: 'copayer 1', + xPubKey: TestData.copayers[3].xPubKey_45H, + requestPubKey: TestData.copayers[3].pubKey_1H_0, + }); + server.joinWallet(copayerOpts, function(err, result) { + should.not.exist(err); + helpers.getAuthServer(result.copayerId, function(server2) { + server.startScan({}, function(err) { + should.not.exist(err); + scans.should.equal(0); + }); + server2.startScan({}, function(err) { + should.not.exist(err); + scans.should.equal(0); + }); + scans.should.equal(0); + }); + }); + }); + }); + }); describe('#replaceTemporaryRequestKey', function() { var server, walletId; @@ -2835,57 +2930,6 @@ describe('Wallet service', function() { }); }); }); - - describe('#startScan', function() { - var server, wallet; - var scanConfigOld = WalletService.scanConfig; - beforeEach(function(done) { - this.timeout(5000); - WalletService.scanConfig.SCAN_WINDOW = 2; - WalletService.scanConfig.DERIVATION_DELAY = 0; - - helpers.createAndJoinWallet(1, 2, function(s, w) { - server = s; - wallet = w; - done(); - }); - }); - afterEach(function() { - WalletService.scanConfig = scanConfigOld; - WalletService.onNotification(function() {}); - }); - - it('should start an asynchronous scan', function(done) { - helpers.stubAddressActivity(['3K2VWMXheGZ4qG35DyGjA2dLeKfaSr534A']); - var expectedPaths = [ - 'm/2147483647/0/0', - 'm/2147483647/0/1', - 'm/2147483647/0/2', - 'm/2147483647/0/3', - 'm/2147483647/1/0', - 'm/2147483647/1/1', - ]; - WalletService.onNotification(function(n) { - if (n.type == 'ScanFinished') { - should.not.exist(n.creatorId); - server.storage.fetchAddresses(wallet.id, function(err, addresses) { - should.exist(addresses); - addresses.length.should.equal(expectedPaths.length); - var paths = _.pluck(addresses, 'path'); - _.difference(paths, expectedPaths).length.should.equal(0); - server.createAddress({}, function(err, address) { - should.not.exist(err); - address.path.should.equal('m/2147483647/0/4'); - done(); - }); - }) - } - }); - server.startScan({}, function(err) { - should.not.exist(err); - }); - }); - }); }); diff --git a/test/lock.js b/test/lock.js new file mode 100644 index 0000000..95ae2fe --- /dev/null +++ b/test/lock.js @@ -0,0 +1,50 @@ +'use strict'; + +var _ = require('lodash'); +var chai = require('chai'); +var sinon = require('sinon'); +var should = chai.should(); +var Lock = require('../lib/lock'); + +describe('Lock', function() { + it('should lock tasks using the same token', function(done) { + var a = false, + b = false; + Lock.get('123', function(lock) { + a = true; + setTimeout(function() { + lock.free(); + }, 5); + Lock.get('123', function(lock) { + b = true; + lock.free(); + }); + }); + setTimeout(function() { + a.should.equal(true); + b.should.equal(false); + }, 1); + setTimeout(function() { + a.should.equal(true); + b.should.equal(true); + done(); + }, 8); + }); + it('should not lock tasks using different tokens', function(done) { + var i = 0; + Lock.get('123', function(lock) { + i++; + setTimeout(function() { + lock.free(); + }, 5); + Lock.get('456', function(lock) { + i++; + lock.free(); + }); + }); + setTimeout(function() { + i.should.equal(2); + done(); + }, 1); + }); +});