From 168de458998c0b2f22ee424519acbcd1a07f1e9b Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 23 Jul 2019 18:56:30 -0700 Subject: [PATCH] Initial app test cleanup --- test/units/app.js | 395 ++++++++++++---------------------------------- 1 file changed, 99 insertions(+), 296 deletions(-) diff --git a/test/units/app.js b/test/units/app.js index 9c963a3..b519f15 100644 --- a/test/units/app.js +++ b/test/units/app.js @@ -1,241 +1,85 @@ /* eslint-env node, mocha */ -/*const assert = require('assert'); +const assert = require('assert'); const shell = require('shelljs'); const fs = require('fs'); const childprocess = require('child_process'); -const mock = require('./util/mockTruffle.js'); +const mock = require('../util/mockTruffle.js'); // shell.test alias for legibility function pathExists(path) { return shell.test('-e', path); } -// tests run out of memory in CI without this -function collectGarbage() { - if (global.gc) { global.gc(); } +function assertCleanInitialState(){ + assert(pathExists('./coverage') === false, 'should start without: coverage'); + assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); } -describe('app', () => { - let testrpcProcess = null; - const script = 'node ./bin/exec.js'; - const port = 8555; - - const config = { - dir: './mock', - port, - testing: true, - silent: true, // <-- Set to false to debug tests - norpc: true, - }; - - before(done => { - const command = `npx testrpc-sc --gasLimit 0xfffffffffff --port ${port}`; - testrpcProcess = childprocess.exec(command); - - testrpcProcess.stdout.on('data', data => { - if (data.includes('Listening')) { - done(); - } - }); - }); +function assertCoverageGenerated(){ + assert(pathExists('./coverage') === true, 'script should gen coverage folder'); + assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); +} - afterEach(() => { - mock.remove(); - }); +function assertCoverageNotGenerated(){ + assert(pathExists('./coverage') !== true, 'script should NOT gen coverage folder'); + assert(pathExists('./coverage.json') !== true, 'script should NOT gen coverage.json'); +} - after(() => { - testrpcProcess.kill(); - }); +function assertExecutionSucceeds(){ + +} + +function assertExecutionFails(){ + +} + +describe.skip('app', function() { + afterEach(() => mock.remove()); - // #1: The 'config' tests ask exec.js to run testrpc on special ports, the subsequent tests use - // the testrpc launched in the before() block. For some reason config tests fail randomly - // unless they are at the top of the suite. Hard to debug since they pass if logging is turned - // on - there might be a timing issue around resource cleanup or something. - // - // #2: Creating repeated instances of testrpc hits the container memory limit on - // CI so these tests are disabled for that context it('config with testrpc options string: should generate coverage, cleanup & exit(0)', () => { - if (!process.env.CI) { - const privateKey = '0x3af46c9ac38ee1f01b05f9915080133f644bf57443f504d339082cb5285ccae4'; - const balance = '0xfffffffffffffff'; - const testConfig = Object.assign({}, config); - - testConfig.testrpcOptions = `--account="${privateKey},${balance}" --port 8777`; - testConfig.dir = './mock'; - testConfig.norpc = false; - testConfig.port = 8777; - - // Installed test will process.exit(1) and crash truffle if the test isn't - // loaded with the account specified above - mock.install('Simple.sol', 'testrpc-options.js', testConfig); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - collectGarbage(); - } - }); - it('config with test command options string: should run test', () => { - if (!process.env.CI) { - assert(pathExists('./allFiredEvents') === false, 'should start without: events log'); - const testConfig = Object.assign({}, config); - - testConfig.testCommand = 'mocha --timeout 5000'; - testConfig.dir = './mock'; - testConfig.norpc = false; - testConfig.port = 8888; - - // Installed test will write a fake allFiredEvents to ./ after 4000ms - // allowing test to pass - mock.install('Simple.sol', 'command-options.js', testConfig); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - collectGarbage(); - } - }); + const privateKey = '0x3af46c9ac38ee1f01b05f9915080133f644bf57443f504d339082cb5285ccae4'; + const balance = '0xfffffffffffffff'; + const testConfig = Object.assign({}, config); - it('config racing test command: should run test after testrpc has started', () => { - if (!process.env.CI) { - assert(pathExists('./allFiredEvents') === false, 'should start without: events log'); - const testConfig = Object.assign({}, config); - - testConfig.testCommand = 'node ../test/util/mockTestCommand.js'; - testConfig.dir = './mock'; - testConfig.norpc = false; - testConfig.port = 8888; - - // Installed test will write a fake allFiredEvents to ./ after 4000ms - // allowing test to pass - mock.install('Simple.sol', 'command-options.js', testConfig); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - collectGarbage(); - } - }); + testConfig.testrpcOptions = `--account="${privateKey},${balance}" --port 8777`; + testConfig.dir = './mock'; + testConfig.norpc = false; + testConfig.port = 8777; - it('contract tests events: tests should pass without errors', () => { - if (!process.env.CI) { - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); - - const testConfig = Object.assign({}, config); - - testConfig.dir = './mock'; - testConfig.norpc = false; - testConfig.port = 8889; - - mock.install('Events.sol', 'events.js', testConfig); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); - - // Coverage should be real. - // This test is tightly bound to the function names in Simple.sol - const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); - const path = Object.keys(produced)[0]; - assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); - assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); - } - }); + // Installed test will process.exit(1) and crash truffle if the test isn't + // loaded with the account specified above + mock.install('Simple.sol', 'testrpc-options.js', testConfig); + shell.exec(script); + assert(shell.error() === null, 'script should not error'); - it('trufflejs specifies coverage network: should generate coverage, cleanup and exit(0)', () => { - if (!process.env.CI) { - const trufflejs = - `module.exports = { - networks: { - development: { - host: "localhost", - port: 8545, - network_id: "*" - }, - coverage: { - host: "localhost", - port: 8999, - network_id: "*", - gas: 0xfffffffffff, - gasPrice: 0x01 - } - }, - compilers: { - solc: { - version: "0.5.3", - } - } - };`; - - const testConfig = Object.assign({}, config); - testConfig.dir = './mock'; - testConfig.norpc = false; - testConfig.port = 8555; // Manually inspect that port is actually set to 8999 - - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); - - // Run script (exits 0); - mock.install('Simple.sol', 'simple.js', testConfig, trufflejs); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); - - // Coverage should be real. - // This test is tightly bound to the function names in Simple.sol - const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); - const path = Object.keys(produced)[0]; - assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); - assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); - } }); - it('large contract w/ many unbracketed statements (Oraclize)', () => { - const trufflejs = - `module.exports = { - networks: { - coverage: { - host: "localhost", - network_id: "*", - port: 8555, - gas: 0xfffffffffff, - gasPrice: 0x01 - }, - }, - compilers: { - solc: { - version: "0.4.24", - } - } - };`; + it('config with test command options string: should run test', () => { + assert(pathExists('./allFiredEvents') === false, 'should start without: events log'); + const testConfig = Object.assign({}, config); - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + testConfig.testCommand = 'mocha --timeout 5000'; + testConfig.dir = './mock'; + testConfig.norpc = false; + testConfig.port = 8888; - // Run script (exits 0); - mock.install('Oraclize.sol', 'oraclize.js', config, trufflejs, null, true); + // Installed test will write a fake allFiredEvents to ./ after 4000ms + // allowing test to pass + mock.install('Simple.sol', 'command-options.js', testConfig); shell.exec(script); assert(shell.error() === null, 'script should not error'); }); it('simple contract: should generate coverage, cleanup & exit(0)', () => { - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run script (exits 0); mock.install('Simple.sol', 'simple.js', config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); // Coverage should be real. // This test is tightly bound to the function names in Simple.sol @@ -243,53 +87,46 @@ describe('app', () => { const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); + }); - it('project uses truffle-config.js: should generate coverage, cleanup and exit(0)', () => { - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + it('Oraclize @ solc v.0.4.24 (large, many unbracketed statements)', () => { + const trufflejs = + `module.exports = { + networks: { + coverage: { + host: "localhost", + network_id: "*", + port: 8555, + gas: 0xfffffffffff, + gasPrice: 0x01 + }, + }, + compilers: { + solc: { + version: "0.4.24", + } + } + };`; + + assertCleanInitialState(); // Run script (exits 0); - mock.install('Simple.sol', 'simple.js', config, null, 'truffle-config.js'); + mock.install('Oraclize.sol', 'oraclize.js', config, trufflejs, null, true); shell.exec(script); assert(shell.error() === null, 'script should not error'); - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); - - // Coverage should be real. - // This test is tightly bound to the function names in Simple.sol - const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); - const path = Object.keys(produced)[0]; - assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); - assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); - }); - - it('testrpc-sc signs and recovers messages correctly', () => { - // sign.js signs and recovers - mock.install('Simple.sol', 'sign.js', config); - shell.exec(script); - assert(shell.error() === null, 'script should not error'); - collectGarbage(); }); it('tests use pure and view modifiers, including with libraries', () => { - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run script (exits 0); mock.installLibraryTest(config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); // Coverage should be real. // This test is tightly bound to the function names in TotallyPure.sol @@ -297,22 +134,18 @@ describe('app', () => { const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'usesThem', 'coverage.json should map "usesThem"'); assert(produced[path].fnMap['2'].name === 'isPure', 'coverage.json should map "getX"'); - collectGarbage(); + }); it('tests require assets outside of test folder: should generate coverage, cleanup & exit(0)', () => { - // Directory should be clean - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run script (exits 0); mock.install('Simple.sol', 'requires-externally.js', config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - // Directory should have coverage report - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); // Coverage should be real. // This test is tightly bound to the function names in Simple.sol @@ -320,70 +153,59 @@ describe('app', () => { const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); + }); it('contract only uses .call: should generate coverage, cleanup & exit(0)', () => { - // Run against contract that only uses method.call. - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); + mock.install('OnlyCall.sol', 'only-call.js', config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'addTwo', 'coverage.json should map "addTwo"'); - collectGarbage(); + }); it('contract sends / transfers to instrumented fallback: coverage, cleanup & exit(0)', () => { - // Skipped due to https://github.com/sc-forks/solidity-coverage/issues/106 - // Validate ethereumjs-vm hack to remove gas constraints on transfer() and send() - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); mock.install('Wallet.sol', 'wallet.js', config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'transferPayment', 'should map "transferPayment"'); - collectGarbage(); + }); it('contract uses inheritance: should generate coverage, cleanup & exit(0)', () => { - // Run against a contract that 'is' another contract - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); - mock.installInheritanceTest(config); + assertCleanInitialState(); + mock.installInheritanceTest(config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const ownedPath = Object.keys(produced)[0]; const proxyPath = Object.keys(produced)[1]; assert(produced[ownedPath].fnMap['1'].name === 'constructor', 'coverage.json should map "constructor"'); assert(produced[proxyPath].fnMap['1'].name === 'isOwner', 'coverage.json should map "isOwner"'); - collectGarbage(); }); it('contracts are skipped: should generate coverage, cleanup & exit(0)', () => { - // Skip instrumentation of some contracts - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); + const testConfig = Object.assign({}, config); testConfig.skipFiles = ['Owned.sol']; @@ -392,32 +214,30 @@ describe('app', () => { shell.exec(script); assert(shell.error() === null, 'script should not error'); - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + assertCoverageGenerated(); const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const firstKey = Object.keys(produced)[0]; assert(Object.keys(produced).length === 1, 'coverage.json should only contain instrumentation for one contract'); assert(firstKey.substr(firstKey.length - 9) === 'Proxy.sol', 'coverage.json should only contain instrumentation for Proxy.sol'); - collectGarbage(); + }); it('truffle tests failing: should generate coverage, cleanup & exit(1)', () => { - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run with Simple.sol and a failing assertion in a truffle test mock.install('Simple.sol', 'truffle-test-fail.js', config); shell.exec(script); assert(shell.error() !== null, 'script should exit 1'); - assert(pathExists('./coverage') === true, 'script should gen coverage folder'); - assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); + + assertCoverageGenerated(); const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'test', 'coverage.json should map "test"'); assert(produced[path].fnMap['2'].name === 'getX', 'coverage.json should map "getX"'); - collectGarbage(); + }); it('deployment cost > block gasLimit: should generate coverage, cleanup & exit(0)', () => { @@ -425,44 +245,27 @@ describe('app', () => { mock.install('Expensive.sol', 'block-gas-limit.js', config); shell.exec(script); assert(shell.error() === null, 'script should not error'); - collectGarbage(); + }); it('truffle crashes: should generate NO coverage, cleanup and exit(1)', () => { - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run with Simple.sol and a syntax error in the truffle test mock.install('Simple.sol', 'truffle-crash.js', config); shell.exec(script); assert(shell.error() !== null, 'script should error'); - assert(pathExists('./coverage') !== true, 'script should NOT gen coverage folder'); - assert(pathExists('./coverage.json') !== true, 'script should NOT gen coverage.json'); - collectGarbage(); + assertCoverageNotGenerated(); }); it('instrumentation errors: should generate NO coverage, cleanup and exit(1)', () => { - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); + assertCleanInitialState(); // Run with SimpleError.sol (has syntax error) and working truffle test mock.install('SimpleError.sol', 'simple.js', config); shell.exec(script); assert(shell.error() !== null, 'script should error'); - assert(pathExists('./coverage') !== true, 'script should NOT gen coverage folder'); - assert(pathExists('./coverage.json') !== true, 'script should NOT gen coverage.json'); - collectGarbage(); + assertCoverageNotGenerated(); }); - it('no events log produced: should generate NO coverage, cleanup and exit(1)', () => { - // Run contract and test that pass but fire no events - assert(pathExists('./coverage') === false, 'should start without: coverage'); - assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); - mock.install('Empty.sol', 'empty.js', config); - shell.exec(script); - assert(shell.error() !== null, 'script should error'); - assert(pathExists('./coverage') !== true, 'script should NOT gen coverage folder'); - assert(pathExists('./coverage.json') !== true, 'script should NOT gen coverage.json'); - collectGarbage(); - }); -});*/ +});