UNPKG

bitcoind-rpc

Version:

Bitcoin Client Library to connect to Bitcoin Core via RPC

539 lines (452 loc) 13.7 kB
'use strict'; var chai = require('chai'); var RpcClient = require('../'); var util = require('util'); var EventEmitter = require('events').EventEmitter; var sinon = require('sinon'); var should = chai.should(); var http = require('http'); var https = require('https'); var async = require('async'); if(!setImmediate) setImmediate = setTimeout; describe('RpcClient', function() { it('should initialize the main object', function() { should.exist(RpcClient); }); it('should be able to create instance', function() { var s = new RpcClient(); should.exist(s); }); it('default to rejectUnauthorized as true', function() { var s = new RpcClient(); should.exist(s); s.rejectUnauthorized.should.equal(true); }); it('should be able to define a custom logger', function() { var customLogger = { info: function(){}, warn: function(){}, err: function(){}, debug: function(){} }; RpcClient.config.log = customLogger; var s = new RpcClient(); s.log.should.equal(customLogger); RpcClient.config.log = false; }); it('should be able to define the logger to normal', function() { RpcClient.config.logger = 'normal'; var s = new RpcClient(); s.log.should.equal(RpcClient.loggers.normal); }); it('should be able to define the logger to none', function() { RpcClient.config.logger = 'none'; var s = new RpcClient(); s.log.should.equal(RpcClient.loggers.none); }); function FakeResponse(){ EventEmitter.call(this); } util.inherits(FakeResponse, EventEmitter); function FakeRequest(){ EventEmitter.call(this); return this; } util.inherits(FakeRequest, EventEmitter); FakeRequest.prototype.setHeader = function() {}; FakeRequest.prototype.write = function(data) { this.data = data; }; FakeRequest.prototype.end = function() {}; it('should use https', function() { var client = new RpcClient({ user: 'user', pass: 'pass', port: 8332, }); client.protocol.should.equal(https); }); it('should use http', function() { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, protocol: 'http' }); client.protocol.should.equal(http); }); it('should accept URL', function() { var client = new RpcClient('http://abc:def@ghi.xyz:1337'); client.protocol.should.equal(http); client.host.should.equal('ghi.xyz'); client.port.should.equal(1337); client.user.should.equal('abc'); client.pass.should.equal('def'); }); it('should call a method and receive response', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); var req = new FakeRequest(); setImmediate(function(){ res.emit('data', '{}'); res.emit('end'); }); callback(res); return req; }); client.setTxFee(0.01, function(error, parsedBuf) { requestStub.restore(); should.not.exist(error); should.exist(parsedBuf); done(); }); }); it('accept many values for bool', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: false }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); var req = new FakeRequest(); setImmediate(function(){ res.emit('data', req.data); res.emit('end'); }); callback(res); return req; }); async.eachSeries([true, 'true', 1, '1', 'True'], function(i, next) { client.importAddress('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', '', i, function(error, parsedBuf) { should.not.exist(error); should.exist(parsedBuf); parsedBuf.params[2].should.equal(true); next(); }); }, function(err) { requestStub.restore(); done(); }); }); it('should process object arguments', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: false }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); var req = new FakeRequest(); setImmediate(function(){ res.emit('data', req.data); res.emit('end'); }); callback(res); return req; }); var obj = {'n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X': 1}; async.eachSeries([obj, JSON.stringify(obj)], function(i, next) { client.sendMany('account', i, function(error, parsedBuf) { should.not.exist(error); should.exist(parsedBuf); parsedBuf.params[1].should.have.property('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', 1); next(); }); }, function(err) { requestStub.restore(); done(); }); }); it('should batch calls for a method and receive a response', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: false }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); setImmediate(function(){ res.emit('data', '[{}, {}, {}]'); res.emit('end'); }); callback(res); return new FakeRequest(); }); client.batchedCalls = []; client.listReceivedByAccount(1, true); client.listReceivedByAccount(2, true); client.listReceivedByAccount(3, true); client.batchedCalls.length.should.equal(3); client.batch(function(){ // batch started }, function(error, result){ // batch ended requestStub.restore(); should.not.exist(error); should.exist(result); result.length.should.equal(3); done(); }); }); it('should handle connection rejected 401 unauthorized', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); res.statusCode = 401; setImmediate(function(){ res.emit('end'); }); callback(res); return new FakeRequest(); }); client.getBalance('n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X', 6, function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Connection Rejected: 401 Unnauthorized'); done(); }); }); it('should handle connection rejected 401 forbidden', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); res.statusCode = 403; setImmediate(function(){ res.emit('end'); }); callback(res); return new FakeRequest(); }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Connection Rejected: 403 Forbidden'); done(); }); }); it('should handle 500 work limit exceeded error', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); res.statusCode = 500; setImmediate(function(){ res.emit('data', 'Work queue depth exceeded'); res.emit('end'); }); callback(res); return new FakeRequest(); }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Work queue depth exceeded'); done(); }); }); it('should handle EPIPE error case 1', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var req = new FakeRequest(); setImmediate(function(){ req.emit('error', new Error('write EPIPE')); }); var res = new FakeResponse(); setImmediate(function(){ res.emit('data', '{}'); res.emit('end'); }); callback(res); return req; }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Request Error: write EPIPE'); done(); }); }); it('should handle EPIPE error case 2', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); setImmediate(function(){ res.emit('data', '{}'); res.emit('end'); }); var req = new FakeRequest(); setImmediate(function(){ req.emit('error', new Error('write EPIPE')); }); callback(res); req.on('error', function(err) { requestStub.restore(); done(); }); return req; }); client.getDifficulty(function(error, parsedBuf) {}); }); it('should handle ECONNREFUSED error', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); var req = new FakeRequest(); setImmediate(function(){ req.emit('error', new Error('connect ECONNREFUSED')); }); callback(res); return req; }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Request Error: connect ECONNREFUSED'); done(); }); }); it('should callback with error if invalid json', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); setImmediate(function(){ res.emit('data', 'not a json string'); res.emit('end'); }); var req = new FakeRequest(); callback(res); return req; }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Error Parsing JSON: Unexpected token o in JSON at position 1'); done(); }); }); it('should callback with error if blank response', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ var res = new FakeResponse(); setImmediate(function(){ res.emit('data', ''); res.emit('end'); }); var req = new FakeRequest(); callback(res); return req; }); client.getDifficulty(function(error, parsedBuf) { requestStub.restore(); should.exist(error); error.message.should.equal('Bitcoin JSON-RPC: Error Parsing JSON: Unexpected end of JSON input'); done(); }); }); it('should add additional http options', function(done) { var client = new RpcClient({ user: 'user', pass: 'pass', host: 'localhost', port: 8332, rejectUnauthorized: true, disableAgent: true }); client.httpOptions = { port: 20001 }; var calledPort = false; var requestStub = sinon.stub(client.protocol, 'request', function(options, callback){ calledPort = options.port; var res = new FakeResponse(); setImmediate(function(){ res.emit('data', '{}'); res.emit('end'); }); var req = new FakeRequest(); callback(res); return req; }); client.getDifficulty(function(error, parsedBuf) { should.not.exist(error); should.exist(parsedBuf); calledPort.should.equal(20001); requestStub.restore(); done(); }); }); });