From 1a54efddc9a342e73d411c310e55e235cc263828 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Sun, 23 Aug 2020 16:51:12 -0700 Subject: [PATCH 1/2] chore: update 'cosmic-swingset' package to use AVA refs #1568 --- packages/cosmic-swingset/package.json | 17 +- packages/cosmic-swingset/test/test-home.js | 195 +++++++-------- packages/cosmic-swingset/test/test-make.js | 26 +- .../test/test-scenario3-setup.js | 26 +- .../test/unitTests/test-lib-board.js | 32 +-- .../test/unitTests/test-repl.js | 233 ++++++++---------- 6 files changed, 234 insertions(+), 295 deletions(-) diff --git a/packages/cosmic-swingset/package.json b/packages/cosmic-swingset/package.json index 955e146ba45..9b4a3abcad3 100644 --- a/packages/cosmic-swingset/package.json +++ b/packages/cosmic-swingset/package.json @@ -8,7 +8,7 @@ "build": "exit 0", "build:gyp": "make compile-gyp", "build:gyp-debug": "make compile-gyp GYP_DEBUG=--debug", - "test": "tap --no-coverage --jobs=1 --timeout 600 'test/**/test*.js'", + "test": "ava --serial", "pretty-fix": "prettier --write '**/*.js'", "pretty-check": "prettier --check '**/*.js'", "lint-fix": "yarn lint --fix", @@ -66,16 +66,23 @@ "ws": "^7.2.0" }, "devDependencies": { + "ava": "3.11.1", "napi-thread-safe-callback": "0.0.6", - "node-addon-api": "^1.7.1", - "tap": "^14.10.5", - "tape": "^4.11.0", - "tape-promise": "^4.0.0" + "node-addon-api": "^1.7.1" }, "publishConfig": { "access": "public" }, "engines": { "node": ">=11.0" + }, + "ava": { + "files": [ + "test/**/test-*.js" + ], + "require": [ + "esm" + ], + "timeout": "10m" } } diff --git a/packages/cosmic-swingset/test/test-home.js b/packages/cosmic-swingset/test/test-home.js index 1bd4641bb85..0a09be3c5ce 100644 --- a/packages/cosmic-swingset/test/test-home.js +++ b/packages/cosmic-swingset/test/test-home.js @@ -1,5 +1,5 @@ import '@agoric/install-ses'; -import { test } from 'tape-promise/tape'; +import test from 'ava'; import bundleSource from '@agoric/bundle-source'; import { makeFixture, E } from './captp-fixture'; @@ -7,128 +7,99 @@ import { makeFixture, E } from './captp-fixture'; // This runs before all the tests. let home; let teardown; -test('setup', async t => { - try { - const { homeP, kill } = makeFixture(); - teardown = kill; - home = await homeP; - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } +test.before('setup', async t => { + const { homeP, kill } = makeFixture(); + teardown = kill; + home = await homeP; + t.truthy('ready'); }); // Now come the tests that use `home`... // ========================================= -test('home.registry', async t => { - try { - const { registry } = E.G(home); - const regVal = await E(registry).get('foolobr_19191'); - t.equals(regVal, undefined, 'random registry name is undefined'); - - const target = 'something'; - const myRegKey = await E(registry).register('myname', target); - t.equals(typeof myRegKey, 'string', 'registry key is string'); - - const registered = await E(registry).get(myRegKey); - t.equals(registered, target, 'registry registers target'); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } +test.serial('home.registry', async t => { + const { registry } = E.G(home); + const regVal = await E(registry).get('foolobr_19191'); + t.is(regVal, undefined, 'random registry name is undefined'); + + const target = 'something'; + const myRegKey = await E(registry).register('myname', target); + t.is(typeof myRegKey, 'string', 'registry key is string'); + + const registered = await E(registry).get(myRegKey); + t.is(registered, target, 'registry registers target'); }); -test('home.board', async t => { - try { - const { board } = E.G(home); - t.rejects( - () => E(board).getValue('0000000000'), - `getting a value for a fake id throws`, - ); - - const myValue = {}; - const myId = await E(board).getId(myValue); - t.equals(typeof myId, 'string', `board key is string`); - - const valueInBoard = await E(board).getValue(myId); - t.deepEquals(valueInBoard, myValue, `board contains myValue`); - - const myId2 = await E(board).getId(myValue); - t.equals(myId2, myId, `board gives the same id for the same value`); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } +test.serial('home.board', async t => { + const { board } = E.G(home); + t.throwsAsync( + () => E(board).getValue('0000000000'), + { message: /board does not have id/ }, + `getting a value for a fake id throws`, + ); + + const myValue = {}; + const myId = await E(board).getId(myValue); + t.is(typeof myId, 'string', `board key is string`); + + const valueInBoard = await E(board).getValue(myId); + t.deepEqual(valueInBoard, myValue, `board contains myValue`); + + const myId2 = await E(board).getId(myValue); + t.is(myId2, myId, `board gives the same id for the same value`); }); -test('home.wallet - receive zoe invite', async t => { - try { - const { wallet, zoe, board } = E.G(home); - - // Setup contract in order to get an invite to use in tests - const contractRoot = require.resolve( - '@agoric/zoe/src/contracts/automaticRefund', - ); - const bundle = await bundleSource(contractRoot); - const installationHandle = await E(zoe).install(bundle); - const { creatorInvitation: invite } = await E(zoe).startInstance( - installationHandle, - ); - - // Check that the wallet knows about the Zoe invite issuer and starts out - // with a default Zoe invite issuer purse. - const zoeInviteIssuer = await E(zoe).getInvitationIssuer(); - const issuers = await E(wallet).getIssuers(); - const issuersMap = new Map(issuers); - t.deepEquals( - issuersMap.get('zoe invite'), - zoeInviteIssuer, - `wallet knows about the Zoe invite issuer`, - ); - const invitePurse = await E(wallet).getPurse('Default Zoe invite purse'); - const zoeInviteBrand = await E(invitePurse).getAllegedBrand(); - t.equals( - zoeInviteBrand, - await E(zoeInviteIssuer).getBrand(), - `invite purse is actually a zoe invite purse`, - ); - - // The code below is meant to be carried out in a Dapp backend. - // The dapp gets the depositBoardId for the default Zoe invite purse - // and sends the invite. - const inviteBrandBoardId = await E(board).getId(zoeInviteBrand); - const depositBoardId = await E(wallet).getDepositFacetId( - inviteBrandBoardId, - ); - const depositFacet = await E(board).getValue(depositBoardId); - await E(depositFacet).receive(invite); - - // The invite was successfully received in the user's wallet. - const invitePurseBalance = await E(invitePurse).getCurrentAmount(); - t.equals( - invitePurseBalance.value[0].description, - 'getRefund', - `invite successfully deposited`, - ); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } +test.serial('home.wallet - receive zoe invite', async t => { + const { wallet, zoe, board } = E.G(home); + + // Setup contract in order to get an invite to use in tests + const contractRoot = require.resolve( + '@agoric/zoe/src/contracts/automaticRefund', + ); + const bundle = await bundleSource(contractRoot); + const installationHandle = await E(zoe).install(bundle); + const { creatorInvitation: invite } = await E(zoe).startInstance( + installationHandle, + ); + + // Check that the wallet knows about the Zoe invite issuer and starts out + // with a default Zoe invite issuer purse. + const zoeInviteIssuer = await E(zoe).getInvitationIssuer(); + const issuers = await E(wallet).getIssuers(); + const issuersMap = new Map(issuers); + t.deepEqual( + issuersMap.get('zoe invite'), + zoeInviteIssuer, + `wallet knows about the Zoe invite issuer`, + ); + const invitePurse = await E(wallet).getPurse('Default Zoe invite purse'); + const zoeInviteBrand = await E(invitePurse).getAllegedBrand(); + t.is( + zoeInviteBrand, + await E(zoeInviteIssuer).getBrand(), + `invite purse is actually a zoe invite purse`, + ); + + // The code below is meant to be carried out in a Dapp backend. + // The dapp gets the depositBoardId for the default Zoe invite purse + // and sends the invite. + const inviteBrandBoardId = await E(board).getId(zoeInviteBrand); + const depositBoardId = await E(wallet).getDepositFacetId(inviteBrandBoardId); + const depositFacet = await E(board).getValue(depositBoardId); + await E(depositFacet).receive(invite); + + // The invite was successfully received in the user's wallet. + const invitePurseBalance = await E(invitePurse).getCurrentAmount(); + t.is( + invitePurseBalance.value[0].description, + 'getRefund', + `invite successfully deposited`, + ); }); // ========================================= // This runs after all the tests. -test('teardown', async t => { - try { - await teardown(); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } +test.after.always('teardown', async t => { + await teardown(); + t.truthy('shutdown'); }); diff --git a/packages/cosmic-swingset/test/test-make.js b/packages/cosmic-swingset/test/test-make.js index e722aeb8cc6..e115b044250 100644 --- a/packages/cosmic-swingset/test/test-make.js +++ b/packages/cosmic-swingset/test/test-make.js @@ -1,20 +1,14 @@ -import { test } from 'tape-promise/tape'; +import test from 'ava'; import { spawn } from 'child_process'; test('make', async t => { - try { - await new Promise(resolve => - spawn('make', { - cwd: `${__dirname}/..`, - stdio: ['ignore', 'ignore', 'inherit'], - }).addListener('exit', code => { - t.equal(code, 0, 'exits successfully'); - resolve(); - }), - ); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } + await new Promise(resolve => + spawn('make', { + cwd: `${__dirname}/..`, + stdio: ['ignore', 'ignore', 'inherit'], + }).addListener('exit', code => { + t.is(code, 0, 'exits successfully'); + resolve(); + }), + ); }); diff --git a/packages/cosmic-swingset/test/test-scenario3-setup.js b/packages/cosmic-swingset/test/test-scenario3-setup.js index 2899650a77f..76830747ae7 100644 --- a/packages/cosmic-swingset/test/test-scenario3-setup.js +++ b/packages/cosmic-swingset/test/test-scenario3-setup.js @@ -1,20 +1,14 @@ -import { test } from 'tape-promise/tape'; +import test from 'ava'; import { spawn } from 'child_process'; test('make scenario3-setup', async t => { - try { - await new Promise(resolve => - spawn('make', ['scenario3-setup'], { - cwd: `${__dirname}/..`, - stdio: ['ignore', 'ignore', 'inherit'], - }).addListener('exit', code => { - t.equal(code, 0, 'exits successfully'); - resolve(); - }), - ); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } + await new Promise(resolve => + spawn('make', ['scenario3-setup'], { + cwd: `${__dirname}/..`, + stdio: ['ignore', 'ignore', 'inherit'], + }).addListener('exit', code => { + t.is(code, 0, 'exits successfully'); + resolve(); + }), + ); }); diff --git a/packages/cosmic-swingset/test/unitTests/test-lib-board.js b/packages/cosmic-swingset/test/unitTests/test-lib-board.js index 768b36aee06..11eeccaba95 100644 --- a/packages/cosmic-swingset/test/unitTests/test-lib-board.js +++ b/packages/cosmic-swingset/test/unitTests/test-lib-board.js @@ -2,33 +2,27 @@ // eslint-disable-next-line import/no-extraneous-dependencies import '@agoric/install-ses'; -import { test } from 'tape-promise/tape'; +import test from 'ava'; import { makeBoard } from '../../lib/ag-solo/vats/lib-board'; test('makeBoard', async t => { - try { - const board = makeBoard(); + const board = makeBoard(); - const obj1 = harden({}); - const obj2 = harden({}); + const obj1 = harden({}); + const obj2 = harden({}); - t.deepEquals(board.ids(), [], `board is empty to start`); + t.deepEqual(board.ids(), [], `board is empty to start`); - const idObj1 = board.getId(obj1); - t.deepEquals(board.ids(), [idObj1], `board has one id`); + const idObj1 = board.getId(obj1); + t.deepEqual(board.ids(), [idObj1], `board has one id`); - const idObj2 = board.getId(obj2); - t.deepEquals(board.ids().length, 2, `board has two ids`); + const idObj2 = board.getId(obj2); + t.deepEqual(board.ids().length, 2, `board has two ids`); - t.deepEquals(board.getValue(idObj1), obj1, `id matches value obj1`); - t.deepEquals(board.getValue(idObj2), obj2, `id matches value obj2`); + t.deepEqual(board.getValue(idObj1), obj1, `id matches value obj1`); + t.deepEqual(board.getValue(idObj2), obj2, `id matches value obj2`); - t.deepEquals(board.getId(obj1), idObj1, `value matches id obj1`); - t.deepEquals(board.getId(obj2), idObj2, `value matches id obj2`); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } + t.deepEqual(board.getId(obj1), idObj1, `value matches id obj1`); + t.deepEqual(board.getId(obj2), idObj2, `value matches id obj2`); }); diff --git a/packages/cosmic-swingset/test/unitTests/test-repl.js b/packages/cosmic-swingset/test/unitTests/test-repl.js index db738d332aa..30aeabb0bf0 100644 --- a/packages/cosmic-swingset/test/unitTests/test-repl.js +++ b/packages/cosmic-swingset/test/unitTests/test-repl.js @@ -2,7 +2,7 @@ import '@agoric/install-ses'; import { makeTransform } from '@agoric/transform-eventual-send'; import * as babelParser from '@agoric/babel-parser'; import babelGenerate from '@babel/generator'; -import { test } from 'tape-promise/tape'; +import test from 'ava'; import { getReplHandler } from '../../lib/ag-solo/vats/repl'; function make() { @@ -27,136 +27,115 @@ function make() { } test('repl: basic eval, eventual promise resolution', async t => { - try { - const { doEval, sentMessages, getHighestHistory } = make(); - - let m = sentMessages.shift(); - t.deepEquals(m.type, 'updateHistory'); - t.equals(sentMessages.length, 0); - - t.deepEquals(getHighestHistory(), { highestHistory: -1 }); - t.equals(sentMessages.length, 0); - - t.deepEquals(doEval(0, '1+2'), {}); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.equals(m.display, 'working on eval(1+2)'); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.equals(m.display, '3'); - t.deepEquals(sentMessages, []); - - // exercise eventual promise resolution - t.deepEquals(doEval(1, 'Promise.resolve(3)'), {}); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, 'working on eval(Promise.resolve(3))'); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, 'unresolved Promise'); - t.deepEquals(sentMessages, []); - await Promise.resolve(); - await Promise.resolve(); // I don't know why two stalls are needed - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, '3'); - t.deepEquals(sentMessages, []); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - throw e; - } finally { - t.end(); - } + const { doEval, sentMessages, getHighestHistory } = make(); + + let m = sentMessages.shift(); + t.deepEqual(m.type, 'updateHistory'); + t.is(sentMessages.length, 0); + + t.deepEqual(getHighestHistory(), { highestHistory: -1 }); + t.is(sentMessages.length, 0); + + t.deepEqual(doEval(0, '1+2'), {}); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.is(m.display, 'working on eval(1+2)'); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.is(m.display, '3'); + t.deepEqual(sentMessages, []); + + // exercise eventual promise resolution + t.deepEqual(doEval(1, 'Promise.resolve(3)'), {}); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, 'working on eval(Promise.resolve(3))'); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, 'unresolved Promise'); + t.deepEqual(sentMessages, []); + await Promise.resolve(); + await Promise.resolve(); // I don't know why two stalls are needed + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, '3'); + t.deepEqual(sentMessages, []); }); test('repl: sloppyGlobals, home, endowments', async t => { - try { - const { doEval, sentMessages } = make(); - - let m = sentMessages.shift(); - t.deepEquals(m.type, 'updateHistory'); - t.equals(sentMessages.length, 0); - - t.deepEquals( - doEval(0, 'newGlobal = home.base + home.fries + home.cooking'), - {}, - ); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.ok(m.display.startsWith('working on eval(newGlobal')); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.equals(m.display, '6'); - t.deepEquals(sentMessages, []); - - t.deepEquals(doEval(1, 'newGlobal'), {}); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.ok(m.display.startsWith('working on eval(newGlobal')); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, '6'); - t.deepEquals(sentMessages, []); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - throw e; - } finally { - t.end(); - } + const { doEval, sentMessages } = make(); + + let m = sentMessages.shift(); + t.deepEqual(m.type, 'updateHistory'); + t.is(sentMessages.length, 0); + + t.deepEqual( + doEval(0, 'newGlobal = home.base + home.fries + home.cooking'), + {}, + ); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.truthy(m.display.startsWith('working on eval(newGlobal')); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.is(m.display, '6'); + t.deepEqual(sentMessages, []); + + t.deepEqual(doEval(1, 'newGlobal'), {}); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.truthy(m.display.startsWith('working on eval(newGlobal')); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, '6'); + t.deepEqual(sentMessages, []); }); test('repl: tildot', async t => { - try { - const { doEval, sentMessages } = make(); - - let m = sentMessages.shift(); - t.deepEquals(m.type, 'updateHistory'); - t.equals(sentMessages.length, 0); - - t.deepEquals(doEval(0, 'target = harden({ foo(x) { return x+1; } })'), {}); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.ok(m.display.startsWith('working on eval(target =')); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 0); - t.equals(m.display, '{"foo":[Function foo]}'); - t.deepEquals(sentMessages, []); - - t.deepEquals(doEval(1, 'target~.foo(2)'), {}); - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, 'working on eval(target~.foo(2))'); - - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, 'unresolved Promise'); - - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); // I don't know why three stalls are needed - - m = sentMessages.shift(); - t.equals(m.type, 'updateHistory'); - t.equals(m.histnum, 1); - t.equals(m.display, '3'); - t.deepEquals(sentMessages, []); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - throw e; - } finally { - t.end(); - } + const { doEval, sentMessages } = make(); + + let m = sentMessages.shift(); + t.deepEqual(m.type, 'updateHistory'); + t.is(sentMessages.length, 0); + + t.deepEqual(doEval(0, 'target = harden({ foo(x) { return x+1; } })'), {}); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.truthy(m.display.startsWith('working on eval(target =')); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 0); + t.is(m.display, '{"foo":[Function foo]}'); + t.deepEqual(sentMessages, []); + + t.deepEqual(doEval(1, 'target~.foo(2)'), {}); + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, 'working on eval(target~.foo(2))'); + + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, 'unresolved Promise'); + + await Promise.resolve(); + await Promise.resolve(); + await Promise.resolve(); // I don't know why three stalls are needed + + m = sentMessages.shift(); + t.is(m.type, 'updateHistory'); + t.is(m.histnum, 1); + t.is(m.display, '3'); + t.deepEqual(sentMessages, []); }); From 37b6a40a9d4e0c69bde3a744d78311b1b702f93c Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Sun, 23 Aug 2020 17:57:59 -0700 Subject: [PATCH 2/2] chore: delete test-scenario3-setup.js, test files in parallel Per @michaelfig, test-scenario3-setup.js is not necessary, because test-home exercises the same thing. By removing it, we can run all the test *files* in parallel (removing the `ava --serial` argument). We still run the test *functions* within `test-home.js` serially, because they all interact with the same running system. But by removing `--serial`, we will be able to run the top-level `yarn test` in parallel across all packages. --- .../cosmic-swingset/test/test-scenario3-setup.js | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 packages/cosmic-swingset/test/test-scenario3-setup.js diff --git a/packages/cosmic-swingset/test/test-scenario3-setup.js b/packages/cosmic-swingset/test/test-scenario3-setup.js deleted file mode 100644 index 76830747ae7..00000000000 --- a/packages/cosmic-swingset/test/test-scenario3-setup.js +++ /dev/null @@ -1,14 +0,0 @@ -import test from 'ava'; -import { spawn } from 'child_process'; - -test('make scenario3-setup', async t => { - await new Promise(resolve => - spawn('make', ['scenario3-setup'], { - cwd: `${__dirname}/..`, - stdio: ['ignore', 'ignore', 'inherit'], - }).addListener('exit', code => { - t.is(code, 0, 'exits successfully'); - resolve(); - }), - ); -});