@agoric/async-flow 0.1.1-calypso-dev-84eb287.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE +201 -0
  3. package/README.md +40 -0
  4. package/docs/async-flow-states.key +0 -0
  5. package/docs/async-flow-states.md +15 -0
  6. package/docs/async-flow-states.png +0 -0
  7. package/index.d.ts +3 -0
  8. package/index.d.ts.map +1 -0
  9. package/index.js +2 -0
  10. package/package.json +66 -0
  11. package/src/async-flow.d.ts +94 -0
  12. package/src/async-flow.d.ts.map +1 -0
  13. package/src/async-flow.js +520 -0
  14. package/src/bijection.d.ts +31 -0
  15. package/src/bijection.d.ts.map +1 -0
  16. package/src/bijection.js +207 -0
  17. package/src/convert.d.ts +6 -0
  18. package/src/convert.d.ts.map +1 -0
  19. package/src/convert.js +133 -0
  20. package/src/endowments.d.ts +16 -0
  21. package/src/endowments.d.ts.map +1 -0
  22. package/src/endowments.js +292 -0
  23. package/src/ephemera.d.ts +3 -0
  24. package/src/ephemera.d.ts.map +1 -0
  25. package/src/ephemera.js +39 -0
  26. package/src/equate.d.ts +2 -0
  27. package/src/equate.d.ts.map +1 -0
  28. package/src/equate.js +123 -0
  29. package/src/log-store.d.ts +27 -0
  30. package/src/log-store.d.ts.map +1 -0
  31. package/src/log-store.js +169 -0
  32. package/src/replay-membrane.d.ts +40 -0
  33. package/src/replay-membrane.d.ts.map +1 -0
  34. package/src/replay-membrane.js +752 -0
  35. package/src/type-guards.d.ts +4 -0
  36. package/src/type-guards.d.ts.map +1 -0
  37. package/src/type-guards.js +68 -0
  38. package/src/types.d.ts +67 -0
  39. package/src/types.d.ts.map +1 -0
  40. package/src/types.js +196 -0
  41. package/test/async-flow-crank.test.js +102 -0
  42. package/test/async-flow-early-completion.test.js +203 -0
  43. package/test/async-flow-no-this.js +65 -0
  44. package/test/async-flow.test.js +383 -0
  45. package/test/bad-host.test.js +210 -0
  46. package/test/bijection.test.js +124 -0
  47. package/test/convert.test.js +132 -0
  48. package/test/endowments.test.js +157 -0
  49. package/test/equate.test.js +120 -0
  50. package/test/log-store.test.js +120 -0
  51. package/test/prepare-test-env-ava.js +28 -0
  52. package/test/replay-membrane-eventual.test.js +217 -0
  53. package/test/replay-membrane-settlement.test.js +173 -0
  54. package/test/replay-membrane-zombie.test.js +187 -0
  55. package/test/replay-membrane.test.js +297 -0
  56. package/tsconfig.build.json +11 -0
  57. package/tsconfig.json +13 -0
  58. package/typedoc.json +8 -0
@@ -0,0 +1,124 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Far } from '@endo/pass-style';
10
+ import { prepareVowTools } from '@agoric/vow';
11
+ import { isVow, toPassableCap } from '@agoric/vow/src/vow-utils.js';
12
+ import { makeHeapZone } from '@agoric/zone/heap.js';
13
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
14
+ import { makeDurableZone } from '@agoric/zone/durable.js';
15
+
16
+ import { prepareBijection } from '../src/bijection.js';
17
+
18
+ /**
19
+ * @import {PromiseKit} from '@endo/promise-kit'
20
+ * @import {Zone} from '@agoric/base-zone'
21
+ * @import {Ephemera} from './types.js';
22
+ */
23
+
24
+ /**
25
+ * @param {any} t
26
+ * @param {Zone} zone
27
+ */
28
+ const testBijection = (t, zone) => {
29
+ const { makeVowKit } = prepareVowTools(zone);
30
+ const makeBijection = prepareBijection(zone);
31
+ const bij = zone.makeOnce('bij', makeBijection);
32
+
33
+ const h1 = zone.exo('h1', undefined, {});
34
+ const h2 = zone.exo('h2', undefined, {});
35
+ const h3 = zone.makeOnce('h3', () => makeVowKit().vow);
36
+ t.true(isVow(h3));
37
+
38
+ const g1 = Far('g1', {});
39
+ const g2 = Far('g2', {});
40
+ const g3 = harden(Promise.resolve('g3'));
41
+
42
+ t.false(bij.has(g1, h1));
43
+ t.throws(() => bij.guestToHost(g1), {
44
+ message: 'guestToHost key not found: "[Alleged: g1]"',
45
+ });
46
+ t.throws(() => bij.hostToGuest(h1), {
47
+ message: 'hostToGuest key not found: "[Alleged: h1]"',
48
+ });
49
+ t.false(bij.hasGuest(g1));
50
+ t.false(bij.hasHost(h1));
51
+ t.false(bij.hasGuest(h1));
52
+ t.false(bij.hasHost(g1));
53
+
54
+ bij.unwrapInit(g1, h1);
55
+
56
+ t.true(bij.has(g1, h1));
57
+ t.is(toPassableCap(bij.guestToHost(g1)), toPassableCap(h1));
58
+ t.is(bij.hostToGuest(h1), g1);
59
+ t.true(bij.hasGuest(g1));
60
+ t.true(bij.hasHost(h1));
61
+ t.false(bij.hasGuest(h1));
62
+ t.false(bij.hasHost(g1));
63
+
64
+ t.throws(() => bij.unwrapInit(g1, h2), {
65
+ message:
66
+ 'guestToHost key already bound: "[Alleged: g1]" -> "[Alleged: h1]" vs "[Alleged: h2]"',
67
+ });
68
+ t.throws(() => bij.unwrapInit(g2, h1), {
69
+ message:
70
+ 'hostToGuest key already bound: "[Alleged: h1]" -> "[Alleged: g1]" vs "[Alleged: g2]"',
71
+ });
72
+ t.throws(() => bij.has(g1, h2), {
73
+ message:
74
+ 'internal: g->h "[Alleged: g1]" -> "[Alleged: h2]" vs "[Alleged: h1]"',
75
+ });
76
+ t.false(bij.has(g2, h2));
77
+ bij.unwrapInit(g2, h2);
78
+ t.true(bij.has(g2, h2));
79
+
80
+ t.false(bij.has(g3, h3));
81
+ bij.unwrapInit(g3, h3);
82
+ t.true(bij.has(g3, h3));
83
+ t.false(bij.has(h3, g3));
84
+ };
85
+
86
+ test('test heap bijection', t => {
87
+ const zone = makeHeapZone('heapRoot');
88
+ testBijection(t, zone);
89
+ });
90
+
91
+ test.serial('test virtual bijection', t => {
92
+ annihilate();
93
+ const zone = makeVirtualZone('virtualRoot');
94
+ testBijection(t, zone);
95
+ });
96
+
97
+ test.serial('test durable bijection', t => {
98
+ annihilate();
99
+
100
+ nextLife();
101
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
102
+ testBijection(t, zone1);
103
+
104
+ // Bijections persist but revive empty since all the guests disappear anyway
105
+
106
+ nextLife();
107
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
108
+ testBijection(t, zone2);
109
+ });
110
+
111
+ test('test heap bijection reset', t => {
112
+ const zone = makeHeapZone('heapRoot');
113
+ const makeBijection = prepareBijection(zone);
114
+ const bij = makeBijection();
115
+
116
+ const h1 = zone.exo('h1', undefined, {});
117
+ const g1 = Far('g1', {});
118
+
119
+ t.false(bij.has(g1, h1));
120
+ bij.unwrapInit(g1, h1);
121
+ t.true(bij.has(g1, h1));
122
+ bij.reset();
123
+ t.false(bij.has(g1, h1));
124
+ });
@@ -0,0 +1,132 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ asyncFlowVerbose,
8
+ } from './prepare-test-env-ava.js';
9
+
10
+ import { X, makeError, q } from '@endo/errors';
11
+ import { Far, getInterfaceOf, makeTagged, passStyleOf } from '@endo/pass-style';
12
+ import { prepareVowTools } from '@agoric/vow';
13
+ import { isVow } from '@agoric/vow/src/vow-utils.js';
14
+ import { makeHeapZone } from '@agoric/zone/heap.js';
15
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
16
+ import { makeDurableZone } from '@agoric/zone/durable.js';
17
+
18
+ import { makeConvertKit } from '../src/convert.js';
19
+ import { prepareBijection } from '../src/bijection.js';
20
+
21
+ /**
22
+ * @import {PromiseKit} from '@endo/promise-kit'
23
+ * @import {Zone} from '@agoric/base-zone'
24
+ */
25
+
26
+ /**
27
+ * @param {any} t
28
+ * @param {Zone} zone
29
+ * @param {boolean} [showOnConsole]
30
+ */
31
+ const testConvert = (t, zone, showOnConsole = false) => {
32
+ const { makeVowKit } = prepareVowTools(zone);
33
+ const makeBijection = prepareBijection(zone);
34
+ const bij = zone.makeOnce('bij', makeBijection);
35
+
36
+ const makeGuestForHostRemotable = hRem => {
37
+ const iface = getInterfaceOf(hRem);
38
+ return Far(`${iface} guest wrapper`, {});
39
+ };
40
+
41
+ const makeGuestForHostVow = _hVow => Promise.resolve('guest P');
42
+
43
+ const { guestToHost, hostToGuest } = makeConvertKit(
44
+ bij,
45
+ makeGuestForHostRemotable,
46
+ makeGuestForHostVow,
47
+ );
48
+
49
+ t.is(hostToGuest(8), 8);
50
+ const h1 = zone.exo('h1', undefined, {});
51
+ const h2 = zone.exo('h2', undefined, {});
52
+ const h3 = zone.makeOnce('h3', () => makeVowKit().vow);
53
+ t.true(isVow(h3));
54
+
55
+ const g1 = hostToGuest(h1);
56
+ const g2 = hostToGuest(h2);
57
+ const g3 = hostToGuest(h3);
58
+ t.is(passStyleOf(g1), 'remotable');
59
+ t.is(passStyleOf(g2), 'remotable');
60
+ t.is(passStyleOf(g3), 'promise');
61
+ t.not(g1, g2);
62
+ t.is(hostToGuest(h1), g1);
63
+ t.is(hostToGuest(h2), g2);
64
+ t.is(hostToGuest(h3), g3);
65
+
66
+ const h4 = makeError(X`open ${'redacted'} ${q('quoted')}`);
67
+ const g4a = hostToGuest(h4);
68
+ const g4b = hostToGuest(h4);
69
+ t.not(g4a, g4b);
70
+ t.deepEqual(g4a, g4b);
71
+
72
+ t.is(guestToHost(g1), h1);
73
+ t.is(guestToHost(g2), h2);
74
+ t.is(guestToHost(g3), h3);
75
+
76
+ t.deepEqual(guestToHost(harden([g1, g3])), [h1, h3]);
77
+ t.deepEqual(hostToGuest(harden([h1, h3])), [g1, g3]);
78
+ t.deepEqual(guestToHost(harden(URIError('msg'))), URIError('msg'));
79
+ t.deepEqual(hostToGuest(harden(URIError('msg'))), URIError('msg'));
80
+
81
+ // guestToHost and hostToGuest does its own hardening
82
+ t.deepEqual(guestToHost([g1, g3]), [h1, h3]);
83
+ t.deepEqual(hostToGuest([h1, h3]), [g1, g3]);
84
+ t.deepEqual(guestToHost(URIError('msg')), URIError('msg'));
85
+ t.deepEqual(hostToGuest(URIError('msg')), URIError('msg'));
86
+
87
+ t.deepEqual(guestToHost({ o1: g1, o2: g2 }), { o1: h1, o2: h2 });
88
+ t.deepEqual(hostToGuest({ o1: h1, o2: h2 }), { o1: g1, o2: g2 });
89
+ t.deepEqual(guestToHost(makeTagged('t', g1)), makeTagged('t', h1));
90
+ t.deepEqual(hostToGuest(makeTagged('t', h1)), makeTagged('t', g1));
91
+
92
+ const gErr1 = makeError(X`error ${'redacted message'}`, URIError);
93
+ const hErr1 = guestToHost(gErr1);
94
+ const gErr2 = hostToGuest(hErr1);
95
+
96
+ t.not(gErr1, hErr1);
97
+ t.not(hErr1, gErr2);
98
+ t.not(gErr1, gErr2);
99
+ t.is(gErr1.name, 'URIError');
100
+ t.is(hErr1.name, 'URIError');
101
+ t.is(gErr2.name, 'URIError');
102
+
103
+ if (showOnConsole) {
104
+ t.log('gErr2', gErr2);
105
+ }
106
+ };
107
+
108
+ test('test heap convert', t => {
109
+ const zone = makeHeapZone('heapRoot');
110
+ testConvert(t, zone, asyncFlowVerbose());
111
+ });
112
+
113
+ test.serial('test virtual convert', t => {
114
+ annihilate();
115
+ const zone = makeVirtualZone('virtualRoot');
116
+ testConvert(t, zone);
117
+ });
118
+
119
+ test.serial('test durable convert', t => {
120
+ annihilate();
121
+
122
+ nextLife();
123
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
124
+ testConvert(t, zone1);
125
+
126
+ // These converters keep their state only in the bijection,
127
+ // which loses all its memory between incarnations.
128
+
129
+ nextLife();
130
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
131
+ testConvert(t, zone2);
132
+ });
@@ -0,0 +1,157 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Far, getInterfaceOf, isPassable, passStyleOf } from '@endo/pass-style';
10
+ import { prepareVowTools } from '@agoric/vow';
11
+ import { isVow } from '@agoric/vow/src/vow-utils.js';
12
+ import { makeHeapZone } from '@agoric/zone/heap.js';
13
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
14
+ import { makeDurableZone } from '@agoric/zone/durable.js';
15
+
16
+ import { forwardingMethods, prepareEndowmentTools } from '../src/endowments.js';
17
+ import { makeConvertKit } from '../src/convert.js';
18
+ import { prepareBijection } from '../src/bijection.js';
19
+
20
+ const { ownKeys } = Reflect;
21
+
22
+ const testEndowmentPlay = async (t, zone, gen, isDurable) => {
23
+ const vowTools = prepareVowTools(zone);
24
+ const { when } = vowTools;
25
+ const { prepareEndowment, unwrap } = prepareEndowmentTools(zone, {
26
+ vowTools,
27
+ });
28
+
29
+ const endowment = harden({
30
+ promise: Promise.resolve(`${gen} promise`),
31
+ storable: {
32
+ emptyRecord: {},
33
+ primitive: 'foo',
34
+ null: null,
35
+ undefined,
36
+ exo: zone.exo('AnExo', undefined, {
37
+ name() {
38
+ return `${gen} exo`;
39
+ },
40
+ }),
41
+ error: URIError(`${gen} error`),
42
+ },
43
+ far: Far('AFar', {
44
+ name: () => `${gen} far`,
45
+ }),
46
+ function() {
47
+ return `${gen} function`;
48
+ },
49
+ array: [() => `${gen} f1`, () => `${gen} f2`],
50
+ state: {
51
+ // So the concrete keys differ by gen
52
+ get [`${gen}_foo`]() {
53
+ return `${gen} foo`;
54
+ },
55
+ get [`${gen}_bar`]() {
56
+ return `${gen} bar`;
57
+ },
58
+ },
59
+ });
60
+
61
+ const wrapped = prepareEndowment(zone, 't1', endowment);
62
+
63
+ t.is(passStyleOf(wrapped), 'copyRecord');
64
+ t.is(passStyleOf(wrapped.promise), 'tagged');
65
+ t.true(isVow(wrapped.promise));
66
+ t.is(endowment.storable, wrapped.storable);
67
+ t.deepEqual(ownKeys(endowment), ownKeys(wrapped));
68
+ t.deepEqual(ownKeys(endowment.storable), ownKeys(wrapped.storable));
69
+ t.is(passStyleOf(wrapped.storable), 'copyRecord');
70
+ t.is(wrapped.storable.exo.name(), `${gen} exo`);
71
+ if (isDurable) {
72
+ t.not(endowment.far, wrapped.far); // since not durably storable
73
+ } else {
74
+ t.is(endowment.far, wrapped.far); // storable in heap, virtual
75
+ }
76
+ t.is(passStyleOf(wrapped.far), 'remotable');
77
+ t.is(wrapped.far.name(), `${gen} far`);
78
+ t.is(passStyleOf(wrapped.function), 'remotable');
79
+ t.is(wrapped.function.apply([]), `${gen} function`);
80
+ t.is(passStyleOf(wrapped.array), 'copyArray');
81
+ t.is(passStyleOf(wrapped.array[0]), 'remotable');
82
+ t.is(wrapped.array[0].apply([]), `${gen} f1`);
83
+ t.is(passStyleOf(wrapped.state), 'remotable');
84
+ t.is(endowment.state[`${gen}_foo`], `${gen} foo`);
85
+ t.is(wrapped.state.get(`${gen}_foo`), `${gen} foo`);
86
+
87
+ const makeBijection = prepareBijection(zone, unwrap);
88
+ const bij = zone.makeOnce('bij', makeBijection);
89
+
90
+ const makeGuestForHostRemotable = hRem => {
91
+ const iface = getInterfaceOf(hRem);
92
+ return Far(`${iface} guest wrapper`, forwardingMethods(hRem));
93
+ };
94
+
95
+ const makeGuestForHostVow = hVow => {
96
+ return when(hVow);
97
+ };
98
+
99
+ const {
100
+ // guestToHost,
101
+ hostToGuest,
102
+ } = makeConvertKit(bij, makeGuestForHostRemotable, makeGuestForHostVow);
103
+
104
+ const unwrapped = hostToGuest(wrapped);
105
+
106
+ t.false(isPassable(unwrapped));
107
+ t.is(passStyleOf(unwrapped.promise), 'promise');
108
+ t.is(await unwrapped.promise, `${gen} promise`);
109
+ t.not(wrapped.storable, unwrapped.storable);
110
+ t.is(passStyleOf(unwrapped.storable), 'copyRecord');
111
+ t.deepEqual(ownKeys(wrapped), ownKeys(unwrapped));
112
+ t.deepEqual(ownKeys(wrapped.storable), ownKeys(unwrapped.storable));
113
+ t.not(wrapped.storable.exo, unwrapped.storable.exo);
114
+ t.is(unwrapped.storable.exo.name(), `${gen} exo`);
115
+ t.is(passStyleOf(unwrapped.far), 'remotable');
116
+ t.is(unwrapped.far.name(), `${gen} far`);
117
+ t.false(isPassable(unwrapped.function));
118
+ t.is(typeof unwrapped.function, 'function');
119
+ t.is(unwrapped.function(), `${gen} function`);
120
+ t.is(unwrapped.array[0](), `${gen} f1`);
121
+ t.false(isPassable(unwrapped.state));
122
+ t.is(typeof unwrapped.state, 'object');
123
+ t.is(unwrapped.state[`${gen}_foo`], `${gen} foo`);
124
+ };
125
+
126
+ const testEndowmentBadReplay = async (_t, _zone, _gen, _isDurable) => {
127
+ // FIXME TODO This upgrade should fail since it doesn't re-prepare
128
+ // everything. Only after that's fixed does it make sense to
129
+ // expand this to test insufficient re-preparation.
130
+ };
131
+
132
+ await test.serial('test heap endowments', async t => {
133
+ const zone = makeHeapZone('heapRoot');
134
+ return testEndowmentPlay(t, zone, 'first', false);
135
+ });
136
+
137
+ test.serial('test virtual endowments', async t => {
138
+ annihilate();
139
+ const zone = makeVirtualZone('virtualRoot');
140
+ return testEndowmentPlay(t, zone, 'first', false);
141
+ });
142
+
143
+ test.serial('test durable endowments', async t => {
144
+ annihilate();
145
+
146
+ nextLife();
147
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
148
+ await testEndowmentPlay(t, zone1, 'first', true);
149
+
150
+ nextLife();
151
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
152
+ await testEndowmentBadReplay(t, zone2, '2nd', true);
153
+
154
+ nextLife();
155
+ const zone3 = makeDurableZone(getBaggage(), 'durableRoot');
156
+ return testEndowmentPlay(t, zone3, '3rd', true);
157
+ });
@@ -0,0 +1,120 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ asyncFlowVerbose,
8
+ } from './prepare-test-env-ava.js';
9
+
10
+ import { X, makeError } from '@endo/errors';
11
+ import { Far } from '@endo/pass-style';
12
+ import { prepareVowTools } from '@agoric/vow';
13
+ import { isVow } from '@agoric/vow/src/vow-utils.js';
14
+ import { makeHeapZone } from '@agoric/zone/heap.js';
15
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
16
+ import { makeDurableZone } from '@agoric/zone/durable.js';
17
+
18
+ import { prepareBijection } from '../src/bijection.js';
19
+ import { makeEquate } from '../src/equate.js';
20
+
21
+ /**
22
+ * @import {Zone} from '@agoric/base-zone'
23
+ */
24
+
25
+ /**
26
+ * @param {any} t
27
+ * @param {Zone} zone
28
+ * @param {boolean} [showOnConsole]
29
+ */
30
+ const testEquate = (t, zone, showOnConsole = false) => {
31
+ const { makeVowKit } = prepareVowTools(zone);
32
+ const makeBijection = prepareBijection(zone);
33
+ const bij = zone.makeOnce('bij', makeBijection);
34
+
35
+ t.throws(() => zone.makeOnce('equate', () => makeEquate(bij)), {
36
+ message: 'maker return value "[Function equate]" is not storable',
37
+ });
38
+
39
+ const equate = makeEquate(bij);
40
+
41
+ equate(8, 8);
42
+ t.throws(() => equate(8, 9), {
43
+ message: 'unequal 8 vs 9',
44
+ });
45
+
46
+ const h1 = zone.exo('h1', undefined, {});
47
+ const h2 = zone.makeOnce('h2', () => makeVowKit().vow);
48
+ t.true(isVow(h2));
49
+
50
+ const g1 = Far('g1', {});
51
+ const g2 = harden(Promise.resolve('g2'));
52
+
53
+ t.throws(() => equate(g1, h1), {
54
+ message:
55
+ 'cannot yet send guest remotables to host "[Alleged: g1]" vs "[Alleged: h1]"',
56
+ });
57
+ bij.unwrapInit(g1, h1);
58
+ t.notThrows(() => equate(g1, h1));
59
+ t.throws(() => equate(g1, h2), {
60
+ message: 'internal: g->h "[Alleged: g1]" -> "[Vow]" vs "[Alleged: h1]"',
61
+ });
62
+ t.throws(() => equate(g2, h1), {
63
+ message: 'internal: unexpected h->g "[Alleged: h1]" -> "[Alleged: g1]"',
64
+ });
65
+ bij.unwrapInit(g2, h2);
66
+ equate(g2, h2);
67
+
68
+ t.throws(() => equate(g1, h2), {
69
+ message: 'internal: g->h "[Alleged: g1]" -> "[Vow]" vs "[Alleged: h1]"',
70
+ });
71
+ t.throws(() => equate(g2, h1), {
72
+ message: 'internal: g->h "[Promise]" -> "[Alleged: h1]" vs "[Vow]"',
73
+ });
74
+
75
+ equate(harden([g1, g2]), harden([h1, h2]));
76
+ t.throws(() => equate(harden([g1, g2]), harden([h1, h1])), {
77
+ message: '[1]: internal: g->h "[Promise]" -> "[Alleged: h1]" vs "[Vow]"',
78
+ });
79
+
80
+ const gErr1 = harden(makeError(X`error ${'redacted message'}`, URIError));
81
+ const hErr1 = harden(makeError(X`another message`, URIError));
82
+ const gErr2 = harden(makeError(X`another error`, TypeError));
83
+
84
+ equate(gErr1, hErr1);
85
+ t.throws(() => equate(gErr2, hErr1), {
86
+ message: 'error name: unequal "TypeError" vs "URIError"',
87
+ });
88
+
89
+ if (showOnConsole) {
90
+ // To see the annotation chain. Once we're synced with the next ses-ava,
91
+ // change this to a t.log, so we will see the annotation chain in context.
92
+ t.log('hErr1', hErr1);
93
+ }
94
+ };
95
+
96
+ test('test heap equate', t => {
97
+ const zone = makeHeapZone('heapRoot');
98
+ testEquate(t, zone, asyncFlowVerbose());
99
+ });
100
+
101
+ test.serial('test virtual equate', t => {
102
+ annihilate();
103
+ const zone = makeVirtualZone('virtualRoot');
104
+ testEquate(t, zone);
105
+ });
106
+
107
+ test.serial('test durable equate', t => {
108
+ annihilate();
109
+
110
+ nextLife();
111
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
112
+ testEquate(t, zone1);
113
+
114
+ // equate keeps its state only in the bijection,
115
+ // which loses all its memory between incarnations.
116
+
117
+ nextLife();
118
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
119
+ testEquate(t, zone2);
120
+ });
@@ -0,0 +1,120 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Fail } from '@endo/errors';
10
+ import { prepareVowTools, toPassableCap } from '@agoric/vow';
11
+ import { makeHeapZone } from '@agoric/zone/heap.js';
12
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
13
+ import { makeDurableZone } from '@agoric/zone/durable.js';
14
+
15
+ import { prepareLogStore } from '../src/log-store.js';
16
+
17
+ /**
18
+ * @import {PromiseKit} from '@endo/promise-kit'
19
+ * @import {Zone} from '@agoric/base-zone'
20
+ * @import {Vow, VowTools} from '@agoric/vow'
21
+ * @import {LogStore} from '../src/log-store.js';
22
+ * @import {Bijection} from '../src/bijection.js';
23
+ */
24
+
25
+ /**
26
+ * @param {any} t
27
+ * @param {Zone} zone
28
+ */
29
+ const testLogStorePlay = async (t, zone) => {
30
+ const { makeVowKit } = prepareVowTools(zone);
31
+ const makeLogStore = prepareLogStore(zone);
32
+
33
+ const log = zone.makeOnce('log', () => makeLogStore());
34
+ const v1 = zone.makeOnce('v1', () => makeVowKit().vow);
35
+ const v2 = zone.makeOnce('v2', () => makeVowKit().vow);
36
+
37
+ t.is(log.getIndex(), 0);
38
+ t.is(log.getLength(), 0);
39
+ t.throws(() => log.pushEntry(['bogus']), {
40
+ message:
41
+ /^In "pushEntry" method of \(LogStore\): arg 0: \["bogus"\] - Must match one of/,
42
+ });
43
+ t.false(log.isReplaying());
44
+ t.is(await log.promiseReplayDone(), undefined);
45
+
46
+ t.is(log.pushEntry(harden(['doFulfill', v1, 'x'])), 1);
47
+ t.is(log.pushEntry(harden(['doReject', v2, 'y'])), 2);
48
+ t.deepEqual(log.dump(), [
49
+ ['doFulfill', v1, 'x'],
50
+ ['doReject', v2, 'y'],
51
+ ]);
52
+ // Because t.deepEqual is too tolerant
53
+ // @ts-expect-error data dependent typing
54
+ t.is(toPassableCap(log.dump()[0][1]), toPassableCap(v1));
55
+ // @ts-expect-error data dependent typing
56
+ t.is(toPassableCap(log.dump()[1][1]), toPassableCap(v2));
57
+
58
+ t.is(log.getIndex(), 2);
59
+ t.is(log.getLength(), 2);
60
+ t.false(log.isReplaying());
61
+ t.is(await log.promiseReplayDone(), undefined);
62
+ };
63
+
64
+ /**
65
+ * @param {any} t
66
+ * @param {Zone} zone
67
+ */
68
+ const testLogStoreReplay = async (t, zone) => {
69
+ prepareVowTools(zone);
70
+ prepareLogStore(zone);
71
+
72
+ const log = /** @type {LogStore} */ (
73
+ zone.makeOnce('log', () => Fail`need log`)
74
+ );
75
+ const v1 = /** @type {Vow} */ (zone.makeOnce('v1', () => Fail`need v1`));
76
+ const v2 = /** @type {Vow} */ (zone.makeOnce('v2', () => Fail`need v2`));
77
+
78
+ t.is(log.getIndex(), 0);
79
+ t.is(log.getLength(), 2);
80
+ t.true(log.isReplaying());
81
+
82
+ t.deepEqual(log.dump(), [
83
+ ['doFulfill', v1, 'x'],
84
+ ['doReject', v2, 'y'],
85
+ ]);
86
+ // Because t.deepEqual is too tolerant
87
+ // @ts-expect-error data dependent typing
88
+ t.is(toPassableCap(log.dump()[0][1]), toPassableCap(v1));
89
+ // @ts-expect-error data dependent typing
90
+ t.is(toPassableCap(log.dump()[1][1]), toPassableCap(v2));
91
+
92
+ t.deepEqual(log.nextEntry(), ['doFulfill', v1, 'x']);
93
+ t.deepEqual(log.nextEntry(), ['doReject', v2, 'y']);
94
+ t.is(log.getIndex(), 2);
95
+ t.false(log.isReplaying());
96
+ t.is(await log.promiseReplayDone(), undefined);
97
+ };
98
+
99
+ await test.serial('test heap log-store', async t => {
100
+ const zone = makeHeapZone('heapRoot');
101
+ return testLogStorePlay(t, zone);
102
+ });
103
+
104
+ test.serial('test virtual log-store', async t => {
105
+ annihilate();
106
+ const zone = makeVirtualZone('virtualRoot');
107
+ return testLogStorePlay(t, zone);
108
+ });
109
+
110
+ test.serial('test durable log-store', async t => {
111
+ annihilate();
112
+
113
+ nextLife();
114
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
115
+ await testLogStorePlay(t, zone1);
116
+
117
+ nextLife();
118
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
119
+ return testLogStoreReplay(t, zone2);
120
+ });
@@ -0,0 +1,28 @@
1
+ import '@agoric/swingset-liveslots/tools/prepare-test-env.js';
2
+ import { wrapTest } from '@endo/ses-ava';
3
+ import rawTest from 'ava';
4
+
5
+ import { environmentOptionsListHas } from '@endo/env-options';
6
+ import { reincarnate } from '@agoric/swingset-liveslots/tools/setup-vat-data.js';
7
+
8
+ export const test = wrapTest(rawTest);
9
+
10
+ /** @type {ReturnType<typeof reincarnate>} */
11
+ let incarnation;
12
+
13
+ export const annihilate = () => {
14
+ incarnation = reincarnate({ relaxDurabilityRules: false });
15
+ };
16
+
17
+ export const getBaggage = () => {
18
+ return incarnation.fakeVomKit.cm.provideBaggage();
19
+ };
20
+
21
+ export const nextLife = () => {
22
+ incarnation = reincarnate(incarnation);
23
+ };
24
+
25
+ export const asyncFlowVerbose = () => {
26
+ // TODO figure out how we really want to control this.
27
+ return environmentOptionsListHas('DEBUG', 'async-flow-verbose');
28
+ };