@agoric/swingset-liveslots 0.10.3-other-dev-8f8782b.0 → 0.10.3-other-dev-3eb1a1d.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.
- package/README.md +2 -0
- package/package.json +27 -19
- package/src/boyd-gc.js +598 -0
- package/src/cache.js +3 -2
- package/src/capdata.js +1 -2
- package/src/collectionManager.js +219 -103
- package/src/facetiousness.js +1 -1
- package/src/index.js +4 -2
- package/src/liveslots.js +131 -301
- package/src/message.js +5 -5
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.js +8 -2
- package/src/vatstore-iterators.js +2 -0
- package/src/virtualObjectManager.js +185 -71
- package/src/virtualReferences.js +135 -26
- package/src/watchedPromises.js +67 -17
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/clear-collection.test.js +586 -0
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +158 -14
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/dropped-weakset-9939.test.js +80 -0
- package/test/dummyMeterControl.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +2 -3
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +506 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
- package/test/liveslots-helpers.js +12 -7
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +62 -37
- package/test/{test-liveslots.js → liveslots.test.js} +14 -15
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/util.js +2 -2
- package/test/vat-environment.test.js +65 -0
- package/test/vat-util.js +2 -2
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -8
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.js +96 -0
- package/tools/vo-test-harness.js +143 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
3
|
|
|
4
4
|
import { Far } from '@endo/marshal';
|
|
5
|
+
import { kslot, kser } from '@agoric/kmarshal';
|
|
5
6
|
import { makeLiveSlots } from '../src/liveslots.js';
|
|
6
7
|
import { parseVatSlot } from '../src/parseVatSlots.js';
|
|
7
|
-
import { kslot, kser } from './kmarshal.js';
|
|
8
8
|
import { buildSyscall } from './liveslots-helpers.js';
|
|
9
9
|
import {
|
|
10
10
|
makeMessage,
|
|
11
11
|
makeStartVat,
|
|
12
12
|
makeBringOutYourDead,
|
|
13
13
|
makeResolve,
|
|
14
|
+
makeRetireImports,
|
|
14
15
|
} from './util.js';
|
|
15
16
|
import { makeMockGC } from './mock-gc.js';
|
|
16
17
|
|
|
@@ -465,3 +466,101 @@ for (const firstType of ['object', 'collection']) {
|
|
|
465
466
|
}
|
|
466
467
|
|
|
467
468
|
// test('double-free', doublefreetest, { firstType: 'object', lastType: 'collection', order: 'first->last' });
|
|
469
|
+
|
|
470
|
+
test('retirement', async t => {
|
|
471
|
+
const { syscall, fakestore, log } = buildSyscall();
|
|
472
|
+
const gcTools = makeMockGC();
|
|
473
|
+
|
|
474
|
+
// A is a weak collection, with one entry, whose key is B (a
|
|
475
|
+
// Presence). We drop the RAM pillar for B and do a BOYD, which
|
|
476
|
+
// should provoke a syscall.dropImports. Then, when we delete A (by
|
|
477
|
+
// dropping the RAM pillar), the next BOYD should see a
|
|
478
|
+
// `syscall.retireImports`.
|
|
479
|
+
|
|
480
|
+
let weakmapA;
|
|
481
|
+
let presenceB;
|
|
482
|
+
|
|
483
|
+
function buildRootObject(vatPowers) {
|
|
484
|
+
const { VatData } = vatPowers;
|
|
485
|
+
const { makeScalarBigWeakMapStore } = VatData;
|
|
486
|
+
|
|
487
|
+
weakmapA = makeScalarBigWeakMapStore();
|
|
488
|
+
|
|
489
|
+
return Far('root', {
|
|
490
|
+
add: p => {
|
|
491
|
+
presenceB = p;
|
|
492
|
+
weakmapA.init(presenceB, 'value');
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const makeNS = () => ({ buildRootObject });
|
|
498
|
+
const ls = makeLiveSlots(syscall, 'vatA', {}, {}, gcTools, undefined, makeNS);
|
|
499
|
+
const { dispatch, testHooks } = ls;
|
|
500
|
+
const { valToSlot } = testHooks;
|
|
501
|
+
|
|
502
|
+
await dispatch(makeStartVat(kser()));
|
|
503
|
+
log.length = 0;
|
|
504
|
+
const weakmapAvref = valToSlot.get(weakmapA);
|
|
505
|
+
const { subid } = parseVatSlot(weakmapAvref);
|
|
506
|
+
const collectionID = String(subid);
|
|
507
|
+
|
|
508
|
+
const rootA = 'o+0';
|
|
509
|
+
const presenceBvref = 'o-1';
|
|
510
|
+
await dispatch(makeMessage(rootA, 'add', [kslot(presenceBvref)]));
|
|
511
|
+
log.length = 0;
|
|
512
|
+
|
|
513
|
+
// the fact that weakmapA can recognize presenceA is recorded in a
|
|
514
|
+
// vatstore key
|
|
515
|
+
const recognizerKey = `vom.ir.${presenceBvref}|${collectionID}`;
|
|
516
|
+
t.is(fakestore.get(recognizerKey), '1');
|
|
517
|
+
|
|
518
|
+
// tell mockGC that userspace has dropped presenceB
|
|
519
|
+
gcTools.kill(presenceB);
|
|
520
|
+
gcTools.flushAllFRs();
|
|
521
|
+
|
|
522
|
+
await dispatch(makeBringOutYourDead());
|
|
523
|
+
const priorKey = `vom.ir.${presenceBvref}|`;
|
|
524
|
+
|
|
525
|
+
t.deepEqual(log.splice(0), [
|
|
526
|
+
// when a Presence is dropped, scanForDeadObjects can't drop the
|
|
527
|
+
// underlying vref import until it knows that virtual data isn't
|
|
528
|
+
// holding a reference, so we expect a refcount check
|
|
529
|
+
{ type: 'vatstoreGet', key: `vom.rc.${presenceBvref}`, result: undefined },
|
|
530
|
+
|
|
531
|
+
// the vref is now in importsToDrop, but since this commonly means
|
|
532
|
+
// it can be retired too, scanForDeadObjects goes ahead and checks
|
|
533
|
+
// for recognizers
|
|
534
|
+
{ type: 'vatstoreGetNextKey', priorKey, result: recognizerKey },
|
|
535
|
+
|
|
536
|
+
// it found a recognizer, so the vref cannot be retired
|
|
537
|
+
// yet. scanForDeadObjects finishes the BOYD by emitting the
|
|
538
|
+
// dropImports, but should keep watching for an opportunity to
|
|
539
|
+
// retire it too
|
|
540
|
+
{ type: 'dropImports', slots: [presenceBvref] },
|
|
541
|
+
]);
|
|
542
|
+
|
|
543
|
+
// now tell mockGC that we're dropping the weakmap too
|
|
544
|
+
gcTools.kill(weakmapA);
|
|
545
|
+
gcTools.flushAllFRs();
|
|
546
|
+
|
|
547
|
+
// this will provoke the deletion of the collection and all its
|
|
548
|
+
// data. It should *also* trigger a syscall.retireImports of the
|
|
549
|
+
// no-longer-recognizable key
|
|
550
|
+
await dispatch(makeBringOutYourDead());
|
|
551
|
+
const retires = log.filter(e => e.type === 'retireImports');
|
|
552
|
+
|
|
553
|
+
t.deepEqual(retires, [{ type: 'retireImports', slots: [presenceBvref] }]);
|
|
554
|
+
|
|
555
|
+
// If the bug is present, the vat won't send `syscall.retireImports`
|
|
556
|
+
// to the kernel. In a full system, that means the kernel can
|
|
557
|
+
// eventually send a `dispatch.retireImports` into the vat, if/when
|
|
558
|
+
// the object's hosting vat decides to drop it. Make sure that won't
|
|
559
|
+
// cause a crash.
|
|
560
|
+
|
|
561
|
+
if (!retires.length) {
|
|
562
|
+
console.log(`testing kernel's dispatch.retireImports`);
|
|
563
|
+
await dispatch(makeRetireImports(presenceBvref));
|
|
564
|
+
console.log(`dispatch.retireImports did not crash`);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/* global process */
|
|
2
3
|
import test from 'ava';
|
|
3
|
-
import '@endo/init/debug.js';
|
|
4
4
|
|
|
5
5
|
import { Far } from '@endo/marshal';
|
|
6
6
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
7
|
+
import { kslot, kser } from '@agoric/kmarshal';
|
|
7
8
|
import engineGC from './engine-gc.js';
|
|
8
|
-
import { makeGcAndFinalize } from './gc-and-finalize.js';
|
|
9
|
-
import { kslot, kser } from './kmarshal.js';
|
|
9
|
+
import { watchCollected, makeGcAndFinalize } from './gc-and-finalize.js';
|
|
10
10
|
import { buildSyscall, makeDispatch } from './liveslots-helpers.js';
|
|
11
11
|
import {
|
|
12
12
|
makeMessage,
|
|
@@ -28,13 +28,13 @@ const gcAndFinalize = makeGcAndFinalize(engineGC);
|
|
|
28
28
|
|
|
29
29
|
test.serial('liveslots retains pending exported promise', async t => {
|
|
30
30
|
const { log, syscall } = buildSyscall();
|
|
31
|
-
let
|
|
31
|
+
let collected;
|
|
32
32
|
const success = [];
|
|
33
33
|
function build(_vatPowers) {
|
|
34
34
|
const root = Far('root', {
|
|
35
35
|
make() {
|
|
36
36
|
const pk = makePromiseKit();
|
|
37
|
-
|
|
37
|
+
collected = watchCollected(pk.promise);
|
|
38
38
|
// we export the Promise, but do not retain resolve/reject
|
|
39
39
|
return [pk.promise];
|
|
40
40
|
},
|
|
@@ -55,7 +55,7 @@ test.serial('liveslots retains pending exported promise', async t => {
|
|
|
55
55
|
const resultP = 'p-1';
|
|
56
56
|
await dispatch(makeMessage(rootA, 'make', [], resultP));
|
|
57
57
|
await gcAndFinalize();
|
|
58
|
-
t.
|
|
58
|
+
t.false(collected.result, 'Promise retained');
|
|
59
59
|
t.is(log[0].type, 'resolve');
|
|
60
60
|
const res0 = log[0].resolutions[0];
|
|
61
61
|
t.is(res0[0], resultP);
|
|
@@ -66,13 +66,13 @@ test.serial('liveslots retains pending exported promise', async t => {
|
|
|
66
66
|
|
|
67
67
|
test.serial('liveslots retains device nodes', async t => {
|
|
68
68
|
const { syscall } = buildSyscall();
|
|
69
|
-
let
|
|
69
|
+
let collected;
|
|
70
70
|
const recognize = new WeakSet(); // real WeakSet
|
|
71
71
|
const success = [];
|
|
72
72
|
function build(_vatPowers) {
|
|
73
73
|
const root = Far('root', {
|
|
74
74
|
first(dn) {
|
|
75
|
-
|
|
75
|
+
collected = watchCollected(dn);
|
|
76
76
|
recognize.add(dn);
|
|
77
77
|
},
|
|
78
78
|
second(dn) {
|
|
@@ -87,25 +87,24 @@ test.serial('liveslots retains device nodes', async t => {
|
|
|
87
87
|
const device = 'd-1';
|
|
88
88
|
await dispatch(makeMessage(rootA, 'first', [kslot(device)]));
|
|
89
89
|
await gcAndFinalize();
|
|
90
|
-
t.
|
|
90
|
+
t.false(collected.result, 'Device node retained');
|
|
91
91
|
await dispatch(makeMessage(rootA, 'second', [kslot(device)]));
|
|
92
92
|
t.deepEqual(success, [true]);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
test.serial('GC syscall.dropImports', async t => {
|
|
96
96
|
const { log, syscall } = buildSyscall();
|
|
97
|
-
let
|
|
97
|
+
let collected;
|
|
98
98
|
function build(_vatPowers) {
|
|
99
|
-
|
|
100
|
-
let presence1;
|
|
99
|
+
const holder = new Set();
|
|
101
100
|
const root = Far('root', {
|
|
102
101
|
one(arg) {
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
holder.add(arg);
|
|
103
|
+
collected = watchCollected(arg);
|
|
105
104
|
},
|
|
106
105
|
two() {},
|
|
107
106
|
three() {
|
|
108
|
-
|
|
107
|
+
holder.clear(); // drops the import
|
|
109
108
|
},
|
|
110
109
|
});
|
|
111
110
|
return root;
|
|
@@ -121,19 +120,29 @@ test.serial('GC syscall.dropImports', async t => {
|
|
|
121
120
|
// rp1 = root~.one(arg)
|
|
122
121
|
await dispatch(makeMessage(rootA, 'one', [kslot(arg)]));
|
|
123
122
|
await dispatch(makeBringOutYourDead());
|
|
124
|
-
t.
|
|
123
|
+
t.false(collected.result);
|
|
125
124
|
|
|
126
125
|
// an intermediate message will trigger GC, but the presence is still held
|
|
127
126
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
128
127
|
await dispatch(makeBringOutYourDead());
|
|
129
|
-
t.
|
|
128
|
+
t.false(collected.result);
|
|
130
129
|
|
|
131
130
|
// now tell the vat to drop the 'arg' presence we gave them earlier
|
|
132
131
|
await dispatch(makeMessage(rootA, 'three', []));
|
|
133
132
|
await dispatch(makeBringOutYourDead());
|
|
134
133
|
|
|
134
|
+
const isV8 =
|
|
135
|
+
typeof process !== 'undefined' && 'v8' in (process.versions || {});
|
|
136
|
+
|
|
135
137
|
// the presence itself should be gone
|
|
136
|
-
|
|
138
|
+
if (!collected.result) {
|
|
139
|
+
if (isV8) {
|
|
140
|
+
// Flake in v8/node: https://github.com/Agoric/agoric-sdk/issues/8883
|
|
141
|
+
t.log('skipping flake in v8');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
t.fail('import not collected');
|
|
145
|
+
}
|
|
137
146
|
|
|
138
147
|
// first it will check that there are no VO's holding onto it
|
|
139
148
|
const l2 = log.shift();
|
|
@@ -246,12 +255,12 @@ test.serial('GC dispatch.retireExports', async t => {
|
|
|
246
255
|
|
|
247
256
|
test.serial('GC dispatch.dropExports', async t => {
|
|
248
257
|
const { log, syscall } = buildSyscall();
|
|
249
|
-
let
|
|
258
|
+
let collected;
|
|
250
259
|
function build(_vatPowers) {
|
|
251
260
|
const root = Far('root', {
|
|
252
261
|
one() {
|
|
253
262
|
const ex1 = Far('export', {});
|
|
254
|
-
|
|
263
|
+
collected = watchCollected(ex1);
|
|
255
264
|
return ex1;
|
|
256
265
|
// ex1 goes out of scope, dropping last userspace strongref
|
|
257
266
|
},
|
|
@@ -285,19 +294,27 @@ test.serial('GC dispatch.dropExports', async t => {
|
|
|
285
294
|
|
|
286
295
|
// the exported Remotable should be held in place by exportedRemotables
|
|
287
296
|
// until we tell the vat we don't need it any more
|
|
288
|
-
t.
|
|
297
|
+
t.false(collected.result);
|
|
289
298
|
|
|
290
299
|
// an intermediate message will trigger GC, but the presence is still held
|
|
291
300
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
292
301
|
await dispatch(makeBringOutYourDead());
|
|
293
|
-
t.
|
|
302
|
+
t.false(collected.result);
|
|
294
303
|
|
|
295
304
|
// now tell the vat we don't need a strong reference to that export.
|
|
296
305
|
await dispatch(makeDropExports(ex1));
|
|
297
306
|
await dispatch(makeBringOutYourDead());
|
|
298
307
|
|
|
299
308
|
// that should allow ex1 to be collected
|
|
300
|
-
t.
|
|
309
|
+
t.true(collected.result);
|
|
310
|
+
|
|
311
|
+
// upon collection, the vat should scan for local recognizers (weak
|
|
312
|
+
// collection keys) in case any need to be dropped, and find none
|
|
313
|
+
t.deepEqual(log.shift(), {
|
|
314
|
+
type: 'vatstoreGetNextKey',
|
|
315
|
+
priorKey: `vom.ir.${ex1}|`,
|
|
316
|
+
result: 'vom.rc.o+d6/1',
|
|
317
|
+
});
|
|
301
318
|
|
|
302
319
|
// and once it's collected, the vat should emit `syscall.retireExport`
|
|
303
320
|
// because nobody else will be able to recognize it again
|
|
@@ -313,19 +330,19 @@ test.serial(
|
|
|
313
330
|
'GC dispatch.retireExports inhibits syscall.retireExports',
|
|
314
331
|
async t => {
|
|
315
332
|
const { log, syscall } = buildSyscall();
|
|
316
|
-
let
|
|
333
|
+
let collected;
|
|
317
334
|
function build(_vatPowers) {
|
|
318
|
-
|
|
335
|
+
const holder = new Set();
|
|
319
336
|
const root = Far('root', {
|
|
320
337
|
hold() {
|
|
321
|
-
ex1 = Far('export', {});
|
|
322
|
-
|
|
338
|
+
const ex1 = Far('export', {});
|
|
339
|
+
holder.add(ex1);
|
|
340
|
+
collected = watchCollected(ex1);
|
|
323
341
|
return ex1;
|
|
324
342
|
},
|
|
325
343
|
two() {},
|
|
326
344
|
drop() {
|
|
327
|
-
//
|
|
328
|
-
ex1 = undefined; // drop the last userspace strongref
|
|
345
|
+
holder.clear(); // drop the last userspace strongref
|
|
329
346
|
},
|
|
330
347
|
});
|
|
331
348
|
return root;
|
|
@@ -356,19 +373,19 @@ test.serial(
|
|
|
356
373
|
|
|
357
374
|
// the exported Remotable should be held in place by exportedRemotables
|
|
358
375
|
// until we tell the vat we don't need it any more
|
|
359
|
-
t.
|
|
376
|
+
t.false(collected.result);
|
|
360
377
|
|
|
361
378
|
// an intermediate message will trigger GC, but the presence is still held
|
|
362
379
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
363
380
|
await dispatch(makeBringOutYourDead());
|
|
364
|
-
t.
|
|
381
|
+
t.false(collected.result);
|
|
365
382
|
|
|
366
383
|
// now tell the vat we don't need a strong reference to that export.
|
|
367
384
|
await dispatch(makeDropExports(ex1));
|
|
368
385
|
await dispatch(makeBringOutYourDead());
|
|
369
386
|
|
|
370
387
|
// that removes the liveslots strongref, but the vat's remains in place
|
|
371
|
-
t.
|
|
388
|
+
t.false(collected.result);
|
|
372
389
|
|
|
373
390
|
// now the kernel tells the vat we can't even recognize the export
|
|
374
391
|
await dispatch(makeRetireExports(ex1));
|
|
@@ -376,17 +393,25 @@ test.serial(
|
|
|
376
393
|
|
|
377
394
|
// that ought to delete the table entry, but doesn't affect the vat
|
|
378
395
|
// strongref
|
|
379
|
-
t.
|
|
396
|
+
t.false(collected.result);
|
|
380
397
|
|
|
381
398
|
// now tell the vat to drop its strongref
|
|
382
399
|
await dispatch(makeMessage(rootA, 'drop', []));
|
|
383
400
|
await dispatch(makeBringOutYourDead());
|
|
384
401
|
|
|
385
402
|
// which should let the export be collected
|
|
386
|
-
t.
|
|
403
|
+
t.true(collected.result);
|
|
404
|
+
|
|
405
|
+
// the vat should scan for local recognizers (weak collection
|
|
406
|
+
// keys) in case any need to be dropped, and find none
|
|
407
|
+
t.deepEqual(log.shift(), {
|
|
408
|
+
type: 'vatstoreGetNextKey',
|
|
409
|
+
priorKey: 'vom.ir.o+10|',
|
|
410
|
+
result: 'vom.rc.o+d6/1',
|
|
411
|
+
});
|
|
387
412
|
|
|
388
|
-
// the vat should *not* emit `syscall.retireExport`, because it
|
|
389
|
-
// received a dispatch.retireExport
|
|
413
|
+
// the vat should *not* emit `syscall.retireExport`, because it
|
|
414
|
+
// already received a dispatch.retireExport
|
|
390
415
|
t.deepEqual(log, []);
|
|
391
416
|
},
|
|
392
417
|
);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
3
|
|
|
4
|
+
import { Fail } from '@endo/errors';
|
|
4
5
|
import { E } from '@endo/eventual-send';
|
|
5
6
|
import { Far } from '@endo/marshal';
|
|
6
7
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
7
|
-
import {
|
|
8
|
+
import { kslot, kser, kunser } from '@agoric/kmarshal';
|
|
8
9
|
import { M } from '@agoric/store';
|
|
9
10
|
import { makeLiveSlots, makeMarshaller } from '../src/liveslots.js';
|
|
10
|
-
import { kslot, kser, kunser } from './kmarshal.js';
|
|
11
11
|
import { buildSyscall, makeDispatch } from './liveslots-helpers.js';
|
|
12
12
|
import { makeMessage, makeStartVat, makeResolve, makeReject } from './util.js';
|
|
13
13
|
import { makeMockGC } from './mock-gc.js';
|
|
@@ -45,14 +45,14 @@ test('calls', async t => {
|
|
|
45
45
|
|
|
46
46
|
// root!one() // sendOnly
|
|
47
47
|
await dispatch(makeMessage(rootA, 'one', ['args']));
|
|
48
|
-
t.
|
|
48
|
+
t.is(log.shift(), 'one');
|
|
49
49
|
|
|
50
50
|
// pr = makePromise()
|
|
51
51
|
// root!two(pr.promise)
|
|
52
52
|
// pr.resolve('result')
|
|
53
53
|
await dispatch(makeMessage(rootA, 'two', [kslot('p-1')]));
|
|
54
54
|
t.deepEqual(log.shift(), { type: 'subscribe', target: 'p-1' });
|
|
55
|
-
t.
|
|
55
|
+
t.is(log.shift(), 'two true');
|
|
56
56
|
|
|
57
57
|
await dispatch(makeResolve('p-1', kser('result')));
|
|
58
58
|
t.deepEqual(log.shift(), ['res', 'result']);
|
|
@@ -63,7 +63,7 @@ test('calls', async t => {
|
|
|
63
63
|
|
|
64
64
|
await dispatch(makeMessage(rootA, 'two', [kslot('p-2')]));
|
|
65
65
|
t.deepEqual(log.shift(), { type: 'subscribe', target: 'p-2' });
|
|
66
|
-
t.
|
|
66
|
+
t.is(log.shift(), 'two true');
|
|
67
67
|
|
|
68
68
|
await dispatch(makeReject('p-2', kser('rejection')));
|
|
69
69
|
t.deepEqual(log.shift(), ['rej', 'rejection']);
|
|
@@ -99,7 +99,7 @@ test('liveslots pipelines to syscall.send', async t => {
|
|
|
99
99
|
// for x!pipe1(), a second pipelined to the result promise of it, and a
|
|
100
100
|
// third pipelined to the result of the second.
|
|
101
101
|
|
|
102
|
-
t.
|
|
102
|
+
t.is(log.shift(), 'sent p1p2p3');
|
|
103
103
|
t.deepEqual(log.shift(), {
|
|
104
104
|
type: 'send',
|
|
105
105
|
targetSlot: x,
|
|
@@ -656,8 +656,7 @@ test('capdata size limit on syscalls', async t => {
|
|
|
656
656
|
};
|
|
657
657
|
|
|
658
658
|
const send = op => dispatch(makeMessage(rootA, op, [kslot(target)], rp));
|
|
659
|
-
const expectFail = () =>
|
|
660
|
-
t.deepEqual(log.shift(), 'fail: syscall capdata too large');
|
|
659
|
+
const expectFail = () => t.is(log.shift(), 'fail: syscall capdata too large');
|
|
661
660
|
const expectVoidReturn = () =>
|
|
662
661
|
t.deepEqual(log.shift(), {
|
|
663
662
|
type: 'resolve',
|
|
@@ -906,7 +905,7 @@ test('disable disavow', async t => {
|
|
|
906
905
|
|
|
907
906
|
// root~.one() // sendOnly
|
|
908
907
|
await dispatch(makeMessage(rootA, 'one', []));
|
|
909
|
-
t.
|
|
908
|
+
t.is(log.shift(), false);
|
|
910
909
|
t.deepEqual(log, []);
|
|
911
910
|
});
|
|
912
911
|
|
|
@@ -967,7 +966,7 @@ test('disavow', async t => {
|
|
|
967
966
|
// root~.one(import1) // sendOnly
|
|
968
967
|
await dispatch(makeMessage(rootA, 'one', [kslot(import1)]));
|
|
969
968
|
t.deepEqual(log.shift(), { type: 'dropImports', slots: [import1] });
|
|
970
|
-
t.
|
|
969
|
+
t.is(log.shift(), 'disavowed pres1');
|
|
971
970
|
|
|
972
971
|
function loggedError(re) {
|
|
973
972
|
const l = log.shift();
|
|
@@ -975,11 +974,11 @@ test('disavow', async t => {
|
|
|
975
974
|
t.truthy(re.test(l.message));
|
|
976
975
|
}
|
|
977
976
|
loggedError(/attempt to disavow unknown/);
|
|
978
|
-
t.
|
|
977
|
+
t.is(log.shift(), 'tried duplicate disavow');
|
|
979
978
|
loggedError(/attempt to disavow unknown/);
|
|
980
|
-
t.
|
|
979
|
+
t.is(log.shift(), 'tried to disavow Promise');
|
|
981
980
|
loggedError(/attempt to disavow an export/);
|
|
982
|
-
t.
|
|
981
|
+
t.is(log.shift(), 'tried to disavow export');
|
|
983
982
|
const msg = log.shift();
|
|
984
983
|
t.like(msg, {
|
|
985
984
|
type: 'exit',
|
|
@@ -987,7 +986,7 @@ test('disavow', async t => {
|
|
|
987
986
|
});
|
|
988
987
|
expectError(t, msg.info, /this Presence has been disavowed/);
|
|
989
988
|
t.deepEqual(log.shift(), Error('this Presence has been disavowed'));
|
|
990
|
-
t.
|
|
989
|
+
t.is(log.shift(), 'tried to send to disavowed');
|
|
991
990
|
t.deepEqual(log, []);
|
|
992
991
|
});
|
|
993
992
|
|
package/test/mock-gc.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
3
|
|
|
4
|
+
import { kslot, kunser } from '@agoric/kmarshal';
|
|
4
5
|
import {
|
|
5
6
|
setupTestLiveslots,
|
|
6
7
|
findSyscallsByType,
|
|
7
8
|
} from '../liveslots-helpers.js';
|
|
8
9
|
import { buildRootObject, mainHeldIdx, mapRef } from '../gc-helpers.js';
|
|
9
|
-
import { kslot, kunser } from '../kmarshal.js';
|
|
10
10
|
import { parseVatSlot } from '../../src/parseVatSlots.js';
|
|
11
11
|
|
|
12
12
|
// These tests follow the model described in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
2
|
|
|
3
|
+
import { kslot } from '@agoric/kmarshal';
|
|
4
4
|
import {
|
|
5
5
|
findSyscallsByType,
|
|
6
6
|
setupTestLiveslots,
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
refValString,
|
|
13
13
|
assertCollectionDeleted,
|
|
14
14
|
} from '../gc-helpers.js';
|
|
15
|
-
import { kslot } from '../kmarshal.js';
|
|
16
15
|
import { vstr } from '../util.js';
|
|
17
16
|
|
|
18
17
|
// These tests follow the model described in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
2
|
|
|
3
|
+
import { kslot } from '@agoric/kmarshal';
|
|
4
4
|
import { setupTestLiveslots } from '../liveslots-helpers.js';
|
|
5
5
|
import {
|
|
6
6
|
buildRootObject,
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
assertCollectionDeleted,
|
|
9
9
|
deduceCollectionID,
|
|
10
10
|
} from '../gc-helpers.js';
|
|
11
|
-
import { kslot } from '../kmarshal.js';
|
|
12
11
|
import { vstr } from '../util.js';
|
|
13
12
|
|
|
14
13
|
// These tests follow the model described in test-virtualObjectGC.js
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* global globalThis */
|
|
2
|
+
// eslint-disable-next-line import/order
|
|
3
|
+
import { annihilate, startLife } from '../tools/prepare-strict-test-env.js';
|
|
4
|
+
|
|
5
|
+
import test from 'ava';
|
|
6
|
+
|
|
7
|
+
import { makeUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
8
|
+
import { makeExoUtils } from './exo-utils.js';
|
|
9
|
+
|
|
10
|
+
test.serial('kind redefinition enforced', async t => {
|
|
11
|
+
annihilate();
|
|
12
|
+
|
|
13
|
+
const { prepareExoClass } = makeExoUtils(globalThis.VatData);
|
|
14
|
+
|
|
15
|
+
await startLife(async baggage => {
|
|
16
|
+
const makeTestExo = prepareExoClass(
|
|
17
|
+
baggage,
|
|
18
|
+
'TestExo',
|
|
19
|
+
undefined,
|
|
20
|
+
() => ({}),
|
|
21
|
+
{
|
|
22
|
+
foo() {
|
|
23
|
+
return 'bar';
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
baggage.init('testExo', makeTestExo());
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await t.throwsAsync(
|
|
32
|
+
async () =>
|
|
33
|
+
startLife(async () => {
|
|
34
|
+
// Not redefining the kind here
|
|
35
|
+
}),
|
|
36
|
+
{ message: 'defineDurableKind not called for tags: [TestExo]' },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
await startLife(async baggage => {
|
|
40
|
+
prepareExoClass(baggage, 'TestExo', undefined, () => ({}), {
|
|
41
|
+
foo() {
|
|
42
|
+
return 'baz';
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
t.is(baggage.get('testExo').foo(), 'baz');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test.serial('decided promise rejected', async t => {
|
|
51
|
+
annihilate();
|
|
52
|
+
|
|
53
|
+
const { prepareExo } = makeExoUtils(globalThis.VatData);
|
|
54
|
+
const { watchPromise } = globalThis.VatData;
|
|
55
|
+
|
|
56
|
+
t.plan(1);
|
|
57
|
+
|
|
58
|
+
await startLife(async baggage => {
|
|
59
|
+
const watcher = prepareExo(
|
|
60
|
+
baggage,
|
|
61
|
+
'DurablePromiseTestWatcher',
|
|
62
|
+
undefined,
|
|
63
|
+
{
|
|
64
|
+
onFulfilled(value) {
|
|
65
|
+
t.fail(
|
|
66
|
+
`First incarnation watcher onFulfilled triggered with value ${value}`,
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
onRejected(reason) {
|
|
70
|
+
t.fail(
|
|
71
|
+
`First incarnation watcher onRejected triggered with reason ${reason}`,
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const never = harden(new Promise(() => {}));
|
|
78
|
+
|
|
79
|
+
watchPromise(never, watcher);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await startLife(async baggage => {
|
|
83
|
+
prepareExo(baggage, 'DurablePromiseTestWatcher', undefined, {
|
|
84
|
+
onFulfilled(value) {
|
|
85
|
+
t.fail(
|
|
86
|
+
`Second incarnation watcher onFulfilled triggered with value ${value}`,
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
onRejected(reason) {
|
|
90
|
+
t.deepEqual(reason, makeUpgradeDisconnection('vat upgraded', 1));
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
package/test/util.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { kser } from '@agoric/kmarshal';
|
|
1
2
|
import { vstr } from './vat-util.js';
|
|
2
|
-
import { kser } from './kmarshal.js';
|
|
3
3
|
|
|
4
4
|
export { vstr };
|
|
5
5
|
|
|
@@ -48,7 +48,7 @@ export function buildDispatch(onDispatchCallback) {
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* @param {unknown} target
|
|
51
|
-
* @param {string} method
|
|
51
|
+
* @param {string | symbol} method
|
|
52
52
|
* @param {any[]} args
|
|
53
53
|
* @param {unknown} result
|
|
54
54
|
*/
|