intchains_ibctminer
Version:
```js const IntMiner = require('./src'); const Debug = require('./src/log')(); const fs = require('fs'); const COMP = '[SIPC]';
1,246 lines (1,012 loc) • 38.7 kB
JavaScript
/*jshint loopfunc:true,forin:false*/
;
var
expect = require('expect.js'),
stratum = require('../lib'),
sinon = require('sinon'),
_ = stratum.lodash,
EventEmitter = stratum.Base,
child_process;
function promisesArray(defers){
var out = [];
defers.forEach(function (t){
out.push(t.promise);
});
return out;
}
function createDefers(defers){
var out = [];
for (var i = 0; i < defers; i++) {
out.push(stratum.q.defer());
}
return {
promise: stratum.q.all(promisesArray(out)),
next: function(value){
if (defers === 0) {
throw new Error('Exceeded next calls');
}
out[--defers].resolve(value);
return out[defers].promise;
},
get current(){
return defers;
}
};
}
module.exports = {
Stratum: {
Base: {
'events': function (done){
var base = stratum.Base.$create();
base.on('event', function (arg){
expect(arg).to.equal(1);
done();
});
base.emit('event', 1);
}
},
Server: {
'inheritance from base': function (){
var server = stratum.Server.$create();
expect(server).to.be.ok();
expect(server.$instanceOf(stratum.Base)).to.equal(true);
expect(server.$instanceOf(stratum.Server)).to.equal(true);
},
'instance sets RPC server if in options': function(){
sinon.stub(stratum.RPCServer.prototype, 'expose', function(){});
var server = stratum.Server.$create({
rpc: {
port : 8080,
password: 'password'
}
});
expect(server.rpc.expose.callCount).to.be(4);
delete server.rpc;
expect(server.expose.bind(server, '')).to.throwException(/RPC is not enabled in the server/);
stratum.RPCServer.prototype.expose.restore();
},
'close socket connection': function(done){
var
socket = stratum.Client.$create(),
calls = 0,
id = socket.id,
server = stratum.Server.$create();
server.clients[id] = socket;
server.on('close', function(_id){
expect(_id).to.be(id);
if (calls === 0) {
socket = stratum.Client.$create();
id = socket.id;
}
if (calls++ === 1){
done();
} else {
server.closeConnection(socket);
}
});
server.closeConnection(socket);
},
'socket connection calls newConnection': function(done){
var server = stratum.Server.$create();
sinon.stub(server, 'newConnection', function(socket){
expect(socket).to.be(true);
done();
});
server.server.emit('connection', true);
},
'emits busy event when too much CPU': function(done){
sinon.stub(stratum, 'toobusy', function(){
return true;
});
var
server = stratum.Server.$create(),
socket = stratum.Client.$create();
server.on('busy', function(){
stratum.toobusy.restore();
done();
});
server.newConnection(socket);
},
'wraps net Socket in Client class on new connection': function(done){
var
socket = stratum.net.Socket(),
found = false,
server = stratum.Server.$create();
server.on('connection', function(_socket){
for (var uuid in server.clients) {
if (server.clients[uuid].socket === socket){
found = true;
break;
}
}
sinon.stub(server,'closeConnection', function(s){
expect(s).to.be(_socket);
_socket.socket.emit('data');
});
sinon.stub(server, 'handleData', function(){
expect('called').to.be('called');
done();
});
expect(found).to.be(true);
expect(_socket.byServer).to.be(true);
expect(_socket.socket).to.be(socket);
expect(_socket).to.be.a(stratum.Client);
_socket.emit('end');
});
server.newConnection(socket);
},
'getStratumCommands should parse the JSON string': function (){
var buffer = [
JSON.stringify({'jsonrpc': '2.0', 'method': 'authorize', 'params': [], 'id': 1}),
JSON.stringify({'jsonrpc': '2.0', 'method': 'subscribe', 'params': [], 'id': 2}),
'', null, JSON.stringify({'jsonrpc': '2.0', 'method': 'subscribe', 'params': [], 'id': 3})
];
expect(stratum.Server.getStratumCommands(new Buffer(buffer.join('\r\n')))).to.eql({string: buffer.join('\n'), cmds: [
buffer[0],
buffer[1],
buffer[4]
]});
},
'process commands on the server': function (done){
var
client = stratum.Client.$create(),
server = stratum.Server.$create(),
defers = createDefers(6),
cmd = '{"method":"mining.subscribe","params":[],"id":1}\n{"method":"mining.authorize","params":[],"id":1}\n',
cmds = stratum.Server.getStratumCommands(new Buffer(cmd));
sinon.stub(client, 'send');
server.on('mining', function (req, deferred, socket){
expect(socket).to.be(client);
expect(this).to.be(server);
if (/authorize|subscribe|set_difficulty/.test(req.method)) {
defers.next(req.method);
}
});
server.on('mining.error', function (error, socket){
expect(socket).to.be(client);
expect(error).to.match(/Client trying to reach a broadcast function|Stratum request without method or result field|Method not found/);
defers.next(error.toString());
});
stratum.Server.processCommands.call(
server,
client,
cmds.cmds
);
stratum.Server.processCommands.call(
server,
client,
stratum.Server.getStratumCommands(new Buffer('{"method":"mining.subscribe","params":[],"id":1}\n')).cmds
);
stratum.Server.processCommands.call(
server,
client,
stratum.Server.getStratumCommands(new Buffer('{"method":"mining.invalid","params":[],"id":1}\n')).cmds
);
stratum.Server.processCommands.call(
server,
client,
stratum.Server.getStratumCommands(new Buffer('{"method":"mining.set_difficulty","params":[],"id":1}\n')).cmds
);
stratum.Server.processCommands.call(
server,
client,
stratum.Server.getStratumCommands(new Buffer('{"jsonrpc":"2.0","params":[],"id":0}')).cmds
);
defers.promise.spread(function (err, broadcast, invalid, sub2, authorize, sub1){
expect(sub1).to.be('subscribe');
expect(authorize).to.be('authorize');
expect(sub2).to.be('subscribe');
expect(broadcast).to.match(/ Client trying to reach a broadcast function/);
expect(err).to.match(/Stratum request without method or result field/);
expect(invalid).to.match(/Method not found/);
server.removeAllListeners();
done();
});
},
'process commands on the client': function (done){
var
client = stratum.Client.$create(),
defers = createDefers(2),
cmd = new Buffer('{"result":true,"error":null,"id":1}\n{"result":false,"error":null,"id":2}\n'),
cmds = stratum.Server.getStratumCommands(cmd);
sinon.stub(client, 'send');
client.on('mining', function(req, socket, type){
expect(type).to.be('result');
expect(socket).to.be(client);
defers.next(req.result);
});
stratum.Server.processCommands.call(
client,
client,
cmds.cmds
);
defers.promise.done(function(res){
expect(res[0]).to.be(false);
expect(res[1]).to.be(true);
done();
});
},
'expose' : function(done){
var
ev = stratum.Base.$create(),
spy = sinon.spy(),
defers = createDefers(2),
f = stratum.Server.expose(ev, 'test');
ev.on('rpc', function(name, args, connection, d){
expect(this).to.be(ev);
expect(name).to.be('test');
if (defers.current === 2) {
expect(args).to.eql([1,2,3]);
d.resolve(['ok!']);
d.promise.then(function(){
expect(spy.lastCall.thisValue).to.be(ev);
expect(spy.lastCall.args).to.eql([null, ['ok!']]);
defers.next();
f([], {}, spy);
});
} else if (defers.current === 1) {
d.reject(['fail']);
d.promise.catch(function(){
expect(spy.lastCall.thisValue).to.be(ev);
expect(spy.lastCall.args).to.eql(['fail']);
defers.next();
});
}
});
f([1,2,3], {}, spy);
defers.promise.done(function(){
done();
});
},
'handle socket data': function (done){
var
client = stratum.Client.$create(),
server = stratum.Server.$create(),
cmd = new Buffer('{"method":"subscribe","params":[],"id":1}\n{"method":"authorize","params":[],"id":1}'),
cmds = stratum.Server.getStratumCommands(cmd),
defers = createDefers(3),
buf = new Buffer(['GET / HTTP/1.1', ''].join('\n'));
sinon.spy(stratum.Server, 'getStratumCommands');
sinon.stub(client, 'stratumHttpHeader', function (host, port){
expect(host).to.equal(server.opts.settings.hostname);
expect(port).to.equal(server.opts.settings.port);
return defers.next();
});
sinon.stub(server, 'closeConnection');
sinon.stub(stratum.Server, 'processCommands', function (){
var args = stratum.Server.processCommands.args[0];
expect(stratum.Server.processCommands.thisValues[0]).to.be(server);
expect(args[0]).to.be(client);
expect(args[1]).to.eql(cmds.cmds);
defers.next();
});
server.handleData(client, buf); // HTTP
server.handleData(client, cmd); // Stratum
server.handleData(client, ' '); // Empty
server.handleData(client, new Buffer('\x10\x19\x18\x10\x00\x00\x00\x12')); // Garbage
server.handleData(client, new Buffer(0)); // really empty
defers.promise.done(function (){
expect(stratum.Server.getStratumCommands.callCount).to.equal(5);
stratum.Server.processCommands.restore();
stratum.Server.getStratumCommands.restore();
done();
});
},
'listen on selected port and close': function(done){
var
opts = {
settings: {
port: 8080,
host: 'localhost'
}
},
server = stratum.Server.$create(opts);
server.rpc = new sinon.createStubInstance(stratum.RPCServer);
sinon.stub(server.server, 'listen', function(port, host, cb){
expect(port).to.be(opts.settings.port);
expect(host).to.be(opts.settings.host);
cb();
});
sinon.stub(server.server, 'close', function(){});
server.listen().done(function(){
expect(server.rpc.listen.called).to.be(true);
server.daemons = {
'dummy': sinon.stub({'close': function(){}})
};
server.close();
expect(server.server.close.called).to.be(true);
expect(server.daemons.dummy.close.called).to.be(true);
done();
});
},
'send to id': function(done){
var
number = 0,
server = stratum.Server.$create(),
client = stratum.Client.$create();
server.clients[client.id] = client;
server.sendToId().catch(function(err){
number++;
expect(err).to.be('sendToId command doesnt exist "undefined"');
})
.then(function(){
return server.sendToId(null, 'doesnt');
})
.catch(function(err){
number++;
expect(err).to.be('sendToId command doesnt exist "doesnt"');
})
.then(function(){
return server.sendToId('invalidid', 'subscribe');
})
.catch(function(err){
number++;
expect(err).to.be('sendToId socket id not found "invalidid"');
})
.then(function(){
sinon.stub(client, 'stratumSend', function(){
return stratum.q.resolve('done');
});
return server.sendToId(client.id, 'subscribe', ['difficulty', 'subscription', 'extranonce1', 'extranonce2_size']);
})
.done(function(command){
expect(command).to.be('done');
expect(number).to.be(3);
done();
});
},
'bindCommand': function (done){
var
client = stratum.Client.$create(),
functions = Object.keys(stratum.Server.commands),
defers = [], f,
size = functions.length,
spy = sinon.spy(stratum.Server, 'rejected');
stratum.Server.commands.subscribe().catch(function(err){
expect(err).to.be('No ID provided');
}).done();
client.subscription = true;
sinon.stub(client, 'stratumSend', function (opts, bypass){
return stratum.q.resolve({
opts : opts,
bypass: bypass
});
});
for (var i = 0; i < size; i++) {
f = stratum.Server.bindCommand(client, functions[i], 'asdf');
//console.log(functions[i], f);
defers.push(f());
}
stratum.q.all(defers).catch(function (err){
//console.log(err);
}).done(function (){
expect(spy.callCount).to.equal(size + 1);
stratum.Server.rejected.restore();
done();
});
},
'addDaemon throws': function() {
var server = stratum.Server.$create();
expect(server.addDaemon.bind(server, {})).to.throwException(/addDaemon expects a full daemon configuration object/);
var dummy = {'name':'bitcoin','user':' ','password':' ','host':' ', 'port': ' '};
server.addDaemon(dummy);
expect(function(){
server.addDaemon(dummy);
}).to.throwException(/daemon already included "bitcoin"/);
expect(Object.keys(server.daemons)).to.have.length(1);
},
'broadcast': function(done){
var
i = 0, server = new stratum.Server(), events = {connection: 0};
server.broadcast('set_difficulty',['asdf']).catch(function(err){
expect(err).to.be('No clients connected');
server.on('connection', function(s){
events.connection++;
s.on('mining', function(){
//console.log(arguments);
});
});
while(i++ < 10) {
var client = new stratum.net.Socket();
server.newConnection(client);
}
for(var id in server.clients) {
sinon.stub(server.clients[id], 'send', function(cli){
return stratum.q.resolve(cli);
}.bind(server.clients[id]));
}
server.broadcast().catch(function(err){
expect(err).to.be('Missing type and data array parameters');
return server.broadcast('set_difficulty');
}).catch(function(err){
expect(err).to.be('Missing type and data array parameters');
return server.broadcast('subscribe', ['asdf']);
}).catch(function(err){
expect(err).to.be('Invalid broadcast type "subscribe"');
return stratum.q.all([
server.broadcast('set_difficulty', ['asdf']),
server.broadcast('notify', ['asdf','adf','asdf','asdf','adf','adsf','adsf','asdf','asdf'])
]);
}).done(function(results){
expect(results[0]).to.equal(i-1);
expect(results[1]).to.equal(i-1);
expect(events.connection).to.equal(i-1);
done();
});
});
}
},
Client: {
'accepts existing socket': function(){
var socket = new stratum.net.Socket();
expect(stratum.Client.createSocket(socket)).to.be(socket);
},
'setLastActivity': function(done){
var client = new stratum.Client();
client.setLastActivity();
setTimeout(function(){
expect(client.lastActivity).to.be.lessThan(Date.now());
client.setLastActivity(1);
expect(client.lastActivity).to.be(1);
done();
}, 0);
},
'events emitted from underlaying socket': function(done){
var
client = new stratum.Client(),
defers = createDefers(3),
cb, socket = client.socket;
cb = function(self){
defers.next(self);
};
client.on('drain', cb);
client.on('end', cb);
client.on('error', cb);
socket.emit('drain');
socket.emit('end');
socket.emit('error');
// destroy the client, but the socket is alive and bound, shouldn't throw
client.$destroy();
socket.emit('drain');
socket.emit('end');
socket.emit('error');
defers.promise.spread(function(drain, end, error){
expect(drain).to.be(client);
expect(end).to.be(client);
expect(error).to.be(client);
done();
});
}
},
ClientServer: {
'built in commands': function(done){
var
socket = new (require('stream')).PassThrough(),
client, defers = createDefers(6),
server = new stratum.Server();
socket.setNoDelay = function(){};
socket.setKeepAlive = function(){};
server.on('connection', function(s){
client = s;
client.on('mining', function(req, cli, type, method){
defers.next(method);
//console.log('client', req, type, method);
switch (method) {
case 'subscribe':
expect(req.result).to.eql([[
['mining.set_difficulty', 'a'],
['mining.notify', 'b']
],
'c',
'd'
]);
expect(cli.authorized).to.be(false);
s.stratumAuthorize('user', 'pass');
break;
case 'authorize':
expect(req.result).to.be(true);
expect(cli.authorized).to.be(true);
s.stratumSubmit('a','b','c','d','f');
break;
case 'submit':
expect(req.result).to.be(true);
break;
}
});
client.on('mining.error', function(err){
//console.log('client.error', err);
});
s.stratumSubscribe('Test');
});
server.on('mining', function(req, res){
//console.log('server', req);
defers.next(req.method);
switch (req.method) {
case 'subscribe':
expect(req.params).to.eql(['Test']);
res.resolve(['a','b','c','d']);
break;
case 'authorize':
expect(req.params).to.eql(['user','pass']);
res.resolve([true]);
break;
case 'submit':
expect(req.params).to.eql(['a', 'b', 'c', 'd', 'f' ]);
res.resolve([true]);
break;
}
});
server.on('mining.error', function(err){
//console.log('server.error', err);
});
server.newConnection(socket);
defers.promise.spread(function(){
done();
});
}
},
RPC: {
before: function (){
// password = 123 = a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
this.opts = {port: 9999, password: 'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3'};
},
'default opts': function (){
var rpc = stratum.RPCServer.$create(this.opts);
expect(rpc.opts).to.eql({
'mode' : 'tcp',
'port' : 9999,
'host' : 'localhost',
'password': 'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3'
});
},
'missing required parameters': function (){
expect(function (){
stratum.RPCServer.$create();
}).to.throwError(/Port must be set/);
expect(function (){
stratum.RPCServer.$create({port: 9999});
}).to.throwError(/Password must be set/);
},
'malformed base64 password': function (){
var rpc = stratum.RPCServer.$create(this.opts);
expect(rpc._password('9s7w45fcsaplw735gfal')).to.equal(false);
},
'working base64 password': function (){
var rpc = stratum.RPCServer.$create(this.opts);
// YmFzZTY0 = base64
expect(rpc._password('YmFzZTY0')).to.equal('371a286d5872a3730d644327581546ec3e658bbf1a3c7f7f0de2bc19905d4402');
},
'authentication': function (){
var rpc = stratum.RPCServer.$create(this.opts),
cb = sinon.spy(),
Context = sinon.stub({
'exposed': function (){ return true; }
});
var exposed = rpc._authenticate('test', Context.exposed, Context);
cb.reset();
exposed([true, 1], {}, cb);
expect(cb.calledWith('No password provided')).to.equal(true);
cb.reset();
exposed(['YmFzZTY0', 1], {}, cb);
expect(cb.calledWith('Unauthorized access')).to.equal(true);
// MTIz = 123
cb.reset();
exposed(['MTIz', 1], {}, cb);
expect(Context.exposed.calledOn(Context)).to.equal(true);
expect(Context.exposed.calledWith([1], {}, cb)).to.equal(true);
expect(cb.called).to.equal(false);
},
'no context': function (){
var
rpc = stratum.RPCServer.$create(this.opts),
cb = sinon.spy();
rpc.$import({
testing: function (){
return true;
}
});
sinon.spy(rpc, 'testing');
var exposed = rpc._authenticate('test', rpc.testing);
exposed(['MTIz', '1', 2], {}, cb);
expect(cb.called).to.be(false);
expect(rpc.testing.called).to.be(true);
expect(rpc.testing.calledWith(['1', 2], {}, cb)).to.be(true);
},
'already listening exception': function (){
var server = stratum.RPCServer.$create(this.opts);
server._server = true;
expect(function (){
server.listen();
}).to.throwException(/Server already listening on port 9999/);
},
'tcp RPC command': function (done){
var server = stratum.RPCServer.$create(this.opts),
exposed = {
'func': function (args, opts, callback){
callback(null, args);
}
},
spy = sinon.spy(exposed, 'func'),
bound = {_server: null},
client = stratum.rpc.Client.$create(server.opts.port, 'localhost');
expect(stratum.RPCServer.prototype.close.bind(bound)()).to.be(bound);
server.expose('func', exposed.func, exposed).listen();
client.connectSocket(function (err, conn){
conn.call('func', ['MTIz', 1, 2], function (err, result){
expect(result).to.eql([1, 2]);
expect(spy.calledWith([1, 2])).to.equal(true);
server.close();
done();
});
});
},
'http RPC command': function (done){
var server = stratum.RPCServer.$create(_.defaults({mode: 'http'}, this.opts)),
exposed = {
'func': function (args, opts, callback){
callback(null, args);
}
},
spy = sinon.spy(exposed, 'func'),
client = stratum.rpc.Client.$create(server.opts.port, 'localhost');
server.expose('func', exposed.func, exposed).listen();
client.call('func', ['MTIz', 1, 2], function (err, result){
expect(result).to.eql([1, 2]);
expect(spy.calledWith([1, 2])).to.equal(true);
server.close();
done();
});
},
'TCP/HTTP RPC command': function (done){
var server = stratum.RPCServer.$create(_.defaults({mode: 'both'}, this.opts)),
exposed = {
'func': function (args, opts, callback){
callback(null, args);
}
},
spy = sinon.spy(exposed, 'func'),
client = stratum.rpc.Client.$create(server.opts.port, 'localhost');
server.expose('func', exposed.func, exposed).listen();
client.connectSocket(function (err, conn){
conn.call('func', ['MTIz', 1, 2], function (err, result){
expect(result).to.eql([1, 2]);
expect(spy.calledWith([1, 2])).to.equal(true);
client.call('func', ['MTIz', 1, 2], function (err, result){
expect(result).to.eql([1, 2]);
expect(spy.calledWith([1, 2])).to.equal(true);
server.close();
done();
});
});
});
}
},
Daemon: {
before: function (){
child_process = function (){
var em = new EventEmitter();
em.kill = sinon.spy();
return em;
};
},
'creation exceptions': function (){
expect(function (){
stratum.Daemon.$create();
}).to.throwError(/Daemon options must not be empty/);
expect(function (){
stratum.Daemon.$create({path: '//', port: 8080});
}).to.throwError(/Daemon must have options "user, password, port, host, name" set, there are no defaults/);
expect(function (){
stratum.Daemon.$create({
path : '/doesnt/exist/%s',
datadir : 'data/dir',
port : 8080,
host : 'localhost',
user : 'user',
password: 'pass',
name : 'Mycoin'
}).start();
}).to.throwError(/Provided daemon "\/doesnt\/exist\/%s" path doesnt exist/);
expect(function (){
stratum.Daemon.$create({
path : '/doesnt/exist/%s',
port : 8080,
host : 'localhost',
user : 'user',
password: 'pass',
name : 'Mycoin'
}).start();
}).to.throwError(/The option "datadir" must be set to the place your wallet.dat is set./);
},
'notify args builder': function (){
var obj = {
'port' : 8080,
'host' : 'localhost',
'user' : 'rpcuser',
'datadir' : 'data/dir',
'password' : 'bitcoindpassword',
'name' : 'Bitcoin',
'rpcserver': {
'port' : 8888,
'host' : 'localhost',
'password' : 'rpcpassword',
'notify' : ['wallet', 'alert', 'block'],
'notifyPath': 'stratum-notify'
},
'args' : [
{'blockminsize': 1000},
{'blockmaxsize': 250000},
'testnet',
'upnp'
]
};
expect(stratum.Daemon.notify(obj)).to.eql([
{ walletnotify: '"stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type wallet --data %s"' },
{ alertnotify: '"stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type alert --data %s"' } ,
{ blocknotify: '"stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type block --data %s"' }
]);
},
'args creation from options': function (){
var daemon = new stratum.Daemon({
'port' : 8080,
'datadir' : 'data/dir',
'host' : 'localhost',
'user' : 'rpcuser',
'password': 'bitcoindpassword',
'name' : 'Bitcoin',
'args' : 'invalid args, must be array'
});
expect(daemon.opts.args).to.eql([]);
},
'arguments helper': function (){
var obj = {
'port' : 8080,
'host' : 'localhost',
'user' : 'rpcuser',
'datadir' : 'data/dir',
'password': 'rpcpassword',
'name' : 'Bitcoin',
'args' : [
{'blockminsize': 1000},
{'blockmaxsize': 250000},
'testnet',
'upnp',
'-argstartingwithdash',
1,
{'-objargwithdash': true}
]
};
expect(stratum.Daemon.mountArgs(obj)).to.eql([
'-blockminsize=1000',
'-blockmaxsize=250000',
'-testnet',
'-upnp',
'-argstartingwithdash',
'-objargwithdash=true'
]);
},
'arguments and notify': function (){
var obj = {
'port' : 8080,
'host' : 'localhost',
'user' : 'rpcuser',
'datadir' : 'data/dir',
'password' : 'rpcpassword',
'name' : 'Bitcoin',
'rpcserver': {
'port' : 8888,
'host' : 'localhost',
'password' : 'rpcpassword',
'notify' : ['wallet', 'alert', 'block'],
'notifyPath': 'stratum-notify'
},
'args' : [
{'blockminsize': 1000},
{'blockmaxsize': 250000},
'testnet',
'upnp'
]
};
stratum.Daemon.notify(obj);
expect(stratum.Daemon.mountArgs(obj)).to.eql([
'-blockminsize=1000',
'-blockmaxsize=250000',
'-testnet',
'-upnp',
'-walletnotify="stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type wallet --data %s"',
'-alertnotify="stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type alert --data %s"',
'-blocknotify="stratum-notify --source Bitcoin --password rpcpassword --host localhost --port 8888 --type block --data %s"'
]);
},
'throws on invalid path': function(){
expect(stratum.Daemon.prototype._pathExists.bind({opts: {path:true}})).to.throwException();
expect(stratum.Daemon.prototype._pathExists.bind({opts: {path:__filename}})).to.not.throwException();
},
'close': function (done){
var clock = sinon.useFakeTimers();
var daemon = stratum.Daemon.$create({
path : '/doesnt/exist/%s',
port : 8080,
host : 'localhost',
datadir : 'data/dir',
user : 'user',
password: 'pass',
name : 'Mycoin'
});
sinon.stub(daemon, '_pathExists', function (){ return true; });
sinon.stub(daemon.rpc, 'call', function (name, params, callback){
if (daemon.callerror === true) {
callback('error');
} else {
callback(null, 'success');
}
});
expect(daemon._pathExists).to.not.throwException();
daemon.close().catch(function (message){
expect(message).to.be('Process wasnt started');
}).done();
var child = child_process();
daemon.process = child;
expect(daemon.start()).to.be(false);
var promise = daemon.close();
clock.tick(5000); // make the timeout be met
promise.catch(function (message){
expect(message).to.be('Process didnt respond and was killed');
daemon.process = child;
expect(child.kill.called).to.be(true);
child.kill.reset();
}).done(function (){
promise = daemon.close(1);
clock.tick(1000);
promise.catch(function (message){
expect(message).to.be('Process didnt respond and was killed');
expect(child.kill.called).to.be(true);
daemon.process = child;
child.kill.reset();
}).done(function (){
daemon.close().done(function (){
expect(daemon.process).to.be(null);
daemon.callerror = true;
daemon.process = child;
daemon.close().catch(function (message){
expect(message).to.be('error');
}).done(function (){
clock.restore();
done();
});
});
});
});
},
'failed RPC call': function (done){
var clock = sinon.useFakeTimers();
var daemon = stratum.Daemon.$create({
path : '/doesnt/exist/%s',
datadir : 'data/dir',
port : 8080,
host : 'localhost',
user : 'user',
password: 'pass',
name : 'Mycoin'
});
sinon.stub(daemon.rpc, 'call', function (name, params, callback){
if (name === 'test') {
callback('error');
}
});
daemon.call('test').catch(function (message){
expect(message).to.equal('error');
}).done(function (){
var promise = daemon.call('timeout');
clock.tick(4000);
promise.catch(function (message){
expect(message).to.be('Command timed out');
}).done(function (){
clock.restore();
done();
});
});
},
'RPC server args': function (){
sinon.spy(stratum.Daemon, 'notify');
var opts = {
path : '/doesnt/exist/%s',
port : 8080,
host : 'localhost',
user : 'user',
datadir : 'data/dir',
password : 'pass',
'rpcserver': {
'port' : 8888,
'host' : 'localhost',
'password' : 'rpcpassword',
'notify' : ['wallet', 'alert', 'block'],
'notifyPath': 'stratum-notify'
},
name : 'Mycoin'
},
daemon = stratum.Daemon.$create(opts);
expect(stratum.Daemon.notify.called).to.be(true);
expect(daemon.opts.rpcserver.notifyPath).to.equal('stratum-notify');
stratum.Daemon.notify.reset();
delete opts.rpcserver.notifyPath;
daemon = stratum.Daemon.$create(opts);
expect(daemon.opts.rpcserver.notifyPath).to.equal(stratum.path.join('..', 'bin', 'stratum-notify'));
stratum.Daemon.notify.reset();
delete opts.rpcserver.notify;
daemon = stratum.Daemon.$create(opts);
expect(stratum.Daemon.notify.called).to.be(false);
expect(daemon.opts.rpcserver.notify).to.eql([]);
stratum.Daemon.notify.restore();
expect(stratum.Daemon.notify()).to.eql([]);
expect(stratum.Daemon.notify({rpcserver:{}})).to.eql([]);
},
'spawn daemon': function (done){
var invalid = 1, daemon = stratum.Daemon.$create({
path : '/doesnt/exist/%s',
port : 8080,
datadir : 'data/dir',
host : 'localhost',
user : 'user',
password: 'pass',
name : 'Mycoin',
args : [
'one',
'two',
invalid
]
});
var child = child_process();
sinon.stub(daemon, '_pathExists', function (){ return true; });
sinon.stub(daemon, 'spawn', function (){ return child; });
expect(daemon.start()).to.be(true);
expect(daemon.spawn.calledWith(
'/doesnt/exist/%s',
[ '-one',
'-two',
'-daemon',
'-rpcuser=user',
'-rpcpassword=pass',
'-rpcport=8080',
'-datadir=data/dir' ]
)).to.be(true);
expect(daemon.process).to.be(child);
daemon.process.on('close', function (){
expect(daemon.process).to.equal(null);
daemon.spawn.restore();
sinon.stub(daemon, 'spawn', function (){ throw new Error('failed to create process'); });
expect(daemon.start()).to.be(false);
done();
});
daemon.process.emit('close');
},
'RPC communication': function (done){
var
daemon = stratum.Daemon.$create({
port : 59881,
host : 'localhost',
datadir : 'data/dir',
user : 'user',
password: 'pass',
name : 'Communicoin'
})
;
sinon.stub(daemon.rpc, 'call', function (args, opts, callback){
expect(opts).to.eql([
{dummy: true}
]);
callback(null, 1);
});
daemon.call('getdifficulty', [
{dummy: true}
]).done(function (res){
expect(res).to.equal(1);
daemon.call('getdifficulty', {dummy: true}).then(function (res){
expect(res).to.equal(1);
done();
}).done();
});
}
}
}
};