Added provider test cases.

This commit is contained in:
ricmoo 2017-03-01 02:26:50 -05:00
parent 8111ef74b2
commit b4b60b64aa
8 changed files with 570 additions and 23 deletions

@ -2,20 +2,10 @@
var reporter = require('nodeunit').reporters.default; var reporter = require('nodeunit').reporters.default;
/*
module.exports = {};
['contract-iterface', 'hdnode', 'utils', 'wallet'].forEach(function(runName) {
var runs = require('./run-' + runName + '.js');
for (var testcaseName in runs) {
module.exports[testcaseName] = runs[testcaseName];
}
});
*/
reporter.run([ reporter.run([
'run-contract-interface.js', 'run-contract-interface.js',
'run-hdnode.js', 'run-hdnode.js',
'run-providers.js',
'run-utils.js', 'run-utils.js',
'run-wallet.js', 'run-wallet.js',
]); ]);

@ -11,6 +11,7 @@ var contracts = require('../../contracts/index.js');
var bigNumber = require('../../utils/bignumber.js'); var bigNumber = require('../../utils/bignumber.js');
var convert = require('../../utils/convert.js'); var convert = require('../../utils/convert.js');
var getAddress = require('../../utils/address.js').getAddress;
var utils = require('./utils.js'); var utils = require('./utils.js');
@ -305,7 +306,7 @@ function makeTests() {
check('sol-28', check('sol-28',
['address', 'string', 'bytes6[4]', 'int'], ['address', 'string', 'bytes6[4]', 'int'],
[ [
"0x97916ef549947a3e0d321485a31dd2715a97d455", getAddress("0x97916ef549947a3e0d321485a31dd2715a97d455"),
"foobar2", "foobar2",
[ [
new Buffer("a165ab0173c6", 'hex'), new Buffer("a165ab0173c6", 'hex'),
@ -409,7 +410,7 @@ function makeTests() {
return { return {
type: 'address', type: 'address',
value: function(extraSeed) { value: function(extraSeed) {
var value = utils.randomHexString(seed + '-' + extraSeed + '-type-2', 20); var value = getAddress(utils.randomHexString(seed + '-' + extraSeed + '-type-2', 20));
return { return {
value: value, value: value,
normalized: value normalized: value

@ -0,0 +1,138 @@
'use strict';
var fs = require('fs');
var path = require('path');
var solc = require('solc');
var convert = require('../../utils/convert.js');
var ethers = require('../../index.js');
var utils = require('./utils.js');
var privateKey = null;
try {
privateKey = fs.readFileSync('.make-providers-account').toString();
console.log('Found privateKey: ' + privateKey);
} catch (error) {
privateKey = convert.hexlify(ethers.utils.randomBytes(32));
console.log('Created new private key: ' + privateKey);
fs.writeFileSync('.make-providers-account', privateKey);
}
var sourcePath = path.join(__dirname, 'test-contracts/TestContract.sol');
var source = fs.readFileSync(sourcePath).toString();
var provider = ethers.providers.getDefaultProvider(true);
var wallet = new ethers.Wallet(privateKey, provider);
console.log('Address: ' + wallet.address);
var TestContract = {
dateCreated: (new Date()).getTime(),
source: source,
owner: wallet.address,
};
var TestContractDeploy = {
dateCreated: (new Date()).getTime(),
source: source,
}
function serialize(object) {
if (object == null) {
return {type: "null"};
}
if (Array.isArray(object)) {
var result = [];
object.forEach(function(object) {
result.push(serialize(object));
});
return result;
} else if (object.toHexString) {
return {type: 'bigNumber', value: object.toHexString()};
}
switch (typeof(object)) {
case 'string':
case 'number':
case 'boolean':
return {type: typeof(object), value: object};
default:
break;
}
var result = {};
for (var key in object) {
result[key] = serialize(object[key]);
}
return result;
}
wallet.getBalance().then(function(balance) {
if (balance.isZero()) {
console.log('Plese send some testnet ether to: ' + wallet.address);
throw new Error('insufficient funds');
}
var compiled = solc.compile(source, 0);
if (compiled.errors) {
console.log('Solidity Compile Error(s):');
compiled.errors.forEach(function(line) {
console.log(' ' + line);
});
throw new Error('invalid solidity contract source');
}
(function() {
var contract = compiled.contracts.TestContractDeploy;
TestContractDeploy.bytecode = '0x' + contract.bytecode;
TestContractDeploy.functions = contract.functionHashes;
TestContractDeploy.interface = contract.interface;
TestContractDeploy.runtimeBytecode = '0x' + contract.runtimeBytecode;
})();
(function() {
var contract = compiled.contracts.TestContract;
TestContract.bytecode = '0x' + contract.bytecode;
TestContract.functions = contract.functionHashes;
TestContract.interface = contract.interface;
TestContract.runtimeBytecode = '0x' + contract.runtimeBytecode;
})();
TestContract.value = 123456789;
var transaction = {
data: TestContract.bytecode,
gasLimit: 2000000,
value: TestContract.value,
}
console.log(transaction);
return wallet.sendTransaction(transaction);
}).then(function(hash) {
TestContract.transactionHash = hash;
return provider.waitForTransaction(hash);
}).then(function(transaction) {
TestContract.address = ethers.utils.getContractAddress(transaction);
TestContract.transaction = JSON.stringify(serialize(transaction));
TestContract.blockNumber = transaction.blockNumber;
TestContract.blockHash = transaction.blockHash;
return Promise.all([
provider.getTransactionReceipt(transaction.hash),
provider.getBlock(transaction.blockHash)
]);
}).then(function(results) {
TestContract.transactionReceipt = JSON.stringify(serialize(results[0]));
TestContract.block = JSON.stringify(serialize(results[1]));
utils.saveTestcase('test-contract', {deploy: TestContractDeploy, test: TestContract});
});

@ -82,3 +82,25 @@ contract TestContract {
callFallback(msg.sender, msg.value); callFallback(msg.sender, msg.value);
} }
} }
contract TestContractDeploy {
address _owner;
uint _uintValue;
string _stringValue;
function TestContractDeploy(uint uintValue, string stringValue) {
_owner = msg.sender;
_uintValue = uintValue;
_stringValue = stringValue;
}
function getValues() constant returns (uint, string) {
return (_uintValue, _stringValue);
}
function cleanup() {
if (msg.sender != _owner) { return; }
suicide(_owner);
}
}

@ -6,19 +6,22 @@
"dependencies": { "dependencies": {
"nodeunit": "0.9.1" "nodeunit": "0.9.1"
}, },
"devDendencies": { "devDependencies": {
"bip39": "2.2.0", "bip39": "2.2.0",
"bitcoinjs-lib": "2.3.0", "bitcoinjs-lib": "2.3.0",
"ethereumjs-abi": "0.6.2", "ethereumjs-abi": "0.6.2",
"ethereumjs-tx": "1.1.1", "ethereumjs-tx": "1.1.1",
"ethereumjs-util": "4.3.0", "ethereumjs-util": "4.3.0",
"grunt": "^0.4.5",
"grunt-browserify": "^5.0.0",
"grunt-contrib-uglify": "^1.0.1",
"promise-rationing": "0.0.1", "promise-rationing": "0.0.1",
"rlp": "2.0.0", "rlp": "2.0.0",
"solc": "0.3.5", "solc": "0.3.5",
"web3": "0.18.2" "web3": "0.18.2"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "node index.js"
}, },
"keywords": [ "keywords": [
"Ethereum", "Ethereum",

@ -1,8 +1,8 @@
'use strict'; 'use strict';
var utils = (function() { var utils = (function() {
var bigNumber = require('../utils/bignumber.js'); var bigNumber = require('../utils/bignumber');
var convert = require('../utils/convert.js'); var convert = require('../utils/convert');
return { return {
arrayify: convert.arrayify, arrayify: convert.arrayify,
@ -10,6 +10,7 @@ var utils = (function() {
}; };
})(); })();
function equals(a, b) { function equals(a, b) {
// Array (treat recursively) // Array (treat recursively)
@ -88,10 +89,7 @@ function testContractInterface(test) {
try { try {
var decoded = Interface.decodeParams(types, result); var decoded = Interface.decodeParams(types, result);
var decodedArray = []; var decodedArray = Array.prototype.slice.call(decoded);;
for (var i = 0; decoded[i] != null; i++) {
decodedArray.push(decoded[i]);
}
test.ok(equals(values, decodedArray), 'failed to decode parameters - ' + testcase.name); test.ok(equals(values, decodedArray), 'failed to decode parameters - ' + testcase.name);

@ -4,7 +4,7 @@ var HDNode = require('../hdnode/index.js');
function testHDNode(test) { function testHDNode(test) {
var Wallet = require('../wallet/index.js'); var Wallet = require('../wallet/index.js');
var c = 0; var c = 0;
var testcases = require('./tests/hdnode.json'); var testcases = require('./tests/hdnode.json');
testcases.forEach(function(testcase) { testcases.forEach(function(testcase) {
//if (c++ > 10) { return; } //if (c++ > 10) { return; }
@ -25,7 +25,7 @@ var c = 0;
} }
function testMnemonic(test) { function testMnemonic(test) {
var c = 0; var c = 0;
var testcases = require('./tests/hdnode.json'); var testcases = require('./tests/hdnode.json');
testcases.forEach(function(testcase) { testcases.forEach(function(testcase) {
//if (c++ > 10) { return; } //if (c++ > 10) { return; }

395
tests/run-providers.js Normal file

@ -0,0 +1,395 @@
'use strict';
var fs = require('fs');
var utils = require('../utils/index.js');
var Wallet = require('../wallet/index.js');
var providers = require('../providers/index.js');
var contracts = require('../contracts');
var TestContracts = require('./tests/test-contract.json');
var TestContract = TestContracts.test;
var TestContractDeploy = TestContracts.deploy;
var callFallback = (function() {
var contractInterface = new contracts.Interface(TestContract.interface);
return contractInterface.events.callFallback();
})();
var privateKey = null;
try {
privateKey = fs.readFileSync('.run-providers-account').toString();
console.log('Found privateKey!');
} catch (error) {
console.log('Creating new private key!');
privateKey = utils.hexlify(utils.randomBytes(32));
fs.writeFileSync('.run-providers-account', privateKey);
}
var provider = providers.getDefaultProvider(true);
var wallet = new Wallet(privateKey, provider);
console.log('Address: ' + wallet.address);
function FailProvider(testnet) {
if (!(this instanceof FailProvider)) { throw new Error('missing new'); }
providers.Provider.call(this, testnet);
}
providers.Provider.inherits(FailProvider);
utils.defineProperty(FailProvider.prototype, 'perform', function (method, params) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('out of order'));
}, 1000);
});
});
function equal(serialized, object) {
if (Array.isArray(serialized)) {
if (!Array.isArray(object) || serialized.length != object.length) { return false; }
for (var i = 0; i < serialized.length; i++) {
if (!equal(serialized[i], object[i])) { return false; }
}
return true;
} else if (serialized.type) {
var result = null;
switch (serialized.type) {
case 'null':
result = (null === object);
break;
case 'string':
case 'number':
case 'boolean':
result = (serialized.value === object);
break;
case 'bigNumber':
result = utils.bigNumberify(serialized.value).eq(object);
break;
default:
throw new Error('unknown type - ' + serialized.type);
}
if (!result) {
console.log('Not Equal: ', serialized, object);
}
return result;
}
for (var key in serialized) {
if (!equal(serialized[key], object[key])) { return false; }
}
return true;
}
function testReadOnlyProvider(test, provider) {
return Promise.all([
provider.getBalance(TestContract.address),
provider.getCode(TestContract.address),
provider.getStorageAt(TestContract.address, 0),
provider.getBlock(TestContract.blockNumber),
provider.getBlock((provider instanceof providers.EtherscanProvider) ? TestContract.blockNumber: TestContract.blockHash),
provider.getTransaction(TestContract.transactionHash),
provider.getTransactionReceipt(TestContract.transactionHash),
provider.call({to: TestContract.address, data: '0x' + TestContract.functions['getOwner()']}),
provider.call({to: TestContract.address, data: '0x' + TestContract.functions['getStringValue()']}),
provider.getBlockNumber(),
provider.getGasPrice(),
//provider.estimeGas()
]).then(function(result) {
// getBalance
test.equal(result[0].toString(), '123456789', 'getBalance(contractAddress)');
// getCode
test.equal(result[1], TestContract.runtimeBytecode, 'getCode(contractAddress)');
// getStorageAt
test.ok(utils.bigNumberify(result[2]).eq(42), 'getStorageAt(contractAddress, 0)');
// getBlock
var block = JSON.parse(TestContract.block);
test.ok(equal(block, result[3]), 'getBlock(blockNumber)');
test.ok(equal(block, result[4]), 'getBlock(blockHash)');
// getTransaction
var transaction = JSON.parse(TestContract.transaction);
test.ok(equal(transaction, result[5]), 'getTransaction(transactionHash)');
// getTransactionReceipt
var transactionReceipt = JSON.parse(TestContract.transactionReceipt);
test.ok(equal(transactionReceipt, result[6]), 'getTransaction(transactionHash)');
// call
test.equal(TestContract.owner, utils.getAddress('0x' + result[7].substring(26)), 'call(getOwner())');
var thisIsNotAString = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001554686973206973206e6f74206120737472696e672e0000000000000000000000';
test.equal(thisIsNotAString, result[8], 'call(getStringValue())');
return {blockNumber: result[9], gasPrice: result[9]}
});
}
function testWriteProvider(test, wallet) {
var testTransaction = {
to: TestContract.address,
gasLimit: 0x793e + 42,
value: 100,
};
return Promise.all([
wallet.estimateGas(testTransaction),
wallet.sendTransaction(testTransaction),
]).then(function(results) {
test.ok(results[0].eq(0x793e), 'estimateGas()');
return wallet.provider.waitForTransaction(results[1]);
}).then(function(transaction) {
test.equal(transaction.to, testTransaction.to, 'check toAddress');
test.equal(transaction.from, wallet.address, 'check fromAddress');
test.ok(transaction.gasLimit.eq(testTransaction.gasLimit), 'check gasLimit');
test.ok(transaction.value.eq(testTransaction.value), 'check value');
});
}
function getProviders() {
return [
new providers.InfuraProvider(true),
//new providers.EtherscanProvider(true),
new providers.FallbackProvider([
new FailProvider(true),
new providers.InfuraProvider(true),
]),
];
}
function testEventsProvider(test, provider) {
var firstBlockNumber = null;
var lastBlockNumber = null;
return Promise.all([
new Promise(function(resolve, reject) {
function callback(blockNumber) {
if (lastBlockNumber === null) {
firstBlockNumber = blockNumber;
lastBlockNumber = blockNumber - 1;
}
test.equal(lastBlockNumber + 1, blockNumber, 'increasing block number');
lastBlockNumber = blockNumber;
if (blockNumber > firstBlockNumber + 4) {
provider.removeListener('block', callback);
resolve(blockNumber);
}
}
provider.on('block', callback);
}),
new Promise(function(resolve, reject) {
function callback(log) {
var result = callFallback.parse(log.data);
if (result.sender !== wallet.address || !result.amount.eq(123)) {
//console.log('someone else is running the test cases');
return;
}
test.ok(true, 'callFallback triggered');
provider.removeListener(callFallback.topics, callback);
resolve(result);
}
provider.on(callFallback.topics, callback);
}),
]);
}
function testReadOnly(test) {
var promises = [];
getProviders().forEach(function(provider) {
promises.push(testReadOnlyProvider(test, provider));
});
Promise.all(promises).then(function(results) {
results.forEach(function(result, i) {
if (i === 0) { return; }
test.equal(results[0].blockNumber, result.blockNumber, 'blockNumber');
test.equal(results[0].gasPrice, result.gasPrice, 'blockNumber');
});
test.done();
}, function(error) {
console.log(error);
test.ok(false, 'error occurred');
});
}
function testWrite(test) {
var promise = wallet.getBalance().then(function(balance) {
if (balance.isZero()) {
console.log('Plese send some testnet ether to: ' + wallet.address);
throw new Error('insufficient balance');
}
});
getProviders().forEach(function(provider) {
promise = promise.then(function() {
var wallet = new Wallet(privateKey, provider);
return testWriteProvider(test, wallet);
});
});
promise.then(function(result) {
test.done();
}, function(error) {
console.log(error);
test.ok(false, 'error occurred');
test.done();
});
}
function testEvents(test) {
var promises = [];
getProviders().forEach(function(provider) {
promises.push(testEventsProvider(test, provider));
});
Promise.all(promises).then(function(result) {
test.done()
}, function (error) {
console.log(error);
test.ok(false, 'error occurred');
test.done()
});
// Send 123 wei to the contrat to trigger its callFallback event
wallet.send(TestContract.address, 123).then(function(hash) {
console.log('Trigger Transaction: ' + hash);
});
}
function testContracts(test) {
var contract = new contracts.Contract(TestContract.address, TestContract.interface, wallet);
var newValue = 'Chicken-' + parseInt((new Date()).getTime());
Promise.all([
contract.getUintValue(),
contract.getArrayValue(0),
contract.getArrayValue(1),
contract.getArrayValue(2),
contract.getBytes32Value(),
contract.getStringValue(),
contract.getOwner(),
contract.getMappingValue('A'),
contract.getMappingValue('B'),
contract.getMappingValue('C'),
contract.getMappingValue('Nothing'),
contract.getValue(),
(new Promise(function(resolve, reject) {
contract.onvaluechanged = function(author, oldValue, newValue) {
test.ok(true, 'contract event oncallfa');
contract.onvaluechanged = null;
resolve({author: author, oldValue: oldValue, newValue: newValue});
};
})),
contract.setValue(newValue),
]).then(function(results) {
test.ok(results[0][0].eq(42), 'getUintValue()');
test.equal(results[1][0], 'One', 'getArrayValue(1)');
test.equal(results[2][0], 'Two', 'getArrayValue(2)');
test.equal(results[3][0], 'Three', 'getArrayValue(3)');
test.equal(
utils.hexlify(results[4][0]),
utils.keccak256(utils.toUtf8Bytes('TheEmptyString')),
'getBytes32Value()'
);
test.equal(results[5][0], 'This is not a string.', 'getStringValue()');
test.equal(results[6][0], TestContract.owner, 'getOwner()');
test.equal(results[7][0], 'Apple', 'getMapping(A)');
test.equal(results[8][0], 'Banana', 'getMapping(B)');
test.equal(results[9][0], 'Cherry', 'getMapping(C)');
test.equal(results[10][0], '', 'getMapping(Nothing)');
var getValue = results[11][0];
var onvaluechanged = results[12];
test.equal(onvaluechanged.oldValue, getValue, 'getValue()');
test.equal(onvaluechanged.author, wallet.address, 'onvaluechanged.author');
test.equal(onvaluechanged.newValue, newValue, 'onvaluechanged.newValue');
test.done();
}, function(error) {
console.log(error);
test.ok(false, 'an error occurred');
});
}
function testDeploy(test) {
var valueUint = parseInt((new Date()).getTime());
var valueString = 'HelloWorld-' + valueUint;
var contractInterface = new contracts.Interface(TestContractDeploy.interface);
var deployInfo = contractInterface.deployFunction(
TestContractDeploy.bytecode,
valueUint,
valueString
);
var transaction = {
data: deployInfo.bytecode
};
var contract = null;
wallet.sendTransaction(transaction).then(function(hash) {
return provider.waitForTransaction(hash);
}).then(function(transaction) {
contract = new contracts.Contract(transaction.creates, TestContractDeploy.interface, wallet);
return contract.getValues();
}).then(function(result) {
test.ok(result[0].eq(valueUint), 'deployed contract - uint equal');
test.equal(result[1], valueString, 'deployed contract - string equal');
return provider.getCode(contract.address);
}).then(function(code) {
test.equal(code, TestContractDeploy.runtimeBytecode, 'getCode() == runtimeBytecode (after deploy)');
return contract.cleanup();
}).then(function(hash) {
return provider.waitForTransaction(hash);
}).then(function(transaction) {
return provider.getCode(contract.address);
}).then(function(code) {
test.equal(code, '0x', 'getCode() == null (after suicide)');
test.done();
});
}
module.exports = {
'read-only': testReadOnly,
'write': testWrite,
'events': testEvents,
'contracts': testContracts,
'deploy': testDeploy,
};