From f3107c20e1c57b45868f2392168201159f692455 Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Tue, 4 Oct 2016 15:19:38 +0200 Subject: [PATCH] improved fake provider, with stacking validation and results --- lib/web3/contract.js | 4 +- lib/web3/requestmanager.js | 2 +- test/contract.js | 268 ++++++++++++++----------------- test/helpers/FakeHttpProvider.js | 73 +++++---- 4 files changed, 167 insertions(+), 180 deletions(-) diff --git a/lib/web3/contract.js b/lib/web3/contract.js index e99503514d8..426a399c550 100644 --- a/lib/web3/contract.js +++ b/lib/web3/contract.js @@ -482,6 +482,7 @@ Contract.prototype.deploy = function(options, callback){ return defer.promise; }; +// TODO add constructor as method with .encodeABI /** * Encodes any contract function, including the constructor into a data ABI HEX string. @@ -752,8 +753,9 @@ Contract.prototype._executeMethod = function _executeMethod(type){ // create the callback method var methodReturnCallback = function(err, returnValue) { - if(type === 'call') + if(type === 'call') { returnValue = _this._parent._decodeMethodReturn(_this._method.outputTypes, returnValue); + } if (err) { diff --git a/lib/web3/requestmanager.js b/lib/web3/requestmanager.js index 562bd11641e..aa5eb011af5 100644 --- a/lib/web3/requestmanager.js +++ b/lib/web3/requestmanager.js @@ -77,7 +77,7 @@ RequestManager.prototype.sendAsync = function (data, callback) { } var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); this.provider.sendAsync(payload, function (err, result) { - // if(payload.id !== result.id) return callback(new Error('Wrong response id for '+ JSON.stringify(payload)));; + if(payload.id !== result.id) return callback(new Error('Wrong response id "'+ result.id +'" (expected: "'+ payload.id +'") in '+ JSON.stringify(payload)));; if (err) { return callback(err); diff --git a/test/contract.js b/test/contract.js index a1e0f2e7610..285a11661f5 100644 --- a/test/contract.js +++ b/test/contract.js @@ -71,41 +71,36 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'Changed(address,uint256,uint256,uint256)'; - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - provider.injectResult('0x123'); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_subscribe'); - assert.deepEqual(payload.params[1], { - topics: [ - '0x' + sha3(signature), - ('0x000000000000000000000000' + address.replace('0x', '')), - null - ], - address: address - }); - step++; - } else if (step === 1) { - provider.injectResult(true); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_unsubscribe'); - } + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params[1], { + topics: [ + '0x' + sha3(signature), + ('0x000000000000000000000000' + address.replace('0x', '')), + null + ], + address: address + }); + }); + provider.injectResult('0x123'); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_unsubscribe'); + done(); + }); + provider.injectResult(true); var contract = new web3.eth.contract(abi, address); - var res = 0; - var event = contract.on('Changed', {filter: {from: address}}, function (err, result) { + var event = contract.on('Changed', {filter: {from: address}}, function (err, result, sub) { assert.equal(result.returnValues.from, address); assert.equal(result.returnValues.amount, 1); assert.equal(result.returnValues.t1, 1); assert.equal(result.returnValues.t2, 8); - res++; - if (res === 1) { - event.unsubscribe(); - done(); - } + + sub.unsubscribe(); }); provider.injectNotification({ @@ -134,62 +129,37 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'Changed(address,uint256,uint256,uint256)'; - var step = 0; + provider.injectValidation(function (payload) { - if (step === 0) { - provider.injectResult('0x321'); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_subscribe'); - assert.deepEqual(payload.params[1], { - topics: [ - '0x' + sha3(signature), - '0x0000000000000000000000001234567890123456789012345678901234567891', - null - ], - address: address - }); - step++; - } else if (step === 1) { - provider.injectResult(true); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_unsubscribe'); - } + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params[1], { + topics: [ + '0x' + sha3(signature), + '0x0000000000000000000000001234567890123456789012345678901234567891', + null + ], + address: address + }); + }); + provider.injectResult('0x321'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_unsubscribe'); + done(); }); + provider.injectResult(true); var contract = new web3.eth.contract(abi, address); - var res = 0; - var event = contract.on('Changed', {filter: {from: address}}, function (err, result) { + var event = contract.on('Changed', {filter: {from: address}}, function (err, result, sub) { assert.equal(result.returnValues.from, address); assert.equal(result.returnValues.amount, 1); assert.equal(result.returnValues.t1, 1); assert.equal(result.returnValues.t2, 8); - res++; - if (res === 2) { - event.unsubscribe(); - done(); - } - }); - provider.injectNotification({ - method: 'eth_subscription', - params: { - subscription: '0x321', - result: { - address: address, - topics: [ - '0x' + sha3(signature), - '0x0000000000000000000000001234567890123456789012345678901234567891', - '0x0000000000000000000000000000000000000000000000000000000000000001' - ], - blockNumber: '0x3', - transactionHash: '0x1234', - blockHash: '0x1345', - logIndex: '0x4', - data: '0x0000000000000000000000000000000000000000000000000000000000000001' + - '0000000000000000000000000000000000000000000000000000000000000008' - } - } + sub.unsubscribe(); }); provider.injectNotification({ @@ -212,30 +182,30 @@ describe('contract', function () { } } }); + }); it('should create all event filter', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'Changed(address,uint256,uint256,uint256)'; - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - provider.injectResult('0x333'); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_subscribe'); - assert.deepEqual(payload.params[1], { - topics: [], - address: address - }); - step++; - } else if (step === 1) { - provider.injectResult(true); - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_unsubscribe'); - } + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params[1], { + topics: [], + address: address + }); + }); + provider.injectResult('0x333'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_unsubscribe'); }); + provider.injectResult(true); + var contract = new web3.eth.contract(abi, address); @@ -275,7 +245,6 @@ describe('contract', function () { it('should call constant function', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)'; provider.injectValidation(function (payload) { @@ -285,6 +254,7 @@ describe('contract', function () { to: address }, 'latest']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var contract = new web3.eth.contract(abi, address); @@ -297,7 +267,6 @@ describe('contract', function () { it('should call constant function with default block', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)'; provider.injectValidation(function (payload) { @@ -307,6 +276,7 @@ describe('contract', function () { to: address }, '0xb']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var contract = new web3.eth.contract(abi, address); @@ -321,6 +291,7 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'send(address,uint256)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); assert.deepEqual(payload.params, [{ @@ -340,9 +311,10 @@ describe('contract', function () { it('should make a call with optional params', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)'; var count = 0; + + provider.injectValidation(function (payload) { count++; if(count > 1) return; @@ -355,6 +327,8 @@ describe('contract', function () { gas: '0xc350' }, 'latest']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var contract = new web3.eth.contract(abi, address); @@ -363,14 +337,13 @@ describe('contract', function () { assert.deepEqual(new BigNumber(0x32), r); done(); }); - }); it('should explicitly make a call with optional params', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ @@ -380,6 +353,7 @@ describe('contract', function () { gas: '0xc350' }, 'latest']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var contract = new web3.eth.contract(abi, address); @@ -394,8 +368,8 @@ describe('contract', function () { it('should explicitly make a call with optional params and defaultBlock', function (done) { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ @@ -405,6 +379,7 @@ describe('contract', function () { gas: '0xc350' }, '0xb']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var contract = new web3.eth.contract(abi, address); @@ -420,6 +395,7 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'send(address,uint256)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); assert.deepEqual(payload.params, [{ @@ -443,6 +419,7 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'send(address,uint256)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_sendTransaction'); assert.deepEqual(payload.params, [{ @@ -466,10 +443,8 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'send(address,uint256)'; - var count = 0; + provider.injectValidation(function (payload) { - count++ - if(count > 1) return; assert.equal(payload.method, 'eth_sendTransaction'); assert.deepEqual(payload.params, [{ @@ -496,6 +471,7 @@ describe('contract', function () { var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'send(address,uint256)'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_estimateGas'); assert.deepEqual(payload.params, [{ @@ -516,12 +492,9 @@ describe('contract', function () { }); it('should call testArr method and properly parse result', function (done) { - var provider = new FakeHttpProvider2(); + var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'testArr(int[])'; - provider.injectResultList([{ - result: '0x0000000000000000000000000000000000000000000000000000000000000005' - }]); provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_call'); @@ -532,10 +505,12 @@ describe('contract', function () { '0000000000000000000000000000000000000000000000000000000000000003', to: address }, - 'latest' - ]); + 'latest' + ]); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000005'); + var contract = new web3.eth.contract(abi, address); contract.testArr([3]).call() .then(function (result) { @@ -546,12 +521,10 @@ describe('contract', function () { }); it('should call testArr method, properly parse result and return the result in a callback', function (done) { - var provider = new FakeHttpProvider2(); + var provider = new FakeHttpProvider(); var web3 = new Web3(provider); var signature = 'testArr(int[])'; - provider.injectResultList([{ - result: '0x0000000000000000000000000000000000000000000000000000000000000005' - }]); + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ @@ -561,9 +534,10 @@ describe('contract', function () { '0000000000000000000000000000000000000000000000000000000000000003', to: address }, - 'latest' + 'latest' ]); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000005'); var contract = new web3.eth.contract(abi, address); @@ -610,58 +584,50 @@ describe('contract', function () { var FakeHttpProvider = require('./helpers/FakeHttpProvider'); var provider = new FakeHttpProvider(); var web3 = new Web3(provider); - var count = 0; - provider.injectValidation(function (payload) { - count++ - - if(count === 1) { - assert.equal(payload.method, 'eth_sendTransaction'); - assert.deepEqual(payload.params, [{ - data: '0x1234567000000000000000000000000123456789012345678901234567890123456789100000000000000000000000000000000000000000000000000000000000000c8' , - from: address, - gas: '0xc350', - gasPrice: '0xbb8' - }]); - - provider.injectResult('0x5550000000000000000000000000000000000000000000000000000000000032'); - } - - if(count === 2) { - - - assert.equal(payload.method, 'eth_subscribe'); - assert.deepEqual(payload.params, ['newBlocks', {}]); + provider.injectValidation(function (payload) { - provider.injectResult('0x1234567'); + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x1234567000000000000000000000000123456789012345678901234567890123456789100000000000000000000000000000000000000000000000000000000000000c8' , + from: address, + gas: '0xc350', + gasPrice: '0xbb8' + }]); - // fake newBlock - provider.injectNotification({ - method: 'eth_subscription', - params: { - subscription: '0x1234567', - result: { - blockNumber: '0x10' - } - } - }); + }); + provider.injectResult('0x5550000000000000000000000000000000000000000000000000000000000032'); - } - if(count === 3) { - assert.equal(payload.method, 'eth_getTransactionReceipt'); - assert.deepEqual(payload.params, ['0x5550000000000000000000000000000000000000000000000000000000000032']); + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params, ['newBlocks', {}]); + }); + provider.injectResult('0x1234567'); - provider.injectResult({ - contractAddress: address - }); + // fake newBlock + provider.injectNotification({ + method: 'eth_subscription', + params: { + subscription: '0x1234567', + result: { + blockNumber: '0x10' + } } - if(count === 4) { - assert.equal(payload.method, 'eth_getCode'); - assert.deepEqual(payload.params, [address,'latest']); + }); - provider.injectResult('0x321'); - } + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_getTransactionReceipt'); + assert.deepEqual(payload.params, ['0x5550000000000000000000000000000000000000000000000000000000000032']); + }); + provider.injectResult({ + contractAddress: address }); + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_getCode'); + assert.deepEqual(payload.params, [address, 'latest']); + }); + provider.injectResult('0x321'); + var contract = new web3.eth.contract(abi); diff --git a/test/helpers/FakeHttpProvider.js b/test/helpers/FakeHttpProvider.js index 2775926a604..0e00ddea17c 100644 --- a/test/helpers/FakeHttpProvider.js +++ b/test/helpers/FakeHttpProvider.js @@ -7,18 +7,18 @@ var utils = require('../../lib/utils/utils'); var FakeHttpProvider = function () { var _this = this; - this.countId = 0; + this.countId = 1; this.getResponseStub = function () { return { jsonrpc: '2.0', - id: _this.countId++, + id: _this.countId, result: null }; }; this.getErrorStub = function () { return { jsonrpc: '2.0', - id: _this.countId++, + id: _this.countId, error: { code: 1234, message: 'Stub error' @@ -26,21 +26,26 @@ var FakeHttpProvider = function () { }; }; - this.response = this.getResponseStub(); - this.error = null; - this.validation = null; + this.response = []; + this.error = []; + this.validation = []; this.notificationCallbacks = []; }; FakeHttpProvider.prototype.send = function (payload) { assert.equal(utils.isArray(payload) || utils.isObject(payload), true); + + if (this.error) { - throw this.error; + throw this.error.shift(); } - if (this.validation) { + + var validation = this.validation.shift(); + + if(validation) { // imitate plain json object - this.validation(JSON.parse(JSON.stringify(payload))); + validation(JSON.parse(JSON.stringify(payload))); } return this.getResponse(payload); @@ -49,19 +54,28 @@ FakeHttpProvider.prototype.send = function (payload) { FakeHttpProvider.prototype.sendAsync = function (payload, callback) { var _this = this; + // set id + if(payload.id) + this.countId = payload.id; + // else + // this.countId++; + assert.equal(utils.isArray(payload) || utils.isObject(payload), true); assert.equal(utils.isFunction(callback), true); - if (this.validation) { + + var validation = this.validation.shift(); + + if (validation) { // imitate plain json object - this.validation(JSON.parse(JSON.stringify(payload)), callback); + validation(JSON.parse(JSON.stringify(payload)), callback); } var response = _this.getResponse(payload); - var error = _this.error; + var error = _this.error.shift(); setTimeout(function(){ callback(error, response); - }, 2); + }, 1); }; FakeHttpProvider.prototype.on = function (type, callback) { @@ -74,7 +88,8 @@ FakeHttpProvider.prototype.injectNotification = function (notification) { var _this = this; setTimeout(function(){ _this.notificationCallbacks.forEach(function(cb){ - cb(null, notification); + if(notification && cb) + cb(null, notification); }); }, 10); }; @@ -84,13 +99,15 @@ FakeHttpProvider.prototype.injectResponse = function (response) { }; FakeHttpProvider.prototype.injectResult = function (result) { - this.response = this.getResponseStub(); - this.response.result = result; + var response = this.getResponseStub(); + response.result = result; + + this.response.push(response); }; FakeHttpProvider.prototype.injectBatchResults = function (results, error) { var _this = this; - this.response = results.map(function (r) { + this.response.push(results.map(function (r) { if(error) { var response = _this.getErrorStub(); response.error.message = r; @@ -99,30 +116,32 @@ FakeHttpProvider.prototype.injectBatchResults = function (results, error) { response.result = r; } return response; - }); + })); }; FakeHttpProvider.prototype.getResponse = function (payload) { var _this = this; - if(this.response) { - if(utils.isArray(this.response)) { - this.response = this.response.map(function(response, index) { - response.id = payload[index] ? payload[index].id : _this.countId++; - return response; + var response = this.response.shift() || this.getResponseStub(); + + if(response) { + if(utils.isArray(response)) { + response = response.map(function(resp, index) { + resp.id = payload[index] ? payload[index].id : _this.countId++; + return resp; }); } else - this.response.id = payload.id; + response.id = payload.id; } - return this.response; + return response; }; FakeHttpProvider.prototype.injectError = function (error) { - this.error = error; + this.error.push(error); }; FakeHttpProvider.prototype.injectValidation = function (callback) { - this.validation = callback; + this.validation.push(callback); }; module.exports = FakeHttpProvider;