This commit is contained in:
Chris Kleeschulte 2017-07-27 17:49:09 -04:00
parent 033849ed1f
commit f8df875c34
21 changed files with 248 additions and 3190 deletions

View File

@ -1,104 +0,0 @@
'use strict';
var sinon = require('sinon');
var Service = require('../lib/service');
var BitcoreNode = require('../lib/node');
var util = require('util');
var should = require('chai').should();
var index = require('../lib');
var log = index.log;
var TestService = function(options) {
this.node = options.node;
};
util.inherits(TestService, Service);
TestService.dependencies = [];
TestService.prototype.start = function(callback) {
callback();
};
TestService.prototype.stop = function(callback) {
callback();
};
TestService.prototype.close = function(callback) {
callback();
};
TestService.prototype.getPublishEvents = function() {
return [
{
name: 'test/testEvent',
scope: this,
subscribe: this.subscribe.bind(this, 'test/testEvent'),
unsubscribe: this.unsubscribe.bind(this, 'test/testEvent')
}
];
};
TestService.prototype.subscribe = function(name, emitter, params) {
emitter.emit(name, params);
};
TestService.prototype.unsubscribe = function(name, emitter) {
emitter.emit('unsubscribe');
};
describe('Bus Functionality', function() {
var sandbox = sinon.sandbox.create();
beforeEach(function() {
sandbox.stub(log, 'info');
});
afterEach(function() {
sandbox.restore();
});
it('should subscribe to testEvent', function(done) {
var node = new BitcoreNode({
datadir: './',
network: 'testnet',
port: 8888,
services: [
{
name: 'testService',
config: {},
module: TestService
}
]
});
node.start(function() {
var bus = node.openBus();
var params = 'somedata';
bus.on('test/testEvent', function(data) {
data.should.be.equal(params);
done();
});
bus.subscribe('test/testEvent', params);
});
});
it('should unsubscribe from a testEvent', function(done) {
var node = new BitcoreNode({
datadir: './',
network: 'testnet',
port: 8888,
services: [
{
name: 'testService',
config: {},
module: TestService
}
]
});
node.start(function() {
var bus = node.openBus();
var params = 'somedata';
bus.on('unsubscribe', function() {
done();
});
bus.subscribe('test/testEvent');
bus.unsubscribe('test/testEvent');
});
});
});

View File

@ -1,131 +0,0 @@
'use strict';
var should = require('chai').should();
var sinon = require('sinon');
var Bus = require('../lib/bus');
describe('Bus', function() {
describe('#subscribe', function() {
it('will call db and services subscribe function with the correct arguments', function() {
var subscribeDb = sinon.spy();
var subscribeService = sinon.spy();
var node = {
services: {
db: {
getPublishEvents: sinon.stub().returns([
{
name: 'dbtest',
scope: this,
subscribe: subscribeDb
}
])
},
service1: {
getPublishEvents: sinon.stub().returns([
{
name: 'test',
scope: this,
subscribe: subscribeService,
}
])
}
}
};
var bus = new Bus({node: node});
bus.subscribe('dbtest', 'a', 'b', 'c');
bus.subscribe('test', 'a', 'b', 'c');
subscribeService.callCount.should.equal(1);
subscribeDb.callCount.should.equal(1);
subscribeDb.args[0][0].should.equal(bus);
subscribeDb.args[0][1].should.equal('a');
subscribeDb.args[0][2].should.equal('b');
subscribeDb.args[0][3].should.equal('c');
subscribeService.args[0][0].should.equal(bus);
subscribeService.args[0][1].should.equal('a');
subscribeService.args[0][2].should.equal('b');
subscribeService.args[0][3].should.equal('c');
});
});
describe('#unsubscribe', function() {
it('will call db and services unsubscribe function with the correct arguments', function() {
var unsubscribeDb = sinon.spy();
var unsubscribeService = sinon.spy();
var node = {
services: {
db: {
getPublishEvents: sinon.stub().returns([
{
name: 'dbtest',
scope: this,
unsubscribe: unsubscribeDb
}
])
},
service1: {
getPublishEvents: sinon.stub().returns([
{
name: 'test',
scope: this,
unsubscribe: unsubscribeService,
}
])
}
}
};
var bus = new Bus({node: node});
bus.unsubscribe('dbtest', 'a', 'b', 'c');
bus.unsubscribe('test', 'a', 'b', 'c');
unsubscribeService.callCount.should.equal(1);
unsubscribeDb.callCount.should.equal(1);
unsubscribeDb.args[0][0].should.equal(bus);
unsubscribeDb.args[0][1].should.equal('a');
unsubscribeDb.args[0][2].should.equal('b');
unsubscribeDb.args[0][3].should.equal('c');
unsubscribeService.args[0][0].should.equal(bus);
unsubscribeService.args[0][1].should.equal('a');
unsubscribeService.args[0][2].should.equal('b');
unsubscribeService.args[0][3].should.equal('c');
});
});
describe('#close', function() {
it('will unsubscribe from all events', function() {
var unsubscribeDb = sinon.spy();
var unsubscribeService = sinon.spy();
var node = {
services: {
db: {
getPublishEvents: sinon.stub().returns([
{
name: 'dbtest',
scope: this,
unsubscribe: unsubscribeDb
}
])
},
service1: {
getPublishEvents: sinon.stub().returns([
{
name: 'test',
scope: this,
unsubscribe: unsubscribeService
}
])
}
}
};
var bus = new Bus({node: node});
bus.close();
unsubscribeDb.callCount.should.equal(1);
unsubscribeService.callCount.should.equal(1);
unsubscribeDb.args[0].length.should.equal(1);
unsubscribeDb.args[0][0].should.equal(bus);
unsubscribeService.args[0].length.should.equal(1);
unsubscribeService.args[0][0].should.equal(bus);
});
});
});

View File

@ -1,16 +0,0 @@
#testnet=1
#irc=0
#upnp=0
server=1
whitelist=127.0.0.1
# listen on different ports
port=20000
rpcallowip=127.0.0.1
rpcuser=bitcoin
rpcpassword=local321

View File

@ -1,14 +0,0 @@
[
{
"comment": "sends to tx[1]",
"hex":"0100000001dee8f4266e83072e0ad258125cc5a42ac25d2d2c73e6e2e873413b3939af1605000000006b483045022100ae987d056f81d2c982b71b0406f2374c1958b24bd289d77371347e275d2a62c002205148b17173be18af4e1e73ce2b0fd600734ea77087754bdba5dc7d645b01880a01210226ab3b46f85bf32f63778c680e16ef8b3fcb51d638a7980d651bfaeae6c17752ffffffff0170820300000000001976a9142baf68e3681df183375a4f4c10306de9a5c6cc7788ac00000000"
},
{
"comment": "spends from tx[0] (valid)",
"hex":"0100000001f77c71cf8c272d22471f054cae7fb48561ebcf004b8ec8f9f65cd87af82a2944000000006a47304402203c2bc91a170facdc5ef4b5b94c413bc7a10f65e09b326d205f070b17aa94d67102205b684111af2a20171eb65db73e6c73f9e77e6e6f739e050bc052ed6ecc9feb4a01210365d8756a4f3fc738105cfab8d80a85189bdb4db5af83374e645b79e2aadd976effffffff01605b0300000000001976a9149e84d1295471958e5ffccd8d36a57bd5d220f8ed88ac00000000"
},
{
"comment": "spends from tx[0] (missing signature)",
"hex":"0100000001f77c71cf8c272d22471f054cae7fb48561ebcf004b8ec8f9f65cd87af82a29440000000000ffffffff01605b0300000000001976a9149e84d1295471958e5ffccd8d36a57bd5d220f8ed88ac00000000"
}
]

View File

@ -1,23 +0,0 @@
#testnet=1
#irc=0
upnp=0
server=1
whitelist=127.0.0.1
txindex=1
addressindex=1
timestampindex=1
spentindex=1
dbcache=8192
checkblocks=144
maxuploadtarget=1024
zmqpubrawtx=tcp://127.0.0.1:28332
zmqpubhashblock=tcp://127.0.0.1:28332
port=20000
rpcport=50001
rpcallowip=127.0.0.1
rpcuser=bitcoin
rpcpassword=local321

View File

@ -1,5 +0,0 @@
{
"genesis": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",
"block1a": "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f69965a91e7fc9ccccbe4051b74d086114741b96678f5e491b5609b18962252fd2d12f858ffff7f20040000000102000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a0100000023210372bfaa748e546ba784a4d1395f5cedf673f9f5a8160effbe0f595fe905fb3e59ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf900000000",
"block1b": "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f36f612e7b9a88a90fdd781e8885ae425ee9124e17c22d6eb4253094d0e6f6ae6dfede058ffff7f20010000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a01000000232103caa96df67b8a5ce37cca53ddf394a093fab6922830fad79fc5f0d8369200121cac00000000"
}

View File

@ -1,12 +0,0 @@
server=1
whitelist=127.0.0.1
txindex=1
addressindex=1
timestampindex=1
spentindex=1
zmqpubrawtx=tcp://127.0.0.1:28332
zmqpubhashblock=tcp://127.0.0.1:28332
rpcallowip=127.0.0.1
rpcuser=bitcoin
rpcpassword=local321
uacomment=bitcore

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +0,0 @@
[
"010000000ec9e1d96d51f7d0a5b726184cda744207e51a596f13b564109de6ffc0653055cf000000006a4730440220263d48a2f4c3a2aa6032f96253c853531131171d8ae3d30586a45de7ba7c4006022077db4b39926877939baf59e8d357effe7674e7b12ad986c0a4cd99f2b7acafca012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff0c16800642bdf90cbbd340be2e801bee9b907db6d59dc4c7cb269358c1e2593a000000006a4730440220085e39cb3a948559c1b1c88ba635eeef37a767322c1e4d96556e998302acb5dc0220421c03de78121692c538a9bc85a58fbe796384541fe87b6e91c39404318c390d012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff559fde3733e950db9e3faea1a27872047a5c8bc14e8e6ac4a7b4f7b5f90c42c2000000006b483045022100a46a109a5acfc34b13c591ab69392e2dc2c3ea12d0900c5f7a539ea888e57ae0022015372bad56d63c6d08a5e66e0c9a63b2fc8dce245aa765e37dac06acb84c18d501210207e2a01d4a334c2d7c9ebacc5ea8a0d4b86fd54599b1aebe125d9e664be012c2ffffffff92760c236f6f18751c4ecab1dfcfebac7358a431b31bcd72b0a09d336233bdce000000006a47304402200857fa82e5b287c6ed5624cbc4fcd068a756a7a9ef785a73ce4e51b15a8aa34b022042cbc6f478b711539c6345d0b05d4bc9a9b5c34b2e4d25f234cf6784ff2eed19012103cab1f64f3d5f20a3f4a070694e6f93f5248b502b3842e369d81f05d07dec01e3ffffffff158669557e8a0b71288df37626601e636c5a8b3797f7f3357590313e8efe790a000000006b48304502210085e62cb95066540730b74aeae133277e511b5bf79de8c0ad60e784638e681ddf022043b456285569e0da133f527412218893f05a781d6f77f8cddd12eb90bfdc5937012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffffc1f9f57f1eda20f3b45669b3f0d1eae73b410ddf2b4fc1cfe10051a6051eff68000000006a47304402200fbe15c73446309040f4264567d0e8cc46691cf5d0626c443fc2dde716211e5402207f84e68e273755d140f346e029213dbc42b65cfb1e2ac41f72402c7ff45feffc012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff39fa27e16c540a9bb796e65d4ac624fc33878e522461d6955764bf7b83c03ce8000000006a4730440220131e6aed76da389f21dfd7cd271fad73c5c533b1c18fbfabd6799a0d0e7dc80602205c38855bea0f1dfbbb608bc1b56c75b91a39980de121ffd9f880b522d412d821012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff375fb7ae26eb637ccc007a669b9f50ed10fa53127504b80e0fd2be34c50becd7000000006b483045022100f0a9e585aa3113eae4bfb204f38f96e60dc613c04313aae931b677e4d8d7081d022014664874859f3d47447c6c0f257c28c74e8fdaedd5f781d752f3a4b651d3d179012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff6f9d6a3c847e6112bb920424ca0d8d6e0956b128acb206e8fb58b2d2f2d7d46b000000006a4730440220736b198484cf5226616a539146e037a93cc75963885eefe58fc29a7be8123c750220619a456c0fe7437ec67c642d88e890344fc1c51a7b3cfc0ae283d61d0f176c5e012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff3cccbd8090d60fcf28064333cf2f51ef0f838ba5e26a5e0f38807ee16d38a649000000006b483045022100e1ed25e9365e596d4fc3cbf278490d8ea765c4266c55f19311cf5da33f8d00750220361888a1738ebba827c0c947690b5f2a5f20e9f1be8956c3a34a4ba03f9e60f5012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff7f4d60a2e961490aa465a7df461bf09b151bdc0c162f3bef0c1cbed6160d02c7000000006a47304402204e79b15a1db9a356f00dc9f2d559e31561cad1343ba5809a65b52bd868e3963e022055b9326ed5de9aa9970ec67a2ebf1a9dbf9ee513b64bd13837c87320bb4d6947012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffffe63b9370ba49a129e071750cbb300128015fdd90d7399f9c4e44934eabbaa2f7000000006b483045022100b9ceb2e376c0334d45bf08bfeb06dc250e7cb01d3a08e2fb3506388683552417022024c7c5bda385b904cca691fb6e1ad8c5eba5858a88a2112cb824dca72793b7a7012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffffc78b96fddededb6cbc1dff9de51f2743fd42e91de2506794b121928af4729528000000006a47304402201f05caddee5a0ff590b27c4ce25be1cbbeb45dc39679a1b8b0e10b1a378d84bc02203e31b01e14d891e9809c43a4df54494c626c5e47eaeeeb99ab4e02bd73c3d6cd012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff30093916240e981a77cb869924fa0c38a894c24b1a6e7d26b117bb9caa7d5bbe000000006a4730440220483f297379daacee14babbf929708a861a991373bca3ed4eef240e2c156a162602205f1e93e375a897c6a9ddc3dc616ccf14137096ebd7888040e1053a769d21b945012103e9100732bb534bea2f6d3b971914ec8403557306600c01c5ce63ec185737c732ffffffff022897d411000000001976a91415354ee1828ed12f243f80dcb92c3a8205285f0188ac3be68c02000000001976a9143ecf8ff79932c3de33829a001236985872d10be188ac00000000"
]

View File

@ -6,6 +6,7 @@ var should = chai.should();
var Logger = require('../lib/logger');
describe('Logger', function() {
process.env.BITCORE_ENV = 'debug';
var sandbox = sinon.sandbox.create();
afterEach(function() {
sandbox.restore();
@ -31,10 +32,10 @@ describe('Logger', function() {
it('will log with formatting', function() {
var logger = new Logger({formatting: true});
sandbox.stub(console, 'info');
sandbox.stub(console, 'log');
logger.info('Test info log');
console.info.callCount.should.equal(1);
console.info.restore();
console.log.callCount.should.equal(1);
console.log.restore();
sandbox.stub(console, 'error');
logger.error(new Error('Test error log'));
@ -46,20 +47,20 @@ describe('Logger', function() {
console.log.callCount.should.equal(1);
console.log.restore();
sandbox.stub(console, 'warn');
sandbox.stub(console, 'log');
logger.warn('Test warn log');
console.warn.callCount.should.equal(1);
console.warn.restore();
console.log.callCount.should.equal(1);
console.log.restore();
});
it('will log without formatting', function() {
var logger = new Logger({formatting: false});
sandbox.stub(console, 'info');
sandbox.stub(console, 'log');
logger.info('Test info log');
console.info.callCount.should.equal(1);
should.not.exist(console.info.args[0][0].match(/^\[/));
console.info.restore();
console.log.callCount.should.equal(1);
should.not.exist(console.log.args[0][0].match(/^\[/));
console.log.restore();
sandbox.stub(console, 'error');
logger.error(new Error('Test error log'));
@ -73,11 +74,11 @@ describe('Logger', function() {
should.equal(console.log.args[0][0].match(/^\[/), null);
console.log.restore();
sandbox.stub(console, 'warn');
sandbox.stub(console, 'log');
logger.warn('Test warn log');
console.warn.callCount.should.equal(1);
should.equal(console.warn.args[0][0].match(/^\[/), null);
console.warn.restore();
console.log.callCount.should.equal(1);
should.equal(console.log.args[0][0].match(/^\[/), null);
console.log.restore();
});
});

View File

@ -189,7 +189,7 @@ describe('Bitcore Node', function() {
});
});
describe('#getServiceOrder', function() {
describe('#_getServiceOrder', function() {
it('should return the services in the correct order', function() {
var node = new Node(baseConfig);
node._unloadedServices = [
@ -218,7 +218,7 @@ describe('Bitcore Node', function() {
}
}
];
var order = node.getServiceOrder();
var order = node._getServiceOrder(node._unloadedServices);
order[0].name.should.equal('daemon');
order[1].name.should.equal('p2p');
order[2].name.should.equal('db');
@ -336,7 +336,7 @@ describe('Bitcore Node', function() {
];
};
node.getServiceOrder = sinon.stub().returns([
node._getServiceOrder = sinon.stub().returns([
{
name: 'test1',
module: TestService,
@ -379,7 +379,7 @@ describe('Bitcore Node', function() {
];
};
node.getServiceOrder = sinon.stub().returns([
node._getServiceOrder = sinon.stub().returns([
{
name: 'test',
module: TestService,
@ -407,7 +407,7 @@ describe('Bitcore Node', function() {
TestService.prototype.start = sinon.stub().callsArg(0);
TestService.prototype.getData = function() {};
node.getServiceOrder = sinon.stub().returns([
node._getServiceOrder = sinon.stub().returns([
{
name: 'test',
module: TestService,
@ -471,7 +471,7 @@ describe('Bitcore Node', function() {
};
node.test2 = {};
node.test2.stop = sinon.stub().callsArg(0);
node.getServiceOrder = sinon.stub().returns([
node._getServiceOrder = sinon.stub().returns([
{
name: 'test1',
module: TestService

View File

@ -1,106 +0,0 @@
'use strict';
var path = require('path');
var should = require('chai').should();
var sinon = require('sinon');
var proxyquire = require('proxyquire');
describe('#defaultConfig', function() {
var expectedExecPath = path.resolve(__dirname, '../../bin/bitcoind');
it('will return expected configuration', function() {
var config = JSON.stringify({
network: 'livenet',
port: 3001,
services: [
'bitcoind',
'web'
],
servicesConfig: {
bitcoind: {
spawn: {
datadir: process.env.HOME + '/.bitcore/data',
exec: expectedExecPath
}
}
}
}, null, 2);
var defaultConfig = proxyquire('../../lib/scaffold/default-config', {
fs: {
existsSync: sinon.stub().returns(false),
writeFileSync: function(path, data) {
path.should.equal(process.env.HOME + '/.bitcore/bitcore-node.json');
data.should.equal(config);
},
readFileSync: function() {
return config;
}
},
mkdirp: {
sync: sinon.stub()
}
});
var home = process.env.HOME;
var info = defaultConfig();
info.path.should.equal(home + '/.bitcore');
info.config.network.should.equal('livenet');
info.config.port.should.equal(3001);
info.config.services.should.deep.equal(['bitcoind', 'web']);
var bitcoind = info.config.servicesConfig.bitcoind;
should.exist(bitcoind);
bitcoind.spawn.datadir.should.equal(home + '/.bitcore/data');
bitcoind.spawn.exec.should.equal(expectedExecPath);
});
it('will include additional services', function() {
var config = JSON.stringify({
network: 'livenet',
port: 3001,
services: [
'bitcoind',
'web',
'insight-api',
'insight-ui'
],
servicesConfig: {
bitcoind: {
spawn: {
datadir: process.env.HOME + '/.bitcore/data',
exec: expectedExecPath
}
}
}
}, null, 2);
var defaultConfig = proxyquire('../../lib/scaffold/default-config', {
fs: {
existsSync: sinon.stub().returns(false),
writeFileSync: function(path, data) {
path.should.equal(process.env.HOME + '/.bitcore/bitcore-node.json');
data.should.equal(config);
},
readFileSync: function() {
return config;
}
},
mkdirp: {
sync: sinon.stub()
}
});
var home = process.env.HOME;
var info = defaultConfig({
additionalServices: ['insight-api', 'insight-ui']
});
info.path.should.equal(home + '/.bitcore');
info.config.network.should.equal('livenet');
info.config.port.should.equal(3001);
info.config.services.should.deep.equal([
'bitcoind',
'web',
'insight-api',
'insight-ui'
]);
var bitcoind = info.config.servicesConfig.bitcoind;
should.exist(bitcoind);
bitcoind.spawn.datadir.should.equal(home + '/.bitcore/data');
bitcoind.spawn.exec.should.equal(expectedExecPath);
});
});

View File

@ -1,79 +0,0 @@
'use strict';
var fs = require('fs');
var path = require('path');
var should = require('chai').should();
var sinon = require('sinon');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var findConfig = require('../../lib/scaffold/find-config');
describe('#findConfig', function() {
var testDir = path.resolve(__dirname, '../temporary-test-data');
var expectedConfig = {
name: 'My Node'
};
before(function(done) {
// setup testing directories
mkdirp(testDir + '/p2/p1/p0', function(err) {
if (err) {
throw err;
}
fs.writeFile(
testDir + '/p2/bitcore-node.json',
JSON.stringify(expectedConfig),
function() {
mkdirp(testDir + '/e0', function(err) {
if (err) {
throw err;
}
done();
});
}
);
});
});
after(function(done) {
// cleanup testing directories
rimraf(testDir, function(err) {
if (err) {
throw err;
}
done();
});
});
describe('will find a configuration file', function() {
it('in the current directory', function() {
var config = findConfig(path.resolve(testDir, 'p2'));
config.path.should.equal(path.resolve(testDir, 'p2'));
config.config.should.deep.equal(expectedConfig);
});
it('in a parent directory', function() {
var config = findConfig(path.resolve(testDir, 'p2/p1'));
config.path.should.equal(path.resolve(testDir, 'p2'));
config.config.should.deep.equal(expectedConfig);
});
it('recursively find in parent directories', function() {
var config = findConfig(path.resolve(testDir, 'p2/p1/p0'));
config.path.should.equal(path.resolve(testDir, 'p2'));
config.config.should.deep.equal(expectedConfig);
});
});
it('will return false if missing a configuration', function() {
var config = findConfig(path.resolve(testDir, 'e0'));
config.should.equal(false);
});
});

View File

@ -1,136 +0,0 @@
'use strict';
var should = require('chai').should();
var sinon = require('sinon');
var proxyquire = require('proxyquire');
var BitcoinService = require('../../lib/services/bitcoind');
var index = require('../../lib');
var log = index.log;
describe('#start', function() {
var sandbox = sinon.sandbox.create();
beforeEach(function() {
sandbox.stub(log, 'error');
});
afterEach(function() {
sandbox.restore();
});
describe('will dynamically create a node from a configuration', function() {
it('require each bitcore-node service with default config', function(done) {
var node;
var TestNode = function(options) {
options.services[0].should.deep.equal({
name: 'bitcoind',
module: BitcoinService,
config: {
spawn: {
datadir: './data'
}
}
});
};
TestNode.prototype.start = sinon.stub().callsArg(0);
TestNode.prototype.on = sinon.stub();
TestNode.prototype.chain = {
on: sinon.stub()
};
var starttest = proxyquire('../../lib/scaffold/start', {
'../node': TestNode
});
starttest.registerExitHandlers = sinon.stub();
node = starttest({
path: __dirname,
config: {
services: [
'bitcoind'
],
servicesConfig: {
bitcoind: {
spawn: {
datadir: './data'
}
}
}
}
});
node.should.be.instanceof(TestNode);
done();
});
it('shutdown with an error from start', function(done) {
var TestNode = proxyquire('../../lib/node', {});
TestNode.prototype.start = function(callback) {
setImmediate(function() {
callback(new Error('error'));
});
};
var starttest = proxyquire('../../lib/scaffold/start', {
'../node': TestNode
});
starttest.cleanShutdown = sinon.stub();
starttest.registerExitHandlers = sinon.stub();
starttest({
path: __dirname,
config: {
services: [],
servicesConfig: {}
}
});
setImmediate(function() {
starttest.cleanShutdown.callCount.should.equal(1);
done();
});
});
it('require each bitcore-node service with explicit config', function(done) {
var node;
var TestNode = function(options) {
options.services[0].should.deep.equal({
name: 'bitcoind',
module: BitcoinService,
config: {
param: 'test',
spawn: {
datadir: './data'
}
}
});
};
TestNode.prototype.start = sinon.stub().callsArg(0);
TestNode.prototype.on = sinon.stub();
TestNode.prototype.chain = {
on: sinon.stub()
};
var starttest = proxyquire('../../lib/scaffold/start', {
'../node': TestNode
});
starttest.registerExitHandlers = sinon.stub();
node = starttest({
path: __dirname,
config: {
services: [
'bitcoind'
],
servicesConfig: {
'bitcoind': {
param: 'test',
spawn: {
datadir: './data'
}
}
},
}
});
node.should.be.instanceof(TestNode);
done();
});
});
});

View File

@ -1,274 +0,0 @@
'use strict';
var should = require('chai').should();
var EventEmitter = require('events').EventEmitter;
var path = require('path');
var sinon = require('sinon');
var proxyquire = require('proxyquire');
var start = require('../../lib/scaffold/start');
describe('#start', function() {
describe('#checkConfigVersion2', function() {
var sandbox = sinon.sandbox.create();
beforeEach(function() {
sandbox.stub(console, 'warn');
});
afterEach(function() {
sandbox.restore();
});
it('will give true with "datadir" at root', function() {
var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2;
var v2 = checkConfigVersion2({datadir: '/home/user/.bitcore/data', services: []});
v2.should.equal(true);
});
it('will give true with "address" service enabled', function() {
var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2;
var v2 = checkConfigVersion2({services: ['address']});
v2.should.equal(true);
});
it('will give true with "db" service enabled', function() {
var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2;
var v2 = checkConfigVersion2({services: ['db']});
v2.should.equal(true);
});
it('will give false without "datadir" at root and "address", "db" services disabled', function() {
var checkConfigVersion2 = proxyquire('../../lib/scaffold/start', {}).checkConfigVersion2;
var v2 = checkConfigVersion2({services: []});
v2.should.equal(false);
});
});
describe('#setupServices', function() {
var cwd = process.cwd();
var setupServices = proxyquire('../../lib/scaffold/start', {}).setupServices;
it('will require an internal module', function() {
function InternalService() {}
InternalService.dependencies = [];
InternalService.prototype.start = sinon.stub();
InternalService.prototype.stop = sinon.stub();
var expectedPath = path.resolve(__dirname, '../../lib/services/internal');
var testRequire = function(p) {
p.should.equal(expectedPath);
return InternalService;
};
var config = {
services: ['internal'],
servicesConfig: {
internal: {
param: 'value'
}
}
};
var services = setupServices(testRequire, cwd, config);
services[0].name.should.equal('internal');
services[0].config.should.deep.equal({param: 'value'});
services[0].module.should.equal(InternalService);
});
it('will require a local module', function() {
function LocalService() {}
LocalService.dependencies = [];
LocalService.prototype.start = sinon.stub();
LocalService.prototype.stop = sinon.stub();
var notfoundPath = path.resolve(__dirname, '../../lib/services/local');
var testRequire = function(p) {
if (p === notfoundPath) {
throw new Error();
} else if (p === 'local') {
return LocalService;
} else if (p === 'local/package.json') {
return {
name: 'local'
};
}
};
var config = {
services: ['local']
};
var services = setupServices(testRequire, cwd, config);
services[0].name.should.equal('local');
services[0].module.should.equal(LocalService);
});
it('will require a local module with "bitcoreNode" in package.json', function() {
function LocalService() {}
LocalService.dependencies = [];
LocalService.prototype.start = sinon.stub();
LocalService.prototype.stop = sinon.stub();
var notfoundPath = path.resolve(__dirname, '../../lib/services/local');
var testRequire = function(p) {
if (p === notfoundPath) {
throw new Error();
} else if (p === 'local/package.json') {
return {
name: 'local',
bitcoreNode: 'lib/bitcoreNode.js'
};
} else if (p === 'local/lib/bitcoreNode.js') {
return LocalService;
}
};
var config = {
services: ['local']
};
var services = setupServices(testRequire, cwd, config);
services[0].name.should.equal('local');
services[0].module.should.equal(LocalService);
});
it('will throw error if module is incompatible', function() {
var internal = {};
var testRequire = function() {
return internal;
};
var config = {
services: ['bitcoind']
};
(function() {
setupServices(testRequire, cwd, config);
}).should.throw('Could not load service');
});
});
describe('#cleanShutdown', function() {
it('will call node stop and process exit', function() {
var log = {
info: sinon.stub(),
error: sinon.stub()
};
var cleanShutdown = proxyquire('../../lib/scaffold/start', {
'../': {
log: log
}
}).cleanShutdown;
var node = {
stop: sinon.stub().callsArg(0)
};
var _process = {
exit: sinon.stub()
};
cleanShutdown(_process, node);
setImmediate(function() {
node.stop.callCount.should.equal(1);
_process.exit.callCount.should.equal(1);
_process.exit.args[0][0].should.equal(0);
});
});
it('will log error during shutdown and exit with status 1', function() {
var log = {
info: sinon.stub(),
error: sinon.stub()
};
var cleanShutdown = proxyquire('../../lib/scaffold/start', {
'../': {
log: log
}
}).cleanShutdown;
var node = {
stop: sinon.stub().callsArgWith(0, new Error('test'))
};
var _process = {
exit: sinon.stub()
};
cleanShutdown(_process, node);
setImmediate(function() {
node.stop.callCount.should.equal(1);
log.error.callCount.should.equal(1);
_process.exit.callCount.should.equal(1);
_process.exit.args[0][0].should.equal(1);
});
});
});
describe('#registerExitHandlers', function() {
var log = {
info: sinon.stub(),
error: sinon.stub()
};
var registerExitHandlers = proxyquire('../../lib/scaffold/start', {
'../': {
log: log
}
}).registerExitHandlers;
it('log, stop and exit with an `uncaughtException`', function(done) {
var proc = new EventEmitter();
proc.exit = sinon.stub();
var node = {
stop: sinon.stub().callsArg(0)
};
registerExitHandlers(proc, node);
proc.emit('uncaughtException', new Error('test'));
setImmediate(function() {
node.stop.callCount.should.equal(1);
proc.exit.callCount.should.equal(1);
done();
});
});
it('stop and exit on `SIGINT`', function(done) {
var proc = new EventEmitter();
proc.exit = sinon.stub();
var node = {
stop: sinon.stub().callsArg(0)
};
registerExitHandlers(proc, node);
proc.emit('SIGINT');
setImmediate(function() {
node.stop.callCount.should.equal(1);
proc.exit.callCount.should.equal(1);
done();
});
});
});
describe('#registerExitHandlers', function() {
var stub;
var registerExitHandlers = require('../../lib/scaffold/start').registerExitHandlers;
before(function() {
stub = sinon.stub(process, 'on');
});
after(function() {
stub.restore();
});
it('should setup two listeners on process when registering exit handlers', function() {
registerExitHandlers(process, {});
stub.callCount.should.equal(2);
});
describe('#exitHandler', function() {
var sandbox;
var cleanShutdown;
var exitHandler;
var logStub;
before(function() {
sandbox = sinon.sandbox.create();
var start = require('../../lib/scaffold/start');
var log = require('../../lib').log;
logStub = sandbox.stub(log, 'error');
cleanShutdown = sandbox.stub(start, 'cleanShutdown', function() {});
exitHandler = require('../../lib/scaffold/start').exitHandler;
});
after(function() {
sandbox.restore();
});
it('should replace the listener for SIGINT after the first SIGINT is handled', function() {
var options = { sigint: true };
var node = {};
exitHandler(options, process, node);
cleanShutdown.callCount.should.equal(1);
exitHandler(options, process, node);
cleanShutdown.callCount.should.equal(1);
});
it('should log all errors and stops the services nonetheless', function() {
var options = { sigint: true };
var stop = sinon.stub();
var node = {
stop: stop
};
exitHandler(options, process, node, new Error('some error'));
logStub.callCount.should.equal(2);
stop.callCount.should.equal(1);
});
});
});
});

View File

@ -81,11 +81,12 @@ describe('Header Service', function() {
it('should start the sync process', function() {
headerService._bestHeight = 123;
headerService._checkpoint = 8888;
headerService._tip = { height: 121, hash: 'a' };
var sync = sandbox.stub(headerService, '_sync');
headerService._startSync();
expect(sync.calledOnce).to.be.true;
expect(headerService._numNeeded).to.equal(2);
expect(headerService._numNeeded).to.equal(8888);
});
});
@ -118,7 +119,7 @@ describe('Header Service', function() {
headerService._db = { batch: batch };
headerService._onHeaders(headers);
header.height = 1;
header.chainwork = '00000000000000000000000000000001';
header.chainwork = '0000000000000000000000000000000000000000000000000000000000000001';
expect(batch.calledOnce).to.be.true;
var expected = batch.args[0][0];

View File

@ -3,13 +3,16 @@
var expect = require('chai').expect;
var MempoolService = require('../../../lib/services/mempool');
var sinon = require('sinon');
var Encoding = require('../../../lib/services/block/encoding');
var Tx = require('bcoin').tx;
var Encoding = require('../../../lib/services/mempool/encoding');
var bcoin = require('bcoin');
var Tx = bcoin.tx;
var Block = bcoin.block;
describe('Mempool Service', function() {
var mempoolService;
var sandbox;
var block = Block.fromRaw('010000006a39821735ec18a366d95b391a7ff10dee181a198f1789b0550e0d00000000002b0c80fa52b669022c344c3e09e6bb9698ab90707bb4bb412af3fbf31cfd2163a601514c5a0c011c572aef0f0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08045a0c011c022003ffffffff0100f2052a01000000434104c5b694d72e601091fd733c6b18b94795c13e2db6b1474747e7be914b407854cad37cee3058f85373b9f9dbb0014e541c45851d5f85e83a1fd7c45e54423718f3ac00000000', 'hex');
var tx = Tx.fromRaw( '0100000004de9b4bb17f627096a9ee0b4528e4eae17df5b5c69edc29704c2e84a7371db29f010000006b483045022100f5b1a0d33b7be291c3953c25f8ae39d98601aa7099a8674daf638a08b86c7173022006ce372da5ad088a1cc6e5c49c2760a1b6f085eb1b51b502211b6bc9508661f9012102ec5e3731e54475dd2902326f43602a03ae3d62753324139163f81f20e787514cffffffff7a1d4e5fc2b8177ec738cd723a16cf2bf493791e55573445fc0df630fe5e2d64010000006b483045022100cf97f6cb8f126703e9768545dfb20ffb10ba78ae3d101aa46775f5a239b075fc02203150c4a89a11eaf5e404f4f96b62efa4455e9525765a025525c7105a7e47b6db012102c01e11b1d331f999bbdb83e8831de503cd52a01e3834a95ccafd615c67703d77ffffffff9e52447116415ca0d0567418a1a4ef8f27be3ff5a96bf87c922f3723d7db5d7c000000006b483045022100f6c117e536701be41a6b0b544d7c3b1091301e4e64a6265b6eb167b15d16959d022076916de4b115e700964194ce36a24cb9105f86482f4abbc63110c3f537cd5770012102ddf84cc7bee2d6a82ac09628a8ad4a26cd449fc528b81e7e6cc615707b8169dfffffffff5815d9750eb3572e30d6fd9df7afb4dbd76e042f3aa4988ac763b3fdf8397f80010000006a473044022028f4402b736066d93d2a32b28ccd3b7a21d84bb58fcd07fe392a611db94cdec5022018902ee0bf2c3c840c1b81ead4e6c87c88c48b2005bf5eea796464e561a620a8012102b6cdd1a6cd129ef796faeedb0b840fcd0ca00c57e16e38e46ee7028d59812ae7ffffffff0220a10700000000001976a914c342bcd1a7784d9842f7386b8b3b8a3d4171a06e88ac59611100000000001976a91449f8c749a9960dc29b5cbe7d2397cea7d26611bb88ac00000000', 'hex');
beforeEach(function() {
sandbox = sinon.sandbox.create();
@ -49,14 +52,14 @@ describe('Mempool Service', function() {
});
});
describe('#getTransaction', function() {
describe('#getMempoolTransaction', function() {
it('should get a transaction', function(done) {
it('should get a mempool transaction', function(done) {
var get = sandbox.stub().callsArgWith(1, null, tx.toJSON());
var key = sandbox.stub();
mempoolService._encoding = { encodeMempoolTransactionKey: key };
mempoolService._db = { get: get };
mempoolService.getTransaction(tx.hash, function(err, mytx) {
mempoolService.getMempoolTransaction(tx.hash, function(err, mytx) {
if(err) {
return done(err);
}
@ -70,28 +73,20 @@ describe('Mempool Service', function() {
describe('#_onTransaction', function() {
it('should add the transaction to the database', function() {
var key = sandbox.stub();
var value = sandbox.stub();
mempoolService._encoding = {
encodeMempoolTransactionKey: key,
encodeMempoolTransactionValue: value
};
var put = sandbox.stub();
mempoolService._db = { put: put };
mempoolService._onTransaction({});
expect(key.calledOnce).to.be.true;
expect(value.calledOnce).to.be.true;
mempoolService._onTransaction(tx);
expect(put.calledOnce).to.be.true;
});
});
describe('#_onBlock', function() {
it('should remove block\'s txs from database', function() {
var batch = sandbox.stub();
mempoolService._db = { batch: batch };
var block = { transactions: [ { id: 1 }, { id: 2 } ] };
mempoolService._onBlock(block);
expect(batch.calledOnce).to.be.true;
it('should remove block\'s txs from database', function(done) {
mempoolService.onBlock(block, function(err, ops) {
expect(ops[0].type).to.deep.equal('del');
expect(ops[0].key.toString('hex')).to.deep.equal('00006321fd1cf3fbf32a41bbb47b7090ab9896bbe6093e4c342c0269b652fa800c2b');
done();
});
});
});
});

View File

@ -1,114 +1,125 @@
'use strict';
var should = require('chai').should();
var bcoin = require('bcoin');
var Tx = bcoin.tx;
var Block = bcoin.block;
var sinon = require('sinon');
var TransactionService = require('../../../lib/services/transaction');
var levelup = require('levelup');
var TxService = require('../../../lib/services/transaction');
var Encoding = require('../../../lib/services/transaction/encoding');
describe('Transaction Index', function() {
describe('Transaction Service', function() {
var block = Block.fromRaw('010000006a39821735ec18a366d95b391a7ff10dee181a198f1789b0550e0d00000000002b0c80fa52b669022c344c3e09e6bb9698ab90707bb4bb412af3fbf31cfd2163a601514c5a0c011c572aef0f0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08045a0c011c022003ffffffff0100f2052a01000000434104c5b694d72e601091fd733c6b18b94795c13e2db6b1474747e7be914b407854cad37cee3058f85373b9f9dbb0014e541c45851d5f85e83a1fd7c45e54423718f3ac00000000', 'hex');
var tx = Tx.fromRaw( '0100000004de9b4bb17f627096a9ee0b4528e4eae17df5b5c69edc29704c2e84a7371db29f010000006b483045022100f5b1a0d33b7be291c3953c25f8ae39d98601aa7099a8674daf638a08b86c7173022006ce372da5ad088a1cc6e5c49c2760a1b6f085eb1b51b502211b6bc9508661f9012102ec5e3731e54475dd2902326f43602a03ae3d62753324139163f81f20e787514cffffffff7a1d4e5fc2b8177ec738cd723a16cf2bf493791e55573445fc0df630fe5e2d64010000006b483045022100cf97f6cb8f126703e9768545dfb20ffb10ba78ae3d101aa46775f5a239b075fc02203150c4a89a11eaf5e404f4f96b62efa4455e9525765a025525c7105a7e47b6db012102c01e11b1d331f999bbdb83e8831de503cd52a01e3834a95ccafd615c67703d77ffffffff9e52447116415ca0d0567418a1a4ef8f27be3ff5a96bf87c922f3723d7db5d7c000000006b483045022100f6c117e536701be41a6b0b544d7c3b1091301e4e64a6265b6eb167b15d16959d022076916de4b115e700964194ce36a24cb9105f86482f4abbc63110c3f537cd5770012102ddf84cc7bee2d6a82ac09628a8ad4a26cd449fc528b81e7e6cc615707b8169dfffffffff5815d9750eb3572e30d6fd9df7afb4dbd76e042f3aa4988ac763b3fdf8397f80010000006a473044022028f4402b736066d93d2a32b28ccd3b7a21d84bb58fcd07fe392a611db94cdec5022018902ee0bf2c3c840c1b81ead4e6c87c88c48b2005bf5eea796464e561a620a8012102b6cdd1a6cd129ef796faeedb0b840fcd0ca00c57e16e38e46ee7028d59812ae7ffffffff0220a10700000000001976a914c342bcd1a7784d9842f7386b8b3b8a3d4171a06e88ac59611100000000001976a91449f8c749a9960dc29b5cbe7d2397cea7d26611bb88ac00000000', 'hex');
var txService;
var sandbox;
describe('Failures', function() {
//if we miss indexing a tx, then this is very bad news. We have no good way of
//recursively retrieving inputValues, timestamp of its block, and block's height
it('should throw error if a transaction is not in the index', function(done) {
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
beforeEach(function() {
sandbox = sinon.sandbox.create();
txService = new TxService({
node: {
getNetworkName: function() { return 'regtest'; },
services: []
}
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
});
txService._encoding = new Encoding(new Buffer('0000', 'hex'));
});
service.encoding = { encodeTransactionKey: function() { return 'key'; }};
var tx = service.getTransaction('1234', {}, function(err, res) {
err.should.be.an.instanceof(Error);
err.message.should.equal('Transaction: 1234 not found in index');
afterEach(function() {
sandbox.restore();
});
describe('#start', function() {
it('should get the prefix and the service tip', function(done) {
var startSubs = sandbox.stub(txService, '_startSubscriptions');
var getPrefix = sandbox.stub().callsArgWith(1, null, new Buffer('ffee', 'hex'));
var getServiceTip = sandbox.stub().callsArgWith(1, null, { height: 1, hash: 'aa' });
txService._db = { getPrefix: getPrefix, getServiceTip: getServiceTip };
txService.start(function() {
startSubs.calledOnce.should.be.true;
getServiceTip.calledOnce.should.be.true;
getPrefix.calledOnce.should.be.true;
txService._encoding.should.be.instanceOf(Encoding);
done();
});
});
it('should search the mempool if opted for', function(done) {
var getTransaction = sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError());
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
}
},
mempool: {
getTransaction: getTransaction
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = { encodeTransactionKey: function() { return 'key'; }};
var tx = service.getTransaction('1234', { queryMempool: true }, function(err, res) {
err.should.be.an.instanceof(Error);
err.message.should.equal('Transaction: 1234 not found in index or mempool');
done();
});
describe('#stop', function() {
it('should stop the service', function(done) {
txService.stop(done);
});
});
describe('Success', function() {
it('should search main index', function(done) {
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, null, 'tx')
}
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = {
encodeTransactionKey: function() { return 'key'; },
decodeTransactionValue: function() { return 'value'; }
};
var tx = service.getTransaction('1234', {}, function(err, res) {
if(err) {
describe('#sendTransaction', function() {
it('should send a raw transaction', function(done) {
var sendTransaction = sandbox.stub().callsArg(0);
txService._p2p = { sendTransaction: sendTransaction };
txService.sendTransaction(function(err) {
if (err) {
return done(err);
}
res.should.equal('value');
done();
});
});
it('should search mempool', function(done) {
var missingInputs = sinon.stub().callsArgWith(1, null, 'tx');
var getTransaction = sinon.stub().callsArgWith(1, null, 'tx');
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
}
},
mempool: {
getTransaction: getTransaction
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = {
encodeTransactionKey: function() { return 'key'; }
};
service._getMissingInputValues = missingInputs;
var tx = service.getTransaction('1234', { queryMempool: true }, function(err, res) {
if(err) {
return done(err);
}
missingInputs.callCount.should.equal(1);
res.should.equal('tx');
done();
});
});
});
describe('#_cacheOutputValues', function() {
it('should cache output values', function() {
txService._cacheOutputValues(tx);
txService._inputValuesCache.get('25e28f9fb0ada5353b7d98d85af5524b2f8df5b0b0e2d188f05968bceca603eb').should.deep.equal([ 50000000000000, 113903300000000 ]);
});
});
describe('#_getBlockTimestamp', function() {
it('should get the block\'s timestamp', function() {
var getTimestamp = sandbox.stub().returns(1);
txService._timestamp = { getTimestampSync: getTimestamp };
var timestamp = txService._getBlockTimestamp('aa');
timestamp.should.equal(1);
});
});
describe('#onBlock', function() {
it('should process new blocks that come in from the block service', function(done) {
var getTimestamp = sandbox.stub().returns(1);
txService._timestamp = { getTimestampSync: getTimestamp };
var batch = sandbox.stub().callsArgWith(1, null);
txService._db = { batch: batch };
txService.onBlock(block, function(err, ops) {
txService._encoding.decodeTransactionKey(ops[0].key).should
.equal('6321fd1cf3fbf32a41bbb47b7090ab9896bbe6093e4c342c0269b652fa800c2b');
txService._encoding.decodeTransactionValue(ops[0].value).should
.be.instanceOf(Tx);
done();
});
});
});
describe('#_onReorg', function() {
it('should perform a reorg', function() {
var commonAncestorHeader = block.toHeaders().toJSON();
var oldList = [];
txService._tip = { height: 80000, hash: 'aa' };
var batch = sandbox.stub().callsArgWith(1, null);
txService._db = { batch: batch };
txService._onReorg(commonAncestorHeader, oldList);
batch.should.be.calledOnce;
batch.args[0][0][0].key.toString('hex').should.deep.equal('ffff7469702d756e646566696e6564');
batch.args[0][0][0].value.toString('hex').should.deep.equal('0000000000000000008ba8d6beb01577730fae52517988564322026e5e2d90a3ee5d3cfb');
});
});
describe('#_startSubscriptions', function() {
it('should start subscriptions', function() {
var on = sandbox.stub();
var subscribe = sandbox.stub();
txService._bus = { on: on, subscribe: subscribe };
txService._startSubscriptions();
on.should.be.calledOnce;
subscribe.should.be.calledOnce;
});
});
});

View File

@ -2,150 +2,124 @@
var should = require('chai').should();
var utils = require('../lib/utils');
var sinon = require('sinon');
describe('Utils', function() {
describe('#isHash', function() {
describe('#isHeight', function() {
it('false for short string', function() {
var a = utils.isHash('ashortstring');
a.should.equal(false);
it('should detect a height', function() {
utils.isHeight(12).should.be.true;
});
it('false for long string', function() {
var a = utils.isHash('00000000000000000000000000000000000000000000000000000000000000000');
a.should.equal(false);
});
it('false for correct length invalid char', function() {
var a = utils.isHash('z000000000000000000000000000000000000000000000000000000000000000');
a.should.equal(false);
});
it('false for invalid type (buffer)', function() {
var a = utils.isHash(new Buffer('abcdef', 'hex'));
a.should.equal(false);
});
it('false for invalid type (number)', function() {
var a = utils.isHash(123456);
a.should.equal(false);
});
it('true for hash', function() {
var a = utils.isHash('fc63629e2106c3440d7e56751adc8cfa5266a5920c1b54b81565af25aec1998b');
a.should.equal(true);
it('should detect a non-height', function() {
utils.isHeight('aaaaaa').should.be.false;
});
});
describe('#isSafeNatural', function() {
describe('#isAbsolutePath', function() {
it('false for float', function() {
var a = utils.isSafeNatural(0.1);
a.should.equal(false);
it('should detect absolute path', function() {
utils.isAbsolutePath('/').should.be.true;
});
it('false for string float', function() {
var a = utils.isSafeNatural('0.1');
a.should.equal(false);
});
it('false for string integer', function() {
var a = utils.isSafeNatural('1');
a.should.equal(false);
});
it('false for negative integer', function() {
var a = utils.isSafeNatural(-1);
a.should.equal(false);
});
it('false for negative integer string', function() {
var a = utils.isSafeNatural('-1');
a.should.equal(false);
});
it('false for infinity', function() {
var a = utils.isSafeNatural(Infinity);
a.should.equal(false);
});
it('false for NaN', function() {
var a = utils.isSafeNatural(NaN);
a.should.equal(false);
});
it('false for unsafe number', function() {
var a = utils.isSafeNatural(Math.pow(2, 53));
a.should.equal(false);
});
it('true for positive integer', function() {
var a = utils.isSafeNatural(1000);
a.should.equal(true);
});
});
describe('#startAtZero', function() {
it('will set key to zero if not set', function() {
var obj = {};
utils.startAtZero(obj, 'key');
obj.key.should.equal(0);
});
it('not if already set', function() {
var obj = {
key: 10
};
utils.startAtZero(obj, 'key');
obj.key.should.equal(10);
});
it('not if set to false', function() {
var obj = {
key: false
};
utils.startAtZero(obj, 'key');
obj.key.should.equal(false);
});
it('not if set to undefined', function() {
var obj = {
key: undefined
};
utils.startAtZero(obj, 'key');
should.equal(obj.key, undefined);
});
it('not if set to null', function() {
var obj = {
key: null
};
utils.startAtZero(obj, 'key');
should.equal(obj.key, null);
it('should not detect absolute path', function() {
utils.isAbsolutePath('.').should.be.false;
});
});
describe('#parseParamsWithJSON', function() {
it('will parse object', function() {
var paramsArg = ['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', '{"start": 100, "end": 1}'];
var params = utils.parseParamsWithJSON(paramsArg);
params.should.deep.equal(['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', {start: 100, end: 1}]);
});
it('will parse array', function() {
var paramsArg = ['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', '[0, 1]'];
var params = utils.parseParamsWithJSON(paramsArg);
params.should.deep.equal(['3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou', [0, 1]]);
});
it('will parse numbers', function() {
var paramsArg = ['3', 0, 'b', '0', 0x12, '0.0001'];
var params = utils.parseParamsWithJSON(paramsArg);
params.should.deep.equal([3, 0, 'b', 0, 0x12, 0.0001]);
it('should parse json params', function() {
utils.parseParamsWithJSON([ '{"test":"1"}', '{}', '[]' ])
.should.deep.equal([{test:'1'}, {}, []]);
});
});
describe('#getTerminalKey', function() {
it('should get the terminal key for a buffer', function() {
utils.getTerminalKey(new Buffer('ffff', 'hex'))
.should.deep.equal(new Buffer('010000', 'hex'));
});
it('should get the terminal key for a large buffer', function() {
utils.getTerminalKey(Buffer.concat([ new Buffer(new Array(64).join('f'), 'hex'), new Buffer('fe', 'hex') ]))
.should.deep.equal(new Buffer('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 'hex'));
});
});
describe('#diffTime', function() {
it('should get the difference in time in seconds', function(done) {
var time = process.hrtime();
setTimeout(function() {
var res = utils.diffTime(time);
res.should.be.greaterThan(0.1);
res.should.be.lessThan(0.5);
done();
}, 100);
});
});
describe('#sendError', function() {
it('should send a web-style error', function() {
var err = { statusCode: 500, message: 'hi there', stack: 'some stack' };
var status = sinon.stub().returnsThis();
var send = sinon.stub();
var res = { status: status, send: send };
utils.sendError(err, res);
send.should.be.calledOnce;
status.should.be.calledOnce;
status.args[0][0].should.equal(500);
send.args[0][0].should.equal('hi there');
});
it('should send a 503 in the case where there is no given status code', function() {
var err = { message: 'hi there', stack: 'some stack' };
var status = sinon.stub().returnsThis();
var send = sinon.stub();
var res = { status: status, send: send };
utils.sendError(err, res);
send.should.be.calledOnce;
status.should.be.calledOnce;
status.args[0][0].should.equal(503);
send.args[0][0].should.equal('hi there');
});
});
describe('#encodeTip', function() {
it('should encode tip', function() {
var res = utils.encodeTip({ height: 0xdeadbeef, hash: new Array(65).join('0') }, 'test');
res.should.deep.equal({
key: new Buffer('ffff7469702d74657374', 'hex'),
value: new Buffer('deadbeef00000000000000000000000000000000000000000000000000000000000000000', 'hex')
});
});
});
describe('#SimpleMap', function() {
var map = new utils.SimpleMap();
it('should build a simple map', function() {
map.should.be.instanceOf(Object);
});
it('should set a key and value', function() {
map.set('key', 'value');
map.getIndex(0).should.equal('value');
});
it('should get a value for key', function() {
map.get('key').should.equal('value');
});
it('should get a get a value at a specific index', function() {
map.getIndex(0).should.equal('value');
});
it('should get the last index', function() {
map.set('last key', 'last value');
map.getLastIndex().should.equal('last value');
});
});
});