From 0481cf8e025de4e9d65863e9f3751f4d5d0ff468 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 19 Jun 2014 00:17:46 -0300 Subject: [PATCH 1/2] fixes POST request in node --- js/models/blockchain/Insight.js | 172 ++++++++++++++++++-------------- test/test.blockchain.Insight.js | 115 ++++++++++++++------- 2 files changed, 176 insertions(+), 111 deletions(-) diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index 897dd22c8..060863cb6 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -3,6 +3,11 @@ var imports = require('soop').imports(); var bitcore = require('bitcore'); +var http; +if (process.version) { + http = require('http'); +}; + function Insight(opts) { opts = opts || {}; this.host = opts.host || 'localhost'; @@ -130,7 +135,6 @@ Insight.prototype.getUnspent = function(addresses, cb) { return cb(err); } - if (res && res.length > 0) { all = all.concat(res); } @@ -159,95 +163,111 @@ Insight.prototype.sendRawTransaction = function(rawtx, cb) { }); }; -Insight.prototype._request = function(options, callback) { - - - var self = this; - if (typeof process === 'undefined' || !process.version) { - var request = new XMLHttpRequest(); - - // TODO: Normalize URL - var url = 'http://' + options.host; - - if (options.port !== 80) { - url = url + ':' + options.port; - } - - url = url + options.path; - - if (options.data && options.method === 'GET') { - url = url + '?' + options.data; - } - - request.open(options.method, url, true); - request.timeout = 5000; - request.ontimeout = function() { - setTimeout(function() { - return self._request(options, callback); - }, self.retryDelay); - return callback(new Error('Insight request timeout')); +Insight.prototype._requestNode = function(options, callback) { + if (options.method === 'POST') { + options.headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': options.data.length, }; + } - request.onreadystatechange = function() { - if (request.readyState !== 4) return; - var ret, errTxt, e; - - if (request.status === 200 || request.status === 304) { + var req = http.request(options, function(response) { + var ret, errTxt, e; + if (response.statusCode == 200 || response.statusCode === 304) { + response.on('data', function(chunk) { try { - ret = JSON.parse(request.responseText); + ret = JSON.parse(chunk); } catch (e2) { errTxt = 'CRITICAL: Wrong response from insight' + e2; } - } else if (request.status >= 400 && request.status < 499) { - errTxt = 'CRITICAL: Bad request to insight. Probably wrong transaction to broadcast?.'; - } else { - errTxt = 'Error code: ' + request.status + ' - Status: ' + request.statusText + ' - Description: ' + request.responseText; - setTimeout(function() { - console.log('### Retrying Insight Request....'); - return self._request(options, callback); - }, self.retryDelay); - } + }); + } else { + errTxt = "INSIGHT ERROR:" + response.statusCode; + console.log(errTxt); + e = new Error(errTxt); + return callback(e); + } + response.on('end', function() { if (errTxt) { - console.log("INSIGHT ERROR:", e); + console.log("INSIGHT ERROR:" + errTxt); e = new Error(errTxt); } return callback(e, ret); - }; - - if (options.method === 'POST') { - request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - } - - request.send(options.data || null); - } else { - var http = require('http'); - var req = http.request(options, function(response) { - var ret; - if (response.statusCode == 200 || response.status === 304) { - response.on('data', function(chunk) { - try { - ret = JSON.parse(chunk); - } catch (e) { - return callback({ - message: 'Wrong response from insight' - }); - } - }); - response.on('end', function() { - return callback(null, ret); - }); - } else { - return callback({ - message: 'Error ' + response.statusCode - }); - } }); + response.on('error', function(e) { + return callback(e, ret); + }); + }); - if (options.data) { - req.write(options.data); + if (options.data) { + req.write(options.data); + } + req.end(); +}; + +Insight.prototype._requestBrowser = function(options, callback) { + var request = new XMLHttpRequest(); + + // TODO: Normalize URL + var url = 'http://' + options.host; + + if (options.port !== 80) { + url = url + ':' + options.port; + } + + url = url + options.path; + + if (options.data && options.method === 'GET') { + url = url + '?' + options.data; + } + + request.open(options.method, url, true); + request.timeout = 5000; + request.ontimeout = function() { + setTimeout(function() { + return self._request(options, callback); + }, self.retryDelay); + return callback(new Error('Insight request timeout')); + }; + + request.onreadystatechange = function() { + if (request.readyState !== 4) return; + var ret, errTxt, e; + + if (request.status === 200 || request.status === 304) { + try { + ret = JSON.parse(request.responseText); + } catch (e2) { + errTxt = 'CRITICAL: Wrong response from insight' + e2; + } + } else if (request.status >= 400 && request.status < 499) { + errTxt = 'CRITICAL: Bad request to insight. Probably wrong transaction to broadcast?.'; + } else { + errTxt = 'Error code: ' + request.status + ' - Status: ' + request.statusText + ' - Description: ' + request.responseText; + setTimeout(function() { + console.log('### Retrying Insight Request....'); + return self._request(options, callback); + }, self.retryDelay); } + if (errTxt) { + console.log("INSIGHT ERROR:", e); + e = new Error(errTxt); + } + return callback(e, ret); + }; - req.end(); + if (options.method === 'POST') { + request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + + request.send(options.data || null); +}; + +Insight.prototype._request = function(options, callback) { + if (typeof process === 'undefined' || !process.version) { + this._requestBrowser(options, callback); + } else { + this._requestNode(options, callback); } }; diff --git a/test/test.blockchain.Insight.js b/test/test.blockchain.Insight.js index f27e9f511..12167ea4b 100644 --- a/test/test.blockchain.Insight.js +++ b/test/test.blockchain.Insight.js @@ -1,14 +1,15 @@ 'use strict'; -var chai = chai || require('chai'); -var should = chai.should(); -var bitcore = bitcore || require('bitcore'); +var chai = chai || require('chai'); +var should = chai.should(); +var sinon = require('sinon'); +var bitcore = bitcore || require('bitcore'); try { var copay = require('copay'); //browser } catch (e) { var copay = require('../copay'); //node } -var Insight = copay.Insight || require('../js/models/blockchain/Insight'); +var Insight = copay.Insight || require('../js/models/blockchain/Insight'); var ID = '933bf321393459b7'; var copayers = [ @@ -26,51 +27,95 @@ var addresses = [ '2N3RhiBW4ssXJnEbPjBCYThJHhEHQWAapf6', '2Mvn2Duvw8cdHs5AB8ZLXfoef1a71UrDr4W', '2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY', - '2N9EdxU3co5XKTyj3yhFBeU3qw3EM1rrgzE' + '2N9EdxU3co5XKTyj3yhFBeU3qw3EM1rrgzE' ]; -var unspent = [ - { - address: "2NE9hTCffeugo5gQtfB4owq98gyTeWC56yb", - txid: "d5597c6cf7f72507af63a4d5a2f9f84edb45fb42452cc8c514435b7a93158915", - vout: 0, - ts: 1397050347, - scriptPubKey: "a914e54f125244a0bf91f9c5d861dc28343ccf19883d87", - amount: 41, - confirmations: 7007 - }, - { - address: "2N9D5bcCQ2bPWUDByQ6Qb5bMgMtgsk1rw3x", - txid: "90d0e1f993fc41596e7b0a7a3be8ef65d606164e13ce538bd3f48136b60eff5a", - vout: 0, - ts: 1397070106, - scriptPubKey: "a914af1a2d1a9c0fa172ed70bc1c50ea6b66994e9abf87", - amount: 50, - confirmations: 6728 - } -]; +var unspent = [{ + address: "2NE9hTCffeugo5gQtfB4owq98gyTeWC56yb", + txid: "d5597c6cf7f72507af63a4d5a2f9f84edb45fb42452cc8c514435b7a93158915", + vout: 0, + ts: 1397050347, + scriptPubKey: "a914e54f125244a0bf91f9c5d861dc28343ccf19883d87", + amount: 41, + confirmations: 7007 +}, { + address: "2N9D5bcCQ2bPWUDByQ6Qb5bMgMtgsk1rw3x", + txid: "90d0e1f993fc41596e7b0a7a3be8ef65d606164e13ce538bd3f48136b60eff5a", + vout: 0, + ts: 1397070106, + scriptPubKey: "a914af1a2d1a9c0fa172ed70bc1c50ea6b66994e9abf87", + amount: 50, + confirmations: 6728 +}]; var rawtx = '01000000010c2a03ed71ee18148e8c99c5ff66d5ffb75e5def46cdea2acc6f30103f33bfb5010000006a47304402207f960aeefdfad270dd77d1acca7af17d3a2e47e2059034ff5d6305cf63635e1d02202f061ee196cc4459cdecae6559beac696a9ecde9a17520849f319fa2a627e64f012103870465f9b4efb90b5d186a7a5eacd7081e601020dacd68d942e5918a56ed0bfcffffffff02a086010000000000ad532102a9495c64323cd8c3354dbf0b3400d830ee680da493acbccc3c2c356d1b20fabf21028233cf8bc6112ae2c36468bd447732c5586b52e1ba3284a2319cadfac6367f99210279fd856e5ed13ab6807e85ed7c0cd6f80613be042240fd731c43f5aba3dcae9821021380858a67a4f99eda52ce2d72c300911f9d3eb9d7a45102a2133f14f7b2dc14210215739b613ce42106a11ce433342c13c610bf68a1bc934f607ad7aeb4178e04cf55ae2044d200000000001976a9146917322f0010aaf7ec136a34b476dfc5eb7a331288ac00000000'; + describe('Insight model', function() { - it('should create an instance', function () { - var w = new Insight(); - should.exist(w); + + it('should create an instance', function() { + var i = new Insight(); + should.exist(i); }); it.skip('should return array of unspent output', function(done) { - var w = new Insight(); - w.listUnspent(addresses, function(a) { - should.exist(a); + var i = new Insight(); + + + var http = require('http'); + var request = { + statusCode: 200 + }; + + request.on = function(event, cb) { + if (event === 'error') return; + if (event === 'data') return { + hola: 'chau' + }; + return cb(); + }; + + var req = {}; + req.write = function() {}; + req.end = function() {}; + + + sinon + .stub(http, 'request') + .returns(req) + .yields(request); + + i.getUnspent(['2MuD5LnZSViZZYwZbpVsagwrH8WWvCztdmV', '2NBSLoMvsHsf2Uv3LA17zV4beH6Gze6RovA'], function(e, ret) { + should.not.exist(e); + should.exist(ret); done(); }); }); - it.skip('should return txid', function (done) { - var w = new Insight(); - w.sendRawTransaction(rawtx, function(a) { + + it.skip('should return txid', function(done) { + var i = new Insight(); + + var http = require('http'); + var request = { + statusCode: 200 + }; + + request.on = function(event, cb) { + if (event === 'error') return; + if (event === 'data') return { + hola: 'chau' + }; + return cb(); + }; + + var req = {}; + req.write = function() {}; + req.end = function() {}; + + + i.sendRawTransaction(rawtx, function(a) { should.exist(a); done(); }); }); }); - From 8b5e616668605ec29fd2084d97a0101192ceed3a Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 19 Jun 2014 00:33:27 -0300 Subject: [PATCH 2/2] add tests for node --- js/models/blockchain/Insight.js | 2 + test/test.blockchain.Insight.js | 109 +++++++++++++++++--------------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index 060863cb6..ae94b95dc 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -195,6 +195,8 @@ Insight.prototype._requestNode = function(options, callback) { return callback(e, ret); }); response.on('error', function(e) { + + console.log('[Insight.js.201]'); //TODO return callback(e, ret); }); }); diff --git a/test/test.blockchain.Insight.js b/test/test.blockchain.Insight.js index 12167ea4b..f24e581d2 100644 --- a/test/test.blockchain.Insight.js +++ b/test/test.blockchain.Insight.js @@ -58,64 +58,71 @@ describe('Insight model', function() { var i = new Insight(); should.exist(i); }); - it.skip('should return array of unspent output', function(done) { - var i = new Insight(); + + // Tests for Node + if (process.version) { + it('should return array of unspent output', function(done) { + var i = new Insight(); - var http = require('http'); - var request = { - statusCode: 200 - }; - - request.on = function(event, cb) { - if (event === 'error') return; - if (event === 'data') return { - hola: 'chau' + var http = require('http'); + var request = { + statusCode: 200 }; - return cb(); - }; - var req = {}; - req.write = function() {}; - req.end = function() {}; - - - sinon - .stub(http, 'request') - .returns(req) - .yields(request); - - i.getUnspent(['2MuD5LnZSViZZYwZbpVsagwrH8WWvCztdmV', '2NBSLoMvsHsf2Uv3LA17zV4beH6Gze6RovA'], function(e, ret) { - should.not.exist(e); - should.exist(ret); - done(); - }); - }); - - it.skip('should return txid', function(done) { - var i = new Insight(); - - var http = require('http'); - var request = { - statusCode: 200 - }; - - request.on = function(event, cb) { - if (event === 'error') return; - if (event === 'data') return { - hola: 'chau' + request.on = function(event, cb) { + if (event === 'error') return; + if (event === 'data') return cb(JSON.stringify(unspent)); + return cb(); }; - return cb(); - }; - var req = {}; - req.write = function() {}; - req.end = function() {}; + var req = {}; + req.write = function() {}; + req.end = function() {}; - i.sendRawTransaction(rawtx, function(a) { - should.exist(a); - done(); + sinon + .stub(http, 'request') + .returns(req) + .yields(request); + + i.getUnspent(['2MuD5LnZSViZZYwZbpVsagwrH8WWvCztdmV', '2NBSLoMvsHsf2Uv3LA17zV4beH6Gze6RovA'], function(e, ret) { + should.not.exist(e); + ret.should.deep.equal(unspent); + http.request.restore(); + done(); + }); }); - }); + + it('should return txid', function(done) { + var i = new Insight(); + + var http = require('http'); + var request = { + statusCode: 200 + }; + + request.on = function(event, cb) { + if (event === 'error') return; + if (event === 'data') return cb('{ "txid": "1234" }'); + return cb(); + }; + + var req = {}; + req.write = function() {}; + req.end = function() {}; + + sinon + .stub(http, 'request') + .returns(req) + .yields(request); + + i.sendRawTransaction(rawtx, function(a) { + should.exist(a); + a.should.equal('1234'); + http.request.restore(); + done(); + }); + }); + } });