@agoric/internal 0.3.3-dev-5ff5e7a.0.5ff5e7a → 0.3.3-dev-04baeed.0.04baeed
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/package.json +4 -4
- package/src/testing-utils.d.ts +4 -1
- package/src/testing-utils.d.ts.map +1 -1
- package/src/testing-utils.js +51 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/internal",
|
|
3
|
-
"version": "0.3.3-dev-
|
|
3
|
+
"version": "0.3.3-dev-04baeed.0.04baeed",
|
|
4
4
|
"description": "Externally unsupported utilities internal to agoric-sdk",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"lint:types": "yarn run -T tsgo --tsBuildInfoFile tsconfig.tsgo.tsbuildinfo"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@agoric/base-zone": "0.1.1-dev-
|
|
27
|
+
"@agoric/base-zone": "0.1.1-dev-04baeed.0.04baeed",
|
|
28
28
|
"@endo/cache-map": "^1.1.0",
|
|
29
29
|
"@endo/common": "^1.4.0",
|
|
30
30
|
"@endo/compartment-mapper": "^2.3.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"jessie.js": "^0.3.4"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@agoric/cosmic-proto": "0.4.1-dev-
|
|
45
|
+
"@agoric/cosmic-proto": "0.4.1-dev-04baeed.0.04baeed",
|
|
46
46
|
"@endo/exo": "^1.7.0",
|
|
47
47
|
"@endo/init": "^1.1.13",
|
|
48
48
|
"@endo/ses-ava": "^1.4.2",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"typeCoverage": {
|
|
71
71
|
"atLeast": 92.84
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "04baeedd0adc9b2480dd9d272e8daffebc408662"
|
|
74
74
|
}
|
package/src/testing-utils.d.ts
CHANGED
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export const eventLoopIteration: () => Promise<void>;
|
|
16
16
|
export function inspectMapStore(store: MapStore): object;
|
|
17
|
-
export function testInterruptedSteps<Input = any, Context = unknown>(t: AvaT<Context>, allSteps: readonly TestStep<Input>[], doInterrupt?: (t: AvaT<Context>) => ERef<void
|
|
17
|
+
export function testInterruptedSteps<Input = any, Context = unknown>(t: AvaT<Context>, allSteps: readonly TestStep<Input>[], doInterrupt?: (t: AvaT<Context>) => ERef<void>, { setup, postcondition }?: {
|
|
18
|
+
setup?: ((t: AvaT<Context>) => Partial<Input> | PromiseLike<Partial<Input>>) | undefined;
|
|
19
|
+
postcondition?: ((t: AvaT<Context>, accum: Partial<Input>, label: string) => ERef<void>) | undefined;
|
|
20
|
+
}): Promise<void>;
|
|
18
21
|
export type TestStep<Input = any> = readonly [stepName: string, fn: (input: Partial<Input>, label: string) => Partial<Input> | PromiseLike<Partial<Input>>];
|
|
19
22
|
import type { MapStore } from '@agoric/store';
|
|
20
23
|
import type { ExecutionContext as AvaT } from 'ava';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing-utils.d.ts","sourceRoot":"","sources":["testing-utils.js"],"names":[],"mappings":"AACA;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,iCAFU,MAAM,OAAO,CAAC,IAAI,CAAC,CAGmB;AAgBzC,uCAHI,QAAQ,GACN,MAAM,CAsBlB;
|
|
1
|
+
{"version":3,"file":"testing-utils.d.ts","sourceRoot":"","sources":["testing-utils.js"],"names":[],"mappings":"AACA;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,iCAFU,MAAM,OAAO,CAAC,IAAI,CAAC,CAGmB;AAgBzC,uCAHI,QAAQ,GACN,MAAM,CAsBlB;AAwCM,qCAjBO,KAAK,QACL,OAAO,eACV,KAAK,OAAO,CAAC,YACb,SAAS,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAC1B,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,6BAExC;IAAqF,KAAK,QAA9E,KAAK,OAAO,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAMe,aAAa,QAA1F,KAAK,OAAO,CAAC,SAAS,OAAO,CAAC,KAAK,CAAC,SAAS,MAAM,KAAK,KAAK,IAAI,CAAC;CAIhF,iBAoFA;qBAvHa,KAAK,UACN,SAAS,CACjB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAC3F;8BA3DuB,eAAe;8CACC,KAAK;0BACzB,qBAAqB"}
|
package/src/testing-utils.js
CHANGED
|
@@ -66,13 +66,37 @@ harden(inspectMapStore);
|
|
|
66
66
|
* For each step, run to just before that point and pause for continuation after
|
|
67
67
|
* interrupt.
|
|
68
68
|
*
|
|
69
|
+
* `allSteps` should contain only steps that are meaningful interruption
|
|
70
|
+
* boundaries — i.e. that leave durable in-flight state whose recovery across an
|
|
71
|
+
* interrupt is worth asserting. Each step in `allSteps` runs `allSteps.length +
|
|
72
|
+
* 2` times, so the total work is quadratic in the number of steps; keep the
|
|
73
|
+
* list to the genuinely mutating steps. Use `options.setup` for non-mutating
|
|
74
|
+
* fixtures and `options.postcondition` for non-mutating outcome assertions so
|
|
75
|
+
* they don't inflate the boundary count.
|
|
76
|
+
*
|
|
69
77
|
* @template [Input=any]
|
|
70
78
|
* @template [Context=unknown]
|
|
71
79
|
* @param {AvaT<Context>} t
|
|
72
80
|
* @param {readonly TestStep<Input>[]} allSteps
|
|
73
81
|
* @param {(t: AvaT<Context>) => ERef<void>} [doInterrupt]
|
|
82
|
+
* @param {object} [options]
|
|
83
|
+
* @param {(t: AvaT<Context>) => Partial<Input> | PromiseLike<Partial<Input>>} [options.setup]
|
|
84
|
+
* Produce the initial accumulator at the start of each run. Runs are never
|
|
85
|
+
* interrupted around setup, so use it for fixtures (e.g. funding a wallet)
|
|
86
|
+
* that are not themselves part of the interruption-resilience contract. It is
|
|
87
|
+
* invoked once per run, so it may create per-run state (e.g. a single-use
|
|
88
|
+
* actor) safely.
|
|
89
|
+
* @param {(t: AvaT<Context>, accum: Partial<Input>, label: string) => ERef<void>} [options.postcondition]
|
|
90
|
+
* Assert the outcome after each run that completes all of its steps (the
|
|
91
|
+
* pre-interrupt run, the post-interrupt run, and each resumed run). Use for
|
|
92
|
+
* non-mutating outcome checks that need not be interruption boundaries.
|
|
74
93
|
*/
|
|
75
|
-
export const testInterruptedSteps = async (
|
|
94
|
+
export const testInterruptedSteps = async (
|
|
95
|
+
t,
|
|
96
|
+
allSteps,
|
|
97
|
+
doInterrupt,
|
|
98
|
+
{ setup, postcondition } = {},
|
|
99
|
+
) => {
|
|
76
100
|
/**
|
|
77
101
|
* @typedef {{
|
|
78
102
|
* label: string;
|
|
@@ -80,16 +104,20 @@ export const testInterruptedSteps = async (t, allSteps, doInterrupt) => {
|
|
|
80
104
|
* }} RunState
|
|
81
105
|
*/
|
|
82
106
|
|
|
107
|
+
/** @returns {Promise<Partial<Input>>} */
|
|
108
|
+
const freshAccum = async () => (setup ? setup(t) : {});
|
|
109
|
+
|
|
83
110
|
/**
|
|
84
111
|
* @param {string} label
|
|
85
112
|
* @param {readonly TestStep<Input>[]} steps
|
|
86
|
-
* @param {RunState} [runState]
|
|
113
|
+
* @param {RunState} [runState] when omitted, a fresh run is started, seeding
|
|
114
|
+
* the accumulator from `setup`.
|
|
87
115
|
* @returns {Promise<RunState>}
|
|
88
116
|
*/
|
|
89
|
-
const runSteps = async (label, steps, runState
|
|
117
|
+
const runSteps = async (label, steps, runState) => {
|
|
90
118
|
await null;
|
|
91
|
-
let accum = runState.accum;
|
|
92
|
-
const runLabel = runState.label;
|
|
119
|
+
let accum = runState ? runState.accum : await freshAccum();
|
|
120
|
+
const runLabel = runState ? runState.label : label;
|
|
93
121
|
for (const [stepName, fn] of steps) {
|
|
94
122
|
await t.notThrowsAsync(async () => {
|
|
95
123
|
accum = await fn(accum, runLabel);
|
|
@@ -98,8 +126,20 @@ export const testInterruptedSteps = async (t, allSteps, doInterrupt) => {
|
|
|
98
126
|
return { label: runLabel, accum };
|
|
99
127
|
};
|
|
100
128
|
|
|
129
|
+
/**
|
|
130
|
+
* @param {RunState} runState
|
|
131
|
+
* @returns {Promise<RunState>}
|
|
132
|
+
*/
|
|
133
|
+
const complete = async runState => {
|
|
134
|
+
await null;
|
|
135
|
+
if (postcondition) {
|
|
136
|
+
await postcondition(t, runState.accum, runState.label);
|
|
137
|
+
}
|
|
138
|
+
return runState;
|
|
139
|
+
};
|
|
140
|
+
|
|
101
141
|
// Sanity check
|
|
102
|
-
await runSteps('pre-interrupt', allSteps);
|
|
142
|
+
await complete(await runSteps('pre-interrupt', allSteps));
|
|
103
143
|
if (!doInterrupt) {
|
|
104
144
|
return;
|
|
105
145
|
}
|
|
@@ -116,7 +156,7 @@ export const testInterruptedSteps = async (t, allSteps, doInterrupt) => {
|
|
|
116
156
|
const runState = await runSteps(
|
|
117
157
|
`pre-${beforeStepName}`,
|
|
118
158
|
allSteps.slice(0, i),
|
|
119
|
-
{ label: `pause-before-${beforeStepName}`, accum:
|
|
159
|
+
{ label: `pause-before-${beforeStepName}`, accum: await freshAccum() },
|
|
120
160
|
);
|
|
121
161
|
pausedRuns.push({ runState, remainingSteps: allSteps.slice(i) });
|
|
122
162
|
}
|
|
@@ -125,12 +165,14 @@ export const testInterruptedSteps = async (t, allSteps, doInterrupt) => {
|
|
|
125
165
|
await doInterrupt(t);
|
|
126
166
|
|
|
127
167
|
// Verify a complete run post-interrupt.
|
|
128
|
-
await runSteps('post-interrupt', allSteps);
|
|
168
|
+
await complete(await runSteps('post-interrupt', allSteps));
|
|
129
169
|
|
|
130
170
|
// Verify completion of each paused step.
|
|
131
171
|
for (const { runState, remainingSteps } of pausedRuns) {
|
|
132
172
|
const [beforeStepName] = remainingSteps[0];
|
|
133
|
-
await
|
|
173
|
+
await complete(
|
|
174
|
+
await runSteps(`resumed-${beforeStepName}`, remainingSteps, runState),
|
|
175
|
+
);
|
|
134
176
|
}
|
|
135
177
|
};
|
|
136
178
|
harden(testInterruptedSteps);
|