@dudousxd/nestjs-durable-testing 0.5.0 → 0.7.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/dist/index.d.ts +19 -2
- package/dist/index.js +326 -75
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5,6 +5,170 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
// src/admission-backend-conformance.ts
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
function runAdmissionBackendContract(name, makeBackend) {
|
|
11
|
+
describe(`AdmissionBackend contract: ${name}`, () => {
|
|
12
|
+
let now = 1e6;
|
|
13
|
+
const make = /* @__PURE__ */ __name((config) => {
|
|
14
|
+
now = 1e6;
|
|
15
|
+
const backend = makeBackend(() => now);
|
|
16
|
+
backend.register(config);
|
|
17
|
+
return backend;
|
|
18
|
+
}, "make");
|
|
19
|
+
it("caps concurrency: a second call blocks until the first releases", async () => {
|
|
20
|
+
const b = make({
|
|
21
|
+
name: "q",
|
|
22
|
+
concurrency: 1
|
|
23
|
+
});
|
|
24
|
+
expect((await b.tryAdmit("q", {
|
|
25
|
+
waiterId: "a"
|
|
26
|
+
})).ok).toBe(true);
|
|
27
|
+
expect((await b.tryAdmit("q", {
|
|
28
|
+
waiterId: "b"
|
|
29
|
+
})).ok).toBe(false);
|
|
30
|
+
await b.release("q", "a");
|
|
31
|
+
expect((await b.tryAdmit("q", {
|
|
32
|
+
waiterId: "b"
|
|
33
|
+
})).ok).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
it("enforces a fixed-window rate limit", async () => {
|
|
36
|
+
const b = make({
|
|
37
|
+
name: "q",
|
|
38
|
+
rateLimit: {
|
|
39
|
+
limit: 2,
|
|
40
|
+
periodMs: 1e3
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
expect((await b.tryAdmit("q", {
|
|
44
|
+
waiterId: "1"
|
|
45
|
+
})).ok).toBe(true);
|
|
46
|
+
expect((await b.tryAdmit("q", {
|
|
47
|
+
waiterId: "2"
|
|
48
|
+
})).ok).toBe(true);
|
|
49
|
+
expect((await b.tryAdmit("q", {
|
|
50
|
+
waiterId: "3"
|
|
51
|
+
})).ok).toBe(false);
|
|
52
|
+
now += 1001;
|
|
53
|
+
expect((await b.tryAdmit("q", {
|
|
54
|
+
waiterId: "4"
|
|
55
|
+
})).ok).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
it("admits the highest-priority waiter first when a slot frees", async () => {
|
|
58
|
+
const b = make({
|
|
59
|
+
name: "q",
|
|
60
|
+
concurrency: 1
|
|
61
|
+
});
|
|
62
|
+
expect((await b.tryAdmit("q", {
|
|
63
|
+
waiterId: "holder"
|
|
64
|
+
})).ok).toBe(true);
|
|
65
|
+
expect((await b.tryAdmit("q", {
|
|
66
|
+
waiterId: "low",
|
|
67
|
+
priority: 1
|
|
68
|
+
})).ok).toBe(false);
|
|
69
|
+
expect((await b.tryAdmit("q", {
|
|
70
|
+
waiterId: "high",
|
|
71
|
+
priority: 9
|
|
72
|
+
})).ok).toBe(false);
|
|
73
|
+
await b.release("q", "holder");
|
|
74
|
+
expect((await b.tryAdmit("q", {
|
|
75
|
+
waiterId: "low",
|
|
76
|
+
priority: 1
|
|
77
|
+
})).ok).toBe(false);
|
|
78
|
+
expect((await b.tryAdmit("q", {
|
|
79
|
+
waiterId: "high",
|
|
80
|
+
priority: 9
|
|
81
|
+
})).ok).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
it("orders plain-concurrency waiters by arrival (FIFO) \u2014 no priority/fairness configured", async () => {
|
|
84
|
+
const b = make({
|
|
85
|
+
name: "q",
|
|
86
|
+
concurrency: 1
|
|
87
|
+
});
|
|
88
|
+
expect((await b.tryAdmit("q", {
|
|
89
|
+
waiterId: "holder"
|
|
90
|
+
})).ok).toBe(true);
|
|
91
|
+
expect((await b.tryAdmit("q", {
|
|
92
|
+
waiterId: "first"
|
|
93
|
+
})).ok).toBe(false);
|
|
94
|
+
expect((await b.tryAdmit("q", {
|
|
95
|
+
waiterId: "second"
|
|
96
|
+
})).ok).toBe(false);
|
|
97
|
+
await b.release("q", "holder");
|
|
98
|
+
expect((await b.tryAdmit("q", {
|
|
99
|
+
waiterId: "second"
|
|
100
|
+
})).ok).toBe(false);
|
|
101
|
+
expect((await b.tryAdmit("q", {
|
|
102
|
+
waiterId: "first"
|
|
103
|
+
})).ok).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
it("admits the most-recent arrival first when order is LIFO", async () => {
|
|
106
|
+
const b = make({
|
|
107
|
+
name: "q",
|
|
108
|
+
concurrency: 1,
|
|
109
|
+
order: "lifo"
|
|
110
|
+
});
|
|
111
|
+
expect((await b.tryAdmit("q", {
|
|
112
|
+
waiterId: "holder"
|
|
113
|
+
})).ok).toBe(true);
|
|
114
|
+
expect((await b.tryAdmit("q", {
|
|
115
|
+
waiterId: "first"
|
|
116
|
+
})).ok).toBe(false);
|
|
117
|
+
expect((await b.tryAdmit("q", {
|
|
118
|
+
waiterId: "second"
|
|
119
|
+
})).ok).toBe(false);
|
|
120
|
+
await b.release("q", "holder");
|
|
121
|
+
expect((await b.tryAdmit("q", {
|
|
122
|
+
waiterId: "first"
|
|
123
|
+
})).ok).toBe(false);
|
|
124
|
+
expect((await b.tryAdmit("q", {
|
|
125
|
+
waiterId: "second"
|
|
126
|
+
})).ok).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
it("round-robins a contended slot across fairness keys", async () => {
|
|
129
|
+
const b = make({
|
|
130
|
+
name: "q",
|
|
131
|
+
concurrency: 1,
|
|
132
|
+
fairness: "key"
|
|
133
|
+
});
|
|
134
|
+
expect((await b.tryAdmit("q", {
|
|
135
|
+
waiterId: "a0",
|
|
136
|
+
key: "A"
|
|
137
|
+
})).ok).toBe(true);
|
|
138
|
+
expect((await b.tryAdmit("q", {
|
|
139
|
+
waiterId: "a1",
|
|
140
|
+
key: "A"
|
|
141
|
+
})).ok).toBe(false);
|
|
142
|
+
expect((await b.tryAdmit("q", {
|
|
143
|
+
waiterId: "b0",
|
|
144
|
+
key: "B"
|
|
145
|
+
})).ok).toBe(false);
|
|
146
|
+
await b.release("q", "a0");
|
|
147
|
+
expect((await b.tryAdmit("q", {
|
|
148
|
+
waiterId: "a1",
|
|
149
|
+
key: "A"
|
|
150
|
+
})).ok).toBe(false);
|
|
151
|
+
expect((await b.tryAdmit("q", {
|
|
152
|
+
waiterId: "b0",
|
|
153
|
+
key: "B"
|
|
154
|
+
})).ok).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
it("leaves an unregistered queue ungated", async () => {
|
|
157
|
+
const b = make({
|
|
158
|
+
name: "q",
|
|
159
|
+
concurrency: 1
|
|
160
|
+
});
|
|
161
|
+
expect((await b.tryAdmit("other", {
|
|
162
|
+
waiterId: "x"
|
|
163
|
+
})).ok).toBe(true);
|
|
164
|
+
expect((await b.tryAdmit("other", {
|
|
165
|
+
waiterId: "y"
|
|
166
|
+
})).ok).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
__name(runAdmissionBackendContract, "runAdmissionBackendContract");
|
|
171
|
+
|
|
8
172
|
// src/assertions.ts
|
|
9
173
|
async function requireRun(store, runId) {
|
|
10
174
|
const run2 = await store.getRun(runId);
|
|
@@ -200,7 +364,7 @@ __name(assertReplayable, "assertReplayable");
|
|
|
200
364
|
|
|
201
365
|
// src/state-store-conformance.ts
|
|
202
366
|
import { WorkflowEngine as WorkflowEngine3 } from "@dudousxd/nestjs-durable-core";
|
|
203
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
367
|
+
import { beforeEach, describe as describe2, expect as expect2, it as it2 } from "vitest";
|
|
204
368
|
var StateStoreUnavailableError = class extends Error {
|
|
205
369
|
static {
|
|
206
370
|
__name(this, "StateStoreUnavailableError");
|
|
@@ -245,7 +409,7 @@ var checkpoint = /* @__PURE__ */ __name((over = {}) => ({
|
|
|
245
409
|
...over
|
|
246
410
|
}), "checkpoint");
|
|
247
411
|
function runStateStoreContract(name, makeStore) {
|
|
248
|
-
|
|
412
|
+
describe2(`StateStore contract: ${name}`, () => {
|
|
249
413
|
let store;
|
|
250
414
|
let cleanup;
|
|
251
415
|
let supportsAsyncTransaction = true;
|
|
@@ -276,7 +440,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
276
440
|
};
|
|
277
441
|
});
|
|
278
442
|
const t = /* @__PURE__ */ __name((label, fn) => {
|
|
279
|
-
|
|
443
|
+
it2(label, async () => {
|
|
280
444
|
if (skipReason) return;
|
|
281
445
|
await fn();
|
|
282
446
|
});
|
|
@@ -284,13 +448,13 @@ function runStateStoreContract(name, makeStore) {
|
|
|
284
448
|
t("creates a run and reads it back with its JSON input", async () => {
|
|
285
449
|
await store.createRun(run());
|
|
286
450
|
const loaded = await store.getRun("r1");
|
|
287
|
-
|
|
288
|
-
|
|
451
|
+
expect2(loaded?.workflow).toBe("checkout");
|
|
452
|
+
expect2(loaded?.input).toEqual({
|
|
289
453
|
orderId: "o1"
|
|
290
454
|
});
|
|
291
455
|
});
|
|
292
456
|
t("returns null for a missing run", async () => {
|
|
293
|
-
|
|
457
|
+
expect2(await store.getRun("nope")).toBeNull();
|
|
294
458
|
});
|
|
295
459
|
t("updates a run (status/output) and round-trips recoveryAttempts + dead status", async () => {
|
|
296
460
|
await store.createRun(run({
|
|
@@ -304,18 +468,104 @@ function runStateStoreContract(name, makeStore) {
|
|
|
304
468
|
updatedAt: at
|
|
305
469
|
});
|
|
306
470
|
const done = await store.getRun("r1");
|
|
307
|
-
|
|
308
|
-
|
|
471
|
+
expect2(done?.status).toBe("completed");
|
|
472
|
+
expect2(done?.output).toEqual({
|
|
309
473
|
total: 42
|
|
310
474
|
});
|
|
311
|
-
|
|
475
|
+
expect2(done?.recoveryAttempts).toBe(3);
|
|
312
476
|
await store.updateRun("r1", {
|
|
313
477
|
status: "dead",
|
|
314
478
|
recoveryAttempts: 4
|
|
315
479
|
});
|
|
316
480
|
const dead = await store.getRun("r1");
|
|
317
|
-
|
|
318
|
-
|
|
481
|
+
expect2(dead?.status).toBe("dead");
|
|
482
|
+
expect2(dead?.recoveryAttempts).toBe(4);
|
|
483
|
+
});
|
|
484
|
+
t("round-trips a run dispatch priority", async () => {
|
|
485
|
+
await store.createRun(run({
|
|
486
|
+
id: "withprio",
|
|
487
|
+
priority: 7
|
|
488
|
+
}));
|
|
489
|
+
await store.createRun(run({
|
|
490
|
+
id: "noprio"
|
|
491
|
+
}));
|
|
492
|
+
expect2((await store.getRun("withprio"))?.priority).toBe(7);
|
|
493
|
+
expect2((await store.getRun("noprio"))?.priority).toBeUndefined();
|
|
494
|
+
});
|
|
495
|
+
t("deleteRun removes the run and all its rows (checkpoints, waiters, attributes)", async () => {
|
|
496
|
+
await store.createRun(run({
|
|
497
|
+
searchAttributes: {
|
|
498
|
+
tier: "pro"
|
|
499
|
+
}
|
|
500
|
+
}));
|
|
501
|
+
await store.saveCheckpoint(checkpoint());
|
|
502
|
+
await store.putSignalWaiter({
|
|
503
|
+
token: "approve-r1",
|
|
504
|
+
runId: "r1",
|
|
505
|
+
seq: 0
|
|
506
|
+
});
|
|
507
|
+
await store.deleteRun("r1");
|
|
508
|
+
expect2(await store.getRun("r1")).toBeNull();
|
|
509
|
+
expect2(await store.listCheckpoints("r1")).toEqual([]);
|
|
510
|
+
expect2(await store.listSignalWaiters("approve-")).toEqual([]);
|
|
511
|
+
expect2(await store.listRuns({
|
|
512
|
+
attributes: [
|
|
513
|
+
{
|
|
514
|
+
key: "tier",
|
|
515
|
+
op: "eq",
|
|
516
|
+
value: "pro"
|
|
517
|
+
}
|
|
518
|
+
]
|
|
519
|
+
})).toEqual([]);
|
|
520
|
+
});
|
|
521
|
+
t("deleteRun is a no-op for a missing run", async () => {
|
|
522
|
+
await expect2(store.deleteRun("nope")).resolves.toBeUndefined();
|
|
523
|
+
});
|
|
524
|
+
t("updateRun maps every patchable field \u2014 clears error and patches tags/lockedBy/input/timers", async () => {
|
|
525
|
+
await store.createRun(run({
|
|
526
|
+
status: "failed",
|
|
527
|
+
error: {
|
|
528
|
+
message: "boom"
|
|
529
|
+
},
|
|
530
|
+
tags: [
|
|
531
|
+
"old"
|
|
532
|
+
],
|
|
533
|
+
lockedBy: "owner-1"
|
|
534
|
+
}));
|
|
535
|
+
await store.updateRun("r1", {
|
|
536
|
+
status: "completed",
|
|
537
|
+
output: {
|
|
538
|
+
ok: true
|
|
539
|
+
},
|
|
540
|
+
error: void 0,
|
|
541
|
+
input: {
|
|
542
|
+
orderId: "o2"
|
|
543
|
+
},
|
|
544
|
+
tags: [
|
|
545
|
+
"x",
|
|
546
|
+
"y"
|
|
547
|
+
],
|
|
548
|
+
lockedBy: "owner-2",
|
|
549
|
+
wakeAt: 123456,
|
|
550
|
+
lockedUntil: 222222,
|
|
551
|
+
updatedAt: at
|
|
552
|
+
});
|
|
553
|
+
const r = await store.getRun("r1");
|
|
554
|
+
expect2(r?.status).toBe("completed");
|
|
555
|
+
expect2(r?.output).toEqual({
|
|
556
|
+
ok: true
|
|
557
|
+
});
|
|
558
|
+
expect2(r?.error).toBeUndefined();
|
|
559
|
+
expect2(r?.input).toEqual({
|
|
560
|
+
orderId: "o2"
|
|
561
|
+
});
|
|
562
|
+
expect2(r?.tags).toEqual([
|
|
563
|
+
"x",
|
|
564
|
+
"y"
|
|
565
|
+
]);
|
|
566
|
+
expect2(r?.lockedBy).toBe("owner-2");
|
|
567
|
+
expect2(r?.wakeAt).toBe(123456);
|
|
568
|
+
expect2(r?.lockedUntil).toBe(222222);
|
|
319
569
|
});
|
|
320
570
|
t("upserts checkpoints, reads them by (runId, seq), and lists them ordered by seq", async () => {
|
|
321
571
|
await store.createRun(run());
|
|
@@ -333,13 +583,13 @@ function runStateStoreContract(name, makeStore) {
|
|
|
333
583
|
again: true
|
|
334
584
|
}
|
|
335
585
|
}));
|
|
336
|
-
|
|
586
|
+
expect2((await store.getCheckpoint("r1", 0))?.output).toEqual({
|
|
337
587
|
ok: true,
|
|
338
588
|
again: true
|
|
339
589
|
});
|
|
340
|
-
|
|
590
|
+
expect2((await store.getCheckpoint("r1", 1))?.name).toBe("charge");
|
|
341
591
|
const list = await store.listCheckpoints("r1");
|
|
342
|
-
|
|
592
|
+
expect2(list.map((c) => c.seq)).toEqual([
|
|
343
593
|
0,
|
|
344
594
|
1
|
|
345
595
|
]);
|
|
@@ -375,14 +625,14 @@ function runStateStoreContract(name, makeStore) {
|
|
|
375
625
|
}
|
|
376
626
|
}));
|
|
377
627
|
const getLatestCheckpointByName = store.getLatestCheckpointByName;
|
|
378
|
-
|
|
628
|
+
expect2(getLatestCheckpointByName).toBeDefined();
|
|
379
629
|
if (!getLatestCheckpointByName) return;
|
|
380
630
|
const latest = await getLatestCheckpointByName.call(store, "r1", "event:progress");
|
|
381
|
-
|
|
382
|
-
|
|
631
|
+
expect2(latest?.seq).toBe(3);
|
|
632
|
+
expect2(latest?.output).toEqual({
|
|
383
633
|
pct: 90
|
|
384
634
|
});
|
|
385
|
-
|
|
635
|
+
expect2(await getLatestCheckpointByName.call(store, "r1", "event:missing")).toBeUndefined();
|
|
386
636
|
});
|
|
387
637
|
t("listCheckpointsByNamePrefix returns prefix matches ordered by seq (empty => none)", async () => {
|
|
388
638
|
await store.createRun(run());
|
|
@@ -409,18 +659,18 @@ function runStateStoreContract(name, makeStore) {
|
|
|
409
659
|
output: "child-b"
|
|
410
660
|
}));
|
|
411
661
|
const listCheckpointsByNamePrefix = store.listCheckpointsByNamePrefix;
|
|
412
|
-
|
|
662
|
+
expect2(listCheckpointsByNamePrefix).toBeDefined();
|
|
413
663
|
if (!listCheckpointsByNamePrefix) return;
|
|
414
664
|
const matches = await listCheckpointsByNamePrefix.call(store, "r1", [
|
|
415
665
|
"signal:child:",
|
|
416
666
|
"spawn:"
|
|
417
667
|
]);
|
|
418
|
-
|
|
668
|
+
expect2(matches.map((c) => c.name)).toEqual([
|
|
419
669
|
"spawn:0",
|
|
420
670
|
"signal:child:c2",
|
|
421
671
|
"spawn:1"
|
|
422
672
|
]);
|
|
423
|
-
|
|
673
|
+
expect2(await listCheckpointsByNamePrefix.call(store, "r1", [])).toEqual([]);
|
|
424
674
|
});
|
|
425
675
|
t("round-trips checkpoint events and reads back a missing checkpoint as null", async () => {
|
|
426
676
|
await store.createRun(run());
|
|
@@ -435,7 +685,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
435
685
|
}
|
|
436
686
|
]
|
|
437
687
|
}));
|
|
438
|
-
|
|
688
|
+
expect2((await store.getCheckpoint("r1", 0))?.events).toEqual([
|
|
439
689
|
{
|
|
440
690
|
at: 1,
|
|
441
691
|
level: "error",
|
|
@@ -444,7 +694,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
444
694
|
status: "failed"
|
|
445
695
|
}
|
|
446
696
|
]);
|
|
447
|
-
|
|
697
|
+
expect2(await store.getCheckpoint("r1", 99)).toBeNull();
|
|
448
698
|
});
|
|
449
699
|
t("lists incomplete runs, pending runs (FIFO), and due timers", async () => {
|
|
450
700
|
await store.createRun(run({
|
|
@@ -470,39 +720,39 @@ function runStateStoreContract(name, makeStore) {
|
|
|
470
720
|
status: "pending",
|
|
471
721
|
createdAt: /* @__PURE__ */ new Date("2026-06-11T00:00:01.000Z")
|
|
472
722
|
}));
|
|
473
|
-
|
|
723
|
+
expect2((await store.listIncompleteRuns()).map((r) => r.id)).toEqual([
|
|
474
724
|
"running1"
|
|
475
725
|
]);
|
|
476
|
-
|
|
726
|
+
expect2((await store.listPendingRuns(10)).map((r) => r.id)).toEqual([
|
|
477
727
|
"pending1",
|
|
478
728
|
"pending2"
|
|
479
729
|
]);
|
|
480
|
-
|
|
730
|
+
expect2((await store.listPendingRuns(1)).map((r) => r.id)).toEqual([
|
|
481
731
|
"pending1"
|
|
482
732
|
]);
|
|
483
|
-
|
|
733
|
+
expect2((await store.listDueTimers(1e4)).map((r) => r.id)).toEqual([
|
|
484
734
|
"suspended1"
|
|
485
735
|
]);
|
|
486
|
-
|
|
736
|
+
expect2(await store.listDueTimers(1e3)).toHaveLength(0);
|
|
487
737
|
});
|
|
488
738
|
t("tryLockRun is atomic and respects lease expiry", async () => {
|
|
489
739
|
await store.createRun(run({
|
|
490
740
|
id: "r1"
|
|
491
741
|
}));
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
742
|
+
expect2(await store.tryLockRun("r1", "A", 2e3, 1e3)).toBe(true);
|
|
743
|
+
expect2(await store.tryLockRun("r1", "B", 3e3, 1500)).toBe(false);
|
|
744
|
+
expect2(await store.tryLockRun("r1", "B", 4e3, 2500)).toBe(true);
|
|
495
745
|
await store.releaseRunLock("r1");
|
|
496
|
-
|
|
746
|
+
expect2(await store.tryLockRun("r1", "C", 9e3, 2600)).toBe(true);
|
|
497
747
|
});
|
|
498
748
|
t("renewRunLock only succeeds for the current owner", async () => {
|
|
499
749
|
await store.createRun(run({
|
|
500
750
|
id: "r1"
|
|
501
751
|
}));
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
752
|
+
expect2(await store.tryLockRun("r1", "A", 2e3, 1e3)).toBe(true);
|
|
753
|
+
expect2(await store.renewRunLock("r1", "A", 5e3)).toBe(true);
|
|
754
|
+
expect2(await store.renewRunLock("r1", "B", 9e3)).toBe(false);
|
|
755
|
+
expect2(await store.tryLockRun("r1", "B", 6e3, 4e3)).toBe(false);
|
|
506
756
|
});
|
|
507
757
|
t("filters listRuns by workflow and by status", async () => {
|
|
508
758
|
await store.createRun(run({
|
|
@@ -520,19 +770,19 @@ function runStateStoreContract(name, makeStore) {
|
|
|
520
770
|
workflow: "checkout",
|
|
521
771
|
status: "completed"
|
|
522
772
|
}));
|
|
523
|
-
|
|
773
|
+
expect2((await store.listRuns({
|
|
524
774
|
workflow: "checkout"
|
|
525
775
|
})).map((r) => r.id).sort()).toEqual([
|
|
526
776
|
"a",
|
|
527
777
|
"c"
|
|
528
778
|
]);
|
|
529
|
-
|
|
779
|
+
expect2((await store.listRuns({
|
|
530
780
|
status: "running"
|
|
531
781
|
})).map((r) => r.id).sort()).toEqual([
|
|
532
782
|
"a",
|
|
533
783
|
"b"
|
|
534
784
|
]);
|
|
535
|
-
|
|
785
|
+
expect2((await store.listRuns({
|
|
536
786
|
workflow: "checkout",
|
|
537
787
|
status: "running"
|
|
538
788
|
})).map((r) => r.id)).toEqual([
|
|
@@ -556,7 +806,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
556
806
|
id: "d",
|
|
557
807
|
status: "pending"
|
|
558
808
|
}));
|
|
559
|
-
|
|
809
|
+
expect2((await store.listRuns({
|
|
560
810
|
statuses: [
|
|
561
811
|
"running",
|
|
562
812
|
"suspended"
|
|
@@ -565,7 +815,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
565
815
|
"a",
|
|
566
816
|
"b"
|
|
567
817
|
]);
|
|
568
|
-
|
|
818
|
+
expect2((await store.listRuns({
|
|
569
819
|
status: "running",
|
|
570
820
|
statuses: [
|
|
571
821
|
"running",
|
|
@@ -574,7 +824,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
574
824
|
})).map((r) => r.id)).toEqual([
|
|
575
825
|
"a"
|
|
576
826
|
]);
|
|
577
|
-
|
|
827
|
+
expect2(await store.listRuns({
|
|
578
828
|
statuses: []
|
|
579
829
|
})).toHaveLength(0);
|
|
580
830
|
});
|
|
@@ -596,21 +846,21 @@ function runStateStoreContract(name, makeStore) {
|
|
|
596
846
|
await store.createRun(run({
|
|
597
847
|
id: "c"
|
|
598
848
|
}));
|
|
599
|
-
|
|
849
|
+
expect2((await store.getRun("a"))?.tags).toEqual([
|
|
600
850
|
"etl",
|
|
601
851
|
"critical"
|
|
602
852
|
]);
|
|
603
|
-
|
|
853
|
+
expect2((await store.listRuns({
|
|
604
854
|
tag: "etl"
|
|
605
855
|
})).map((r) => r.id)).toEqual([
|
|
606
856
|
"a"
|
|
607
857
|
]);
|
|
608
|
-
|
|
858
|
+
expect2((await store.listRuns({
|
|
609
859
|
tag: "etl-foo"
|
|
610
860
|
})).map((r) => r.id)).toEqual([
|
|
611
861
|
"b"
|
|
612
862
|
]);
|
|
613
|
-
|
|
863
|
+
expect2(await store.listRuns({
|
|
614
864
|
tag: "nope"
|
|
615
865
|
})).toHaveLength(0);
|
|
616
866
|
});
|
|
@@ -627,18 +877,18 @@ function runStateStoreContract(name, makeStore) {
|
|
|
627
877
|
id: "new",
|
|
628
878
|
createdAt: /* @__PURE__ */ new Date("2026-06-11T00:00:02.000Z")
|
|
629
879
|
}));
|
|
630
|
-
|
|
880
|
+
expect2((await store.listRuns({})).map((r) => r.id)).toEqual([
|
|
631
881
|
"new",
|
|
632
882
|
"mid",
|
|
633
883
|
"old"
|
|
634
884
|
]);
|
|
635
|
-
|
|
885
|
+
expect2((await store.listRuns({
|
|
636
886
|
limit: 2
|
|
637
887
|
})).map((r) => r.id)).toEqual([
|
|
638
888
|
"new",
|
|
639
889
|
"mid"
|
|
640
890
|
]);
|
|
641
|
-
|
|
891
|
+
expect2((await store.listRuns({
|
|
642
892
|
limit: 2,
|
|
643
893
|
offset: 1
|
|
644
894
|
})).map((r) => r.id)).toEqual([
|
|
@@ -668,11 +918,11 @@ function runStateStoreContract(name, makeStore) {
|
|
|
668
918
|
tier: "pro"
|
|
669
919
|
}
|
|
670
920
|
}));
|
|
671
|
-
|
|
921
|
+
expect2((await store.getRun("b"))?.searchAttributes).toEqual({
|
|
672
922
|
amount: 200,
|
|
673
923
|
tier: "pro"
|
|
674
924
|
});
|
|
675
|
-
|
|
925
|
+
expect2((await store.listRuns({
|
|
676
926
|
attributes: [
|
|
677
927
|
{
|
|
678
928
|
key: "amount",
|
|
@@ -684,7 +934,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
684
934
|
"b",
|
|
685
935
|
"c"
|
|
686
936
|
]);
|
|
687
|
-
|
|
937
|
+
expect2((await store.listRuns({
|
|
688
938
|
attributes: [
|
|
689
939
|
{
|
|
690
940
|
key: "tier",
|
|
@@ -700,7 +950,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
700
950
|
})).map((r) => r.id)).toEqual([
|
|
701
951
|
"b"
|
|
702
952
|
]);
|
|
703
|
-
|
|
953
|
+
expect2((await store.listRuns({
|
|
704
954
|
attributes: [
|
|
705
955
|
{
|
|
706
956
|
key: "tier",
|
|
@@ -732,7 +982,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
732
982
|
other: 1
|
|
733
983
|
}
|
|
734
984
|
}));
|
|
735
|
-
|
|
985
|
+
expect2((await store.listRuns({
|
|
736
986
|
attributes: [
|
|
737
987
|
{
|
|
738
988
|
key: "vip",
|
|
@@ -743,7 +993,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
743
993
|
})).map((r) => r.id)).toEqual([
|
|
744
994
|
"a"
|
|
745
995
|
]);
|
|
746
|
-
|
|
996
|
+
expect2((await store.listRuns({
|
|
747
997
|
attributes: [
|
|
748
998
|
{
|
|
749
999
|
key: "vip",
|
|
@@ -770,7 +1020,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
770
1020
|
"lt",
|
|
771
1021
|
"lte"
|
|
772
1022
|
]) {
|
|
773
|
-
|
|
1023
|
+
expect2(await store.listRuns({
|
|
774
1024
|
attributes: [
|
|
775
1025
|
{
|
|
776
1026
|
key: "missing",
|
|
@@ -789,7 +1039,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
789
1039
|
amount: 10
|
|
790
1040
|
}
|
|
791
1041
|
}));
|
|
792
|
-
|
|
1042
|
+
expect2((await store.listRuns({
|
|
793
1043
|
attributes: [
|
|
794
1044
|
{
|
|
795
1045
|
key: "tier",
|
|
@@ -805,7 +1055,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
805
1055
|
tier: "pro"
|
|
806
1056
|
}
|
|
807
1057
|
});
|
|
808
|
-
|
|
1058
|
+
expect2((await store.listRuns({
|
|
809
1059
|
attributes: [
|
|
810
1060
|
{
|
|
811
1061
|
key: "tier",
|
|
@@ -816,7 +1066,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
816
1066
|
})).map((r) => r.id)).toEqual([
|
|
817
1067
|
"a"
|
|
818
1068
|
]);
|
|
819
|
-
|
|
1069
|
+
expect2(await store.listRuns({
|
|
820
1070
|
attributes: [
|
|
821
1071
|
{
|
|
822
1072
|
key: "tier",
|
|
@@ -825,7 +1075,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
825
1075
|
}
|
|
826
1076
|
]
|
|
827
1077
|
})).toHaveLength(0);
|
|
828
|
-
|
|
1078
|
+
expect2(await store.listRuns({
|
|
829
1079
|
attributes: [
|
|
830
1080
|
{
|
|
831
1081
|
key: "amount",
|
|
@@ -868,7 +1118,7 @@ function runStateStoreContract(name, makeStore) {
|
|
|
868
1118
|
],
|
|
869
1119
|
limit: 10
|
|
870
1120
|
});
|
|
871
|
-
|
|
1121
|
+
expect2(res.map((r) => r.id)).toEqual([
|
|
872
1122
|
"a"
|
|
873
1123
|
]);
|
|
874
1124
|
});
|
|
@@ -888,12 +1138,12 @@ function runStateStoreContract(name, makeStore) {
|
|
|
888
1138
|
runId: "r3",
|
|
889
1139
|
seq: 5
|
|
890
1140
|
});
|
|
891
|
-
|
|
1141
|
+
expect2((await store.listSignalWaiters("approve-")).map((w) => w.token).sort()).toEqual([
|
|
892
1142
|
"approve-1",
|
|
893
1143
|
"approve-2"
|
|
894
1144
|
]);
|
|
895
|
-
|
|
896
|
-
|
|
1145
|
+
expect2((await store.takeSignalWaiter("approve-1"))?.seq).toBe(3);
|
|
1146
|
+
expect2(await store.takeSignalWaiter("approve-1")).toBeNull();
|
|
897
1147
|
});
|
|
898
1148
|
t("buffers signals and takes them FIFO per token", async () => {
|
|
899
1149
|
await store.bufferSignal("sig", {
|
|
@@ -905,18 +1155,18 @@ function runStateStoreContract(name, makeStore) {
|
|
|
905
1155
|
await store.bufferSignal("other", {
|
|
906
1156
|
n: 9
|
|
907
1157
|
});
|
|
908
|
-
|
|
1158
|
+
expect2(await store.takeBufferedSignal("sig")).toEqual({
|
|
909
1159
|
payload: {
|
|
910
1160
|
n: 1
|
|
911
1161
|
}
|
|
912
1162
|
});
|
|
913
|
-
|
|
1163
|
+
expect2(await store.takeBufferedSignal("sig")).toEqual({
|
|
914
1164
|
payload: {
|
|
915
1165
|
n: 2
|
|
916
1166
|
}
|
|
917
1167
|
});
|
|
918
|
-
|
|
919
|
-
|
|
1168
|
+
expect2(await store.takeBufferedSignal("sig")).toBeNull();
|
|
1169
|
+
expect2(await store.takeBufferedSignal("other")).toEqual({
|
|
920
1170
|
payload: {
|
|
921
1171
|
n: 9
|
|
922
1172
|
}
|
|
@@ -936,10 +1186,10 @@ function runStateStoreContract(name, makeStore) {
|
|
|
936
1186
|
}));
|
|
937
1187
|
return "ok";
|
|
938
1188
|
});
|
|
939
|
-
|
|
1189
|
+
expect2(result).toBe("ok");
|
|
940
1190
|
const cp = await store.getCheckpoint("r1", 7);
|
|
941
|
-
|
|
942
|
-
|
|
1191
|
+
expect2(cp?.name).toBe("tx-step");
|
|
1192
|
+
expect2(cp?.output).toEqual({
|
|
943
1193
|
paid: true
|
|
944
1194
|
});
|
|
945
1195
|
});
|
|
@@ -966,11 +1216,11 @@ function runStateStoreContract(name, makeStore) {
|
|
|
966
1216
|
await engine.start("wf", {
|
|
967
1217
|
x: 1
|
|
968
1218
|
}, "run1");
|
|
969
|
-
|
|
1219
|
+
expect2((await engine.waitForRun("run1")).status).toBe("failed");
|
|
970
1220
|
const resumed = await engine.resume("run1");
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1221
|
+
expect2(resumed.status).toBe("completed");
|
|
1222
|
+
expect2(resumed.output).toBe(15);
|
|
1223
|
+
expect2(aRuns).toBe(1);
|
|
974
1224
|
});
|
|
975
1225
|
});
|
|
976
1226
|
}
|
|
@@ -5515,6 +5765,7 @@ export {
|
|
|
5515
5765
|
failTimes,
|
|
5516
5766
|
preserveColumnExpectation,
|
|
5517
5767
|
recordedSteps,
|
|
5768
|
+
runAdmissionBackendContract,
|
|
5518
5769
|
runStateStoreContract
|
|
5519
5770
|
};
|
|
5520
5771
|
//# sourceMappingURL=index.js.map
|