| 1 | import assert from 'node:assert/strict'; |
| 2 | import { createRequire } from 'node:module'; |
| 3 | import { resolve } from 'node:path'; |
| 4 | import { webcrypto } from 'node:crypto'; |
| 5 | import { setTimeout } from 'node:timers'; |
| 6 | |
| 7 | globalThis.crypto ??= webcrypto; |
| 8 | let failure = 0; |
| 9 | let phase = 'initializing wasm'; |
| 10 | let early = true; |
| 11 | globalThis.setTimeout = (callback, delay, ...args) => { |
| 12 | if (early && failure === 2 && delay <= 1000) { |
| 13 | early = false; |
| 14 | delay = 0; |
| 15 | } |
| 16 | return setTimeout(callback, delay, ...args).unref(); |
| 17 | }; |
| 18 | const failures = [0, 0, 0]; |
| 19 | globalThis.snowboundReceiptPhase = value => { phase = value; }; |
| 20 | globalThis.snowboundReceiptFailure = value => { failure = value; }; |
| 21 | globalThis.snowboundReceiptTurn = () => new Promise(resolve => setTimeout(resolve, 10)); |
| 22 | globalThis.snowboundFlushStorage = () => { |
| 23 | failures[failure]++; |
| 24 | if (failure === 1) { |
| 25 | throw 'Injected persistent storage failure'; |
| 26 | } |
| 27 | if (failure === 2) return Promise.reject('Injected asynchronous storage failure'); |
| 28 | return Promise.resolve(); |
| 29 | }; |
| 30 | const wasm = createRequire(import.meta.url)(resolve(process.argv[2])); |
| 31 | const timeout = setTimeout(() => { throw Error(`Receipt retry stalled while ${phase}: mode ${failure}, flushes ${failures}`); }, 10000); |
| 32 | try { |
| 33 | await wasm.receipt_probe(); |
| 34 | assert.ok(failures[1] >= 2, 'The active and dropped owner each retry synchronous storage failure'); |
| 35 | assert.ok(failures[2] >= 1, 'An asynchronous storage rejection also keeps the receipt pending'); |
| 36 | assert.equal(early, false, 'A retry timer fired before its deadline'); |
| 37 | console.log(`Actual wasm receipts passed: ${failures[1]} throws, ${failures[2]} rejections, early timer, one publication, responsive reads, retained ownership`); |
| 38 | } finally { |
| 39 | clearTimeout(timeout); |
| 40 | } |