ethers.js/tests/run-providers.js
2017-05-21 20:34:45 -04:00

502 lines
16 KiB
JavaScript

'use strict';
var fs = require('fs');
var utils = require('../utils');
var Wallet = require('../wallet/wallet');
var providers = require('../providers');
var contracts = require('../contracts');
var TestContracts = require('./tests/test-contract.json');
var TestContract = TestContracts.test;
var TestContractDeploy = TestContracts.deploy;
process.on('unhandledRejection', function(reason, p){
console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
console.log(p);
console.log(reason);
});
var callFallback = (function() {
var contractInterface = new contracts.Interface(TestContract.interface);
return contractInterface.events.callFallback();
})();
var privateKey = null;
if (fs && fs.readFileSync) {
try {
privateKey = fs.readFileSync('.test-account.key').toString();
console.log('Found privateKey!');
} catch (error) {
console.log('Creating new private key!');
privateKey = utils.hexlify(utils.randomBytes(32));
fs.writeFileSync('.test-account.key', privateKey);
}
} else {
privateKey = global.localStorage.getItem('ethers-tests-privateKey');
if (privateKey) {
console.log('Found privateKey');
} else {
console.log('Creating new private key!');
privateKey = utils.hexlify(utils.randomBytes(32));
global.localStorage.setItem('ethers-tests-privateKey', 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, address, provider) {
return Promise.all([
provider.getBalance(address),
provider.getCode(address),
provider.getStorageAt(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: address, data: '0x' + TestContract.functions['getOwner()']}),
provider.call({to: 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, address, wallet) {
var testTransaction = {
to: 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].hash);
}).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');
}).catch(function(error) {
console.log(error);
test.ok(false, 'error occurred');
});
}
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.topics, 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, TestContract.address, 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, TestContract.address, 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(transaction) {
console.log('Trigger Transaction: ' + 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 transaction = contracts.Contract.getDeployTransaction(
TestContractDeploy.bytecode,
TestContractDeploy.interface,
valueUint,
valueString
);
var contract = null;
wallet.sendTransaction(transaction).then(function(transaction) {
return provider.waitForTransaction(transaction.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(transaction) {
return provider.waitForTransaction(transaction.hash);
}).then(function(transaction) {
return provider.getCode(contract.address);
}).then(function(code) {
test.equal(code, '0x', 'getCode() == null (after suicide)');
test.done();
});
}
function testENSProviderReadOnly(test, provider) {
var promises = [];
getProviders().forEach(function(provider) {
promises.push(testReadOnlyProvider(test, 'test.ricmoose.eth', provider));
});
Promise.all(promises).then(function(results) {
console.log(results);
test.done();
}, function(error) {
console.log(error);
test.ok(false, 'error occurred');
});
/*
provider.resolveName('anemone.eth').then(function(result) {
console.log(result);
test.done();
});
*/
}
function testENSProviderWrite(test, provider) {
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, TestContract.address, wallet);
});
});
promise.then(function(result) {
test.done();
}, function(error) {
console.log(error);
test.ok(false, 'error occurred');
test.done();
});
}
function testENSReadOnly(test) {
testENSProviderReadOnly(test, new providers.InfuraProvider(true));
}
function testENSWrite(test) {
testENSProviderWrite(test, new providers.InfuraProvider(true));
}
function testENS(test) {
var provider = providers.getDefaultProvider(true);
provider.resolveName('ricmoose.eth').then(function(address) {
test.equal('0x5543707cC4520F3984656e8eDEa6527ca474E77B', address, 'Simple ENS name');
return provider.resolveName('duck.ricmoose.eth');
}).then(function(address) {
test.equal('0xf770358c6F29FAA38186E49c149C87968775B228', address, 'Nested ENS name');
return provider.resolveName('nothing-here.ricmoose.eth');
}).then(function(address) {
test.equal(null, address, 'Non-existing ENS name');
return provider.resolveName('not-valid');
}).then(function(address) {
test.equal(null, address, 'Invalid ENS name');
test.done();
});
}
module.exports = {
'read-only': testReadOnly,
'write': testWrite,
'events': testEvents,
'contracts': testContracts,
'deploy': testDeploy,
'ens': testENS,
'ens-readonly': testENSReadOnly,
'ens-write': testENSWrite,
};