@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.
Files changed (77) hide show
  1. package/README.md +2 -0
  2. package/package.json +27 -19
  3. package/src/boyd-gc.js +598 -0
  4. package/src/cache.js +3 -2
  5. package/src/capdata.js +1 -2
  6. package/src/collectionManager.js +219 -103
  7. package/src/facetiousness.js +1 -1
  8. package/src/index.js +4 -2
  9. package/src/liveslots.js +131 -301
  10. package/src/message.js +5 -5
  11. package/src/parseVatSlots.js +1 -1
  12. package/src/types-index.d.ts +4 -0
  13. package/src/types-index.js +2 -0
  14. package/src/types.js +8 -2
  15. package/src/vatstore-iterators.js +2 -0
  16. package/src/virtualObjectManager.js +185 -71
  17. package/src/virtualReferences.js +135 -26
  18. package/src/watchedPromises.js +67 -17
  19. package/test/{test-baggage.js → baggage.test.js} +1 -2
  20. package/test/{test-cache.js → cache.test.js} +0 -1
  21. package/test/clear-collection.test.js +586 -0
  22. package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
  23. package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
  24. package/test/{test-collections.js → collections.test.js} +158 -14
  25. package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
  26. package/test/dropped-weakset-9939.test.js +80 -0
  27. package/test/dummyMeterControl.js +1 -1
  28. package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
  29. package/test/exo-utils.js +70 -0
  30. package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
  31. package/test/gc-and-finalize.js +30 -1
  32. package/test/gc-before-finalizer.test.js +230 -0
  33. package/test/gc-helpers.js +2 -3
  34. package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
  35. package/test/handled-promises.test.js +506 -0
  36. package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
  37. package/test/liveslots-helpers.js +12 -7
  38. package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
  39. package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +62 -37
  40. package/test/{test-liveslots.js → liveslots.test.js} +14 -15
  41. package/test/mock-gc.js +1 -0
  42. package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
  43. package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
  44. package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
  45. package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
  46. package/test/strict-test-env-upgrade.test.js +94 -0
  47. package/test/util.js +2 -2
  48. package/test/vat-environment.test.js +65 -0
  49. package/test/vat-util.js +2 -2
  50. package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
  51. package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
  52. package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
  53. package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
  54. package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
  55. package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
  56. package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
  57. package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
  58. package/test/virtual-objects/set-debug-label-instances.js +1 -1
  59. package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
  60. package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
  61. package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -8
  62. package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
  63. package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
  64. package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
  65. package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
  66. package/test/waitUntilQuiescent.js +2 -1
  67. package/test/weakset-dropped-remotable.test.js +50 -0
  68. package/tools/fakeCollectionManager.js +44 -0
  69. package/tools/fakeVirtualObjectManager.js +62 -0
  70. package/tools/fakeVirtualSupport.js +389 -0
  71. package/tools/prepare-strict-test-env.js +124 -0
  72. package/tools/prepare-test-env.js +13 -0
  73. package/tools/setup-vat-data.js +96 -0
  74. package/tools/vo-test-harness.js +143 -0
  75. package/CHANGELOG.md +0 -61
  76. package/test/kmarshal.js +0 -79
  77. 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
- /* global WeakRef */
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 watch;
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
- watch = new WeakRef(pk.promise);
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.truthy(watch.deref(), 'Promise not retained');
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 watch;
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
- watch = new WeakRef(dn);
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.truthy(watch.deref(), 'Device node not retained');
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 wr;
97
+ let collected;
98
98
  function build(_vatPowers) {
99
- // eslint-disable-next-line no-unused-vars
100
- let presence1;
99
+ const holder = new Set();
101
100
  const root = Far('root', {
102
101
  one(arg) {
103
- presence1 = arg;
104
- wr = new WeakRef(arg);
102
+ holder.add(arg);
103
+ collected = watchCollected(arg);
105
104
  },
106
105
  two() {},
107
106
  three() {
108
- presence1 = undefined; // drops the import
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.truthy(wr.deref());
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.truthy(wr.deref());
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
- t.falsy(wr.deref());
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 wr;
258
+ let collected;
250
259
  function build(_vatPowers) {
251
260
  const root = Far('root', {
252
261
  one() {
253
262
  const ex1 = Far('export', {});
254
- wr = new WeakRef(ex1);
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.truthy(wr.deref());
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.truthy(wr.deref());
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.falsy(wr.deref());
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 wr;
333
+ let collected;
317
334
  function build(_vatPowers) {
318
- let ex1;
335
+ const holder = new Set();
319
336
  const root = Far('root', {
320
337
  hold() {
321
- ex1 = Far('export', {});
322
- wr = new WeakRef(ex1);
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
- // eslint-disable-next-line no-unused-vars
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.truthy(wr.deref());
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.truthy(wr.deref());
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.truthy(wr.deref());
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.truthy(wr.deref());
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.falsy(wr.deref());
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 already
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 { Fail } from '@agoric/assert';
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.deepEqual(log.shift(), 'one');
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.deepEqual(log.shift(), 'two true');
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.deepEqual(log.shift(), 'two true');
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.deepEqual(log.shift(), 'sent p1p2p3');
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.deepEqual(log.shift(), false);
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.deepEqual(log.shift(), 'disavowed pres1');
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.deepEqual(log.shift(), 'tried duplicate disavow');
977
+ t.is(log.shift(), 'tried duplicate disavow');
979
978
  loggedError(/attempt to disavow unknown/);
980
- t.deepEqual(log.shift(), 'tried to disavow Promise');
979
+ t.is(log.shift(), 'tried to disavow Promise');
981
980
  loggedError(/attempt to disavow an export/);
982
- t.deepEqual(log.shift(), 'tried to disavow export');
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.deepEqual(log.shift(), 'tried to send to disavowed');
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,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import { waitUntilQuiescent } from './waitUntilQuiescent.js';
2
3
  import { makeDummyMeterControl } from './dummyMeterControl.js';
3
4
 
@@ -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,5 +1,4 @@
1
1
  import test from 'ava';
2
- import '@endo/init/debug.js';
3
2
 
4
3
  import { setupTestLiveslots } from '../liveslots-helpers.js';
5
4
  import { buildRootObject, mapRef } from '../gc-helpers.js';
@@ -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
  */