diff --git a/packages/async-flow/test/replay-membrane-eventual.test.js b/packages/async-flow/test/replay-membrane-eventual.test.js index 460b89643481..b4ad7158d6a2 100644 --- a/packages/async-flow/test/replay-membrane-eventual.test.js +++ b/packages/async-flow/test/replay-membrane-eventual.test.js @@ -20,7 +20,6 @@ import { prepareBijection } from '../src/bijection.js'; import { makeReplayMembrane } from '../src/replay-membrane.js'; /** - * @import {PromiseKit} from '@endo/promise-kit' * @import {Zone} from '@agoric/base-zone' * @import {LogStore} from '../src/log-store.js'; * @import {Bijection} from '../src/bijection.js'; @@ -41,11 +40,19 @@ const preparePingee = zone => * @typedef {ReturnType>} Pingee */ +const testMode = /** @type {const} */ ({ + normal: 'normal', + noEventualSend: 'noEventualSend', + retry: 'retry', +}); + /** * @param {any} t * @param {Zone} zone + * @param {testMode[keyof testMode]} [mode] */ -const testFirstPlay = async (t, zone) => { +const testFirstPlay = async (t, zone, mode = testMode.normal) => { + t.log('testFirstPlay', mode); const vowTools = prepareVowTools(zone); const { makeVowKit } = vowTools; const makeLogStore = prepareLogStore(zone); @@ -63,6 +70,7 @@ const testFirstPlay = async (t, zone) => { vowTools, watchWake, panic, + enableEventualSend: mode !== testMode.noEventualSend, }); const p1 = mem.hostToGuest(v1); @@ -109,8 +117,10 @@ const testFirstPlay = async (t, zone) => { /** * @param {any} t * @param {Zone} zone + * @param {testMode[keyof testMode]} [mode] */ -const testReplay = async (t, zone) => { +const testReplay = async (t, zone, mode = testMode.normal) => { + t.log('testReplay', mode); const vowTools = prepareVowTools(zone); prepareLogStore(zone); prepareBijection(zone); @@ -129,7 +139,7 @@ const testReplay = async (t, zone) => { const dump = log.dump(); const v3 = dump[3][2]; - t.deepEqual(dump, [ + const beforeY = [ ['checkCall', pingee, 'ping', ['call'], 0], ['doReturn', 0, undefined], ['checkSend', pingee, 'ping', ['send'], 2], @@ -137,7 +147,10 @@ const testReplay = async (t, zone) => { ['checkSendOnly', pingee, 'ping', ['sendOnly'], 4], ['doFulfill', v3, undefined], ['doFulfill', v1, 'x'], - ]); + ]; + const afterY = [['doFulfill', v2, 'y']]; + const initialDump = beforeY; + t.deepEqual(dump, initialDump); const mem = makeReplayMembrane({ log, @@ -145,6 +158,7 @@ const testReplay = async (t, zone) => { vowTools, watchWake, panic, + enableEventualSend: mode !== testMode.noEventualSend, }); t.true(log.isReplaying()); t.is(log.getIndex(), 0); @@ -159,17 +173,10 @@ const testReplay = async (t, zone) => { mem.wake(); t.true(log.isReplaying()); t.is(log.getIndex(), 0); - t.deepEqual(log.dump(), [ - ['checkCall', pingee, 'ping', ['call'], 0], - ['doReturn', 0, undefined], - ['checkSend', pingee, 'ping', ['send'], 2], - ['doReturn', 2, v3], - ['checkSendOnly', pingee, 'ping', ['sendOnly'], 4], - ['doFulfill', v3, undefined], - ['doFulfill', v1, 'x'], - ]); + t.deepEqual(log.dump(), initialDump); + + const pingSend = E(guestPingee).ping('send'); - E(guestPingee).ping('send'); // TODO Once https://github.com/endojs/endo/issues/2336 is fixed, // the following `void` should not be needed. But strangely, TS isn't // telling me a `void` is needed above, which is also incorrect. @@ -177,20 +184,21 @@ const testReplay = async (t, zone) => { guestPingee.ping('call'); - t.is(await p1, 'x'); - t.is(await p2, 'y'); - t.false(log.isReplaying()); + let finalDump; + if (mode === testMode.noEventualSend) { + t.true(log.isReplaying()); + finalDump = beforeY; + } else { + t.is(await p1, 'x'); + t.is(await p2, 'y'); + t.false(log.isReplaying()); + finalDump = [...beforeY, ...afterY]; + } - t.deepEqual(log.dump(), [ - ['checkCall', pingee, 'ping', ['call'], 0], - ['doReturn', 0, undefined], - ['checkSend', pingee, 'ping', ['send'], 2], - ['doReturn', 2, v3], - ['checkSendOnly', pingee, 'ping', ['sendOnly'], 4], - ['doFulfill', v3, undefined], - ['doFulfill', v1, 'x'], - ['doFulfill', v2, 'y'], - ]); + await eventLoopIteration(); + + t.deepEqual(log.dump(), finalDump); + return pingSend; }; test.serial('test heap replay-membrane settlement', async t => { @@ -215,3 +223,22 @@ test.serial('test durable replay-membrane settlement', async t => { const zone3 = makeDurableZone(getBaggage(), 'durableRoot'); return testReplay(t, zone3); }); + +test.serial('test durable disabled eventual send', async t => { + annihilate(); + + nextLife(); + const zone1 = makeDurableZone(getBaggage(), 'durableRoot'); + await testFirstPlay(t, zone1); + + nextLife(); + const zone2 = makeDurableZone(getBaggage(), 'durableRoot'); + await t.throwsAsync(() => testReplay(t, zone2, testMode.noEventualSend), { + message: /^panic over "\[Error: guest eventual applyMethod not enabled:/, + }); + + await eventLoopIteration(); + nextLife(); + const zone3 = makeDurableZone(getBaggage(), 'durableRoot'); + await testReplay(t, zone3, testMode.retry); +});