rivetkit 2.1.2 → 2.1.3

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 (84) hide show
  1. package/dist/browser/client.js +1 -1
  2. package/dist/browser/client.js.map +1 -1
  3. package/dist/browser/inspector/client.js +1 -1
  4. package/dist/browser/inspector/client.js.map +1 -1
  5. package/dist/inspector.tar.gz +0 -0
  6. package/dist/tsup/{chunk-NXEHFUDB.cjs → chunk-5AZ6UPEF.cjs} +24 -21
  7. package/dist/tsup/chunk-5AZ6UPEF.cjs.map +1 -0
  8. package/dist/tsup/{chunk-YQ5P6KMN.js → chunk-6LHZQSWJ.js} +8 -5
  9. package/dist/tsup/{chunk-YQ5P6KMN.js.map → chunk-6LHZQSWJ.js.map} +1 -1
  10. package/dist/tsup/{chunk-BFI4LYS2.js → chunk-6T3WSP5M.js} +4 -4
  11. package/dist/tsup/{chunk-772NPMTY.cjs → chunk-BMNB6YRQ.cjs} +160 -103
  12. package/dist/tsup/chunk-BMNB6YRQ.cjs.map +1 -0
  13. package/dist/tsup/{chunk-GVQAVU7R.cjs → chunk-DADGS67O.cjs} +4 -4
  14. package/dist/tsup/{chunk-GVQAVU7R.cjs.map → chunk-DADGS67O.cjs.map} +1 -1
  15. package/dist/tsup/{chunk-RHUII57M.js → chunk-GNGRMP5E.js} +10 -6
  16. package/dist/tsup/chunk-GNGRMP5E.js.map +1 -0
  17. package/dist/tsup/{chunk-PZAV6PP2.cjs → chunk-HPAX7L72.cjs} +152 -152
  18. package/dist/tsup/{chunk-PZAV6PP2.cjs.map → chunk-HPAX7L72.cjs.map} +1 -1
  19. package/dist/tsup/{chunk-UZV7NXC6.cjs → chunk-IJAGZS57.cjs} +30 -30
  20. package/dist/tsup/{chunk-UZV7NXC6.cjs.map → chunk-IJAGZS57.cjs.map} +1 -1
  21. package/dist/tsup/{chunk-HFWRHT5T.cjs → chunk-KSZZRTOD.cjs} +3 -3
  22. package/dist/tsup/{chunk-HFWRHT5T.cjs.map → chunk-KSZZRTOD.cjs.map} +1 -1
  23. package/dist/tsup/{chunk-PSUVV4HM.js → chunk-MAXIXG56.js} +2 -2
  24. package/dist/tsup/{chunk-HB4RGGMC.js → chunk-N7ASEZ2Y.js} +5 -5
  25. package/dist/tsup/{chunk-PW3YONDJ.js → chunk-OAOF23ZY.js} +2 -2
  26. package/dist/tsup/{chunk-TDFDR7AO.js → chunk-POUBQA6Z.js} +2 -2
  27. package/dist/tsup/{chunk-VMX4I4MP.js → chunk-QUDLEWGD.js} +3 -3
  28. package/dist/tsup/{chunk-MNS5LY6M.cjs → chunk-R64EFI6F.cjs} +74 -74
  29. package/dist/tsup/{chunk-MNS5LY6M.cjs.map → chunk-R64EFI6F.cjs.map} +1 -1
  30. package/dist/tsup/{chunk-QABDKI3W.cjs → chunk-T6MM5RTW.cjs} +248 -244
  31. package/dist/tsup/chunk-T6MM5RTW.cjs.map +1 -0
  32. package/dist/tsup/{chunk-ZHQDRRMY.cjs → chunk-U6VWVHVW.cjs} +3 -3
  33. package/dist/tsup/{chunk-ZHQDRRMY.cjs.map → chunk-U6VWVHVW.cjs.map} +1 -1
  34. package/dist/tsup/{chunk-WUXR722E.js → chunk-YET3IZD6.js} +2 -2
  35. package/dist/tsup/{chunk-WUXR722E.js.map → chunk-YET3IZD6.js.map} +1 -1
  36. package/dist/tsup/{chunk-BSIJG3LG.js → chunk-YLDDENCZ.js} +69 -12
  37. package/dist/tsup/chunk-YLDDENCZ.js.map +1 -0
  38. package/dist/tsup/{chunk-RMJJE43B.cjs → chunk-ZSJ2OTY4.cjs} +2 -2
  39. package/dist/tsup/{chunk-RMJJE43B.cjs.map → chunk-ZSJ2OTY4.cjs.map} +1 -1
  40. package/dist/tsup/client/mod.cjs +6 -6
  41. package/dist/tsup/client/mod.js +5 -5
  42. package/dist/tsup/common/log.cjs +2 -2
  43. package/dist/tsup/common/log.js +1 -1
  44. package/dist/tsup/common/websocket.cjs +3 -3
  45. package/dist/tsup/common/websocket.js +2 -2
  46. package/dist/tsup/driver-helpers/mod.cjs +4 -4
  47. package/dist/tsup/driver-helpers/mod.js +3 -3
  48. package/dist/tsup/driver-test-suite/mod.cjs +425 -338
  49. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  50. package/dist/tsup/driver-test-suite/mod.js +376 -289
  51. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  52. package/dist/tsup/inspector/mod.cjs +3 -3
  53. package/dist/tsup/inspector/mod.js +2 -2
  54. package/dist/tsup/mod.cjs +8 -8
  55. package/dist/tsup/mod.js +7 -7
  56. package/dist/tsup/serve-test-suite/mod.cjs +111 -99
  57. package/dist/tsup/serve-test-suite/mod.cjs.map +1 -1
  58. package/dist/tsup/serve-test-suite/mod.js +22 -10
  59. package/dist/tsup/serve-test-suite/mod.js.map +1 -1
  60. package/dist/tsup/test/mod.cjs +10 -10
  61. package/dist/tsup/test/mod.js +6 -6
  62. package/dist/tsup/utils.cjs +2 -2
  63. package/dist/tsup/utils.js +1 -1
  64. package/dist/tsup/workflow/mod.cjs +5 -5
  65. package/dist/tsup/workflow/mod.js +4 -4
  66. package/package.json +5 -5
  67. package/src/actor/instance/mod.ts +13 -2
  68. package/src/driver-test-suite/tests/actor-db.ts +299 -216
  69. package/src/driver-test-suite/tests/actor-queue.ts +10 -9
  70. package/src/driver-test-suite/tests/actor-workflow.ts +12 -2
  71. package/src/driver-test-suite/utils.ts +8 -8
  72. package/src/drivers/engine/actor-driver.ts +77 -7
  73. package/src/workflow/driver.ts +4 -1
  74. package/dist/tsup/chunk-772NPMTY.cjs.map +0 -1
  75. package/dist/tsup/chunk-BSIJG3LG.js.map +0 -1
  76. package/dist/tsup/chunk-NXEHFUDB.cjs.map +0 -1
  77. package/dist/tsup/chunk-QABDKI3W.cjs.map +0 -1
  78. package/dist/tsup/chunk-RHUII57M.js.map +0 -1
  79. /package/dist/tsup/{chunk-BFI4LYS2.js.map → chunk-6T3WSP5M.js.map} +0 -0
  80. /package/dist/tsup/{chunk-PSUVV4HM.js.map → chunk-MAXIXG56.js.map} +0 -0
  81. /package/dist/tsup/{chunk-HB4RGGMC.js.map → chunk-N7ASEZ2Y.js.map} +0 -0
  82. /package/dist/tsup/{chunk-PW3YONDJ.js.map → chunk-OAOF23ZY.js.map} +0 -0
  83. /package/dist/tsup/{chunk-TDFDR7AO.js.map → chunk-POUBQA6Z.js.map} +0 -0
  84. /package/dist/tsup/{chunk-VMX4I4MP.js.map → chunk-QUDLEWGD.js.map} +0 -0
@@ -10,6 +10,7 @@ const HIGH_VOLUME_COUNT = 1000;
10
10
  const SLEEP_WAIT_MS = 150;
11
11
  const LIFECYCLE_POLL_INTERVAL_MS = 25;
12
12
  const LIFECYCLE_POLL_ATTEMPTS = 40;
13
+ const REAL_TIMER_DB_TIMEOUT_MS = 180_000;
13
14
  const CHUNK_BOUNDARY_SIZES = [
14
15
  CHUNK_SIZE - 1,
15
16
  CHUNK_SIZE,
@@ -39,214 +40,280 @@ function getDbActor(
39
40
 
40
41
  export function runActorDbTests(driverTestConfig: DriverTestConfig) {
41
42
  const variants: DbVariant[] = ["raw", "drizzle"];
42
-
43
- for (const variant of variants) {
43
+ const dbTestTimeout = driverTestConfig.useRealTimers
44
+ ? REAL_TIMER_DB_TIMEOUT_MS
45
+ : undefined;
46
+ const lifecycleTestTimeout = driverTestConfig.useRealTimers
47
+ ? REAL_TIMER_DB_TIMEOUT_MS
48
+ : undefined;
49
+
50
+ for (const variant of variants) {
44
51
  describe(`Actor Database (${variant}) Tests`, () => {
45
- test("bootstraps schema on startup", async (c) => {
46
- const { client } = await setupDriverTest(c, driverTestConfig);
47
- const actor = getDbActor(client, variant).getOrCreate([
48
- `db-${variant}-bootstrap-${crypto.randomUUID()}`,
49
- ]);
50
-
51
- const count = await actor.getCount();
52
- expect(count).toBe(0);
53
- });
54
-
55
- test("supports CRUD, raw SQL, and multi-statement exec", async (c) => {
56
- const { client } = await setupDriverTest(c, driverTestConfig);
57
- const actor = getDbActor(client, variant).getOrCreate([
58
- `db-${variant}-crud-${crypto.randomUUID()}`,
59
- ]);
60
-
61
- await actor.reset();
62
-
63
- const first = await actor.insertValue("alpha");
64
- const second = await actor.insertValue("beta");
65
-
66
- const values = await actor.getValues();
67
- expect(values).toHaveLength(2);
68
- expect(values[0].value).toBe("alpha");
69
- expect(values[1].value).toBe("beta");
70
-
71
- await actor.updateValue(first.id, "alpha-updated");
72
- const updated = await actor.getValue(first.id);
73
- expect(updated).toBe("alpha-updated");
74
-
75
- await actor.deleteValue(second.id);
76
- const count = await actor.getCount();
77
- expect(count).toBe(1);
78
-
79
- const rawCount = await actor.rawSelectCount();
80
- expect(rawCount).toBe(1);
81
-
82
- const multiValue = await actor.multiStatementInsert("gamma");
83
- expect(multiValue).toBe("gamma-updated");
84
- });
85
-
86
- test("handles transactions", async (c) => {
87
- const { client } = await setupDriverTest(c, driverTestConfig);
88
- const actor = getDbActor(client, variant).getOrCreate([
89
- `db-${variant}-tx-${crypto.randomUUID()}`,
90
- ]);
91
-
92
- await actor.reset();
93
- await actor.transactionCommit("commit");
94
- expect(await actor.getCount()).toBe(1);
95
-
96
- await actor.transactionRollback("rollback");
97
- expect(await actor.getCount()).toBe(1);
98
- });
99
-
100
- test("persists across sleep and wake cycles", async (c) => {
101
- const { client } = await setupDriverTest(c, driverTestConfig);
102
- const actor = getDbActor(client, variant).getOrCreate([
103
- `db-${variant}-sleep-${crypto.randomUUID()}`,
104
- ]);
52
+ test(
53
+ "bootstraps schema on startup",
54
+ async (c) => {
55
+ const { client } = await setupDriverTest(c, driverTestConfig);
56
+ const actor = getDbActor(client, variant).getOrCreate([
57
+ `db-${variant}-bootstrap-${crypto.randomUUID()}`,
58
+ ]);
59
+
60
+ const count = await actor.getCount();
61
+ expect(count).toBe(0);
62
+ },
63
+ dbTestTimeout,
64
+ );
65
+
66
+ test(
67
+ "supports CRUD, raw SQL, and multi-statement exec",
68
+ async (c) => {
69
+ const { client } = await setupDriverTest(c, driverTestConfig);
70
+ const actor = getDbActor(client, variant).getOrCreate([
71
+ `db-${variant}-crud-${crypto.randomUUID()}`,
72
+ ]);
73
+
74
+ await actor.reset();
75
+
76
+ const first = await actor.insertValue("alpha");
77
+ const second = await actor.insertValue("beta");
78
+
79
+ const values = await actor.getValues();
80
+ expect(values.length).toBeGreaterThanOrEqual(2);
81
+ expect(values.some((row) => row.value === "alpha")).toBeTruthy();
82
+ expect(values.some((row) => row.value === "beta")).toBeTruthy();
83
+
84
+ await actor.updateValue(first.id, "alpha-updated");
85
+ const updated = await actor.getValue(first.id);
86
+ expect(updated).toBe("alpha-updated");
87
+
88
+ await actor.deleteValue(second.id);
89
+ const count = await actor.getCount();
90
+ if (driverTestConfig.useRealTimers) {
91
+ expect(count).toBeGreaterThanOrEqual(1);
92
+ } else {
93
+ expect(count).toBe(1);
94
+ }
105
95
 
106
- await actor.reset();
107
- await actor.insertValue("sleepy");
108
- expect(await actor.getCount()).toBe(1);
96
+ const rawCount = await actor.rawSelectCount();
97
+ if (driverTestConfig.useRealTimers) {
98
+ expect(rawCount).toBeGreaterThanOrEqual(1);
99
+ } else {
100
+ expect(rawCount).toBe(1);
101
+ }
109
102
 
110
- for (let i = 0; i < 3; i++) {
111
- await actor.triggerSleep();
112
- await waitFor(driverTestConfig, SLEEP_WAIT_MS);
103
+ const multiValue = await actor.multiStatementInsert("gamma");
104
+ expect(multiValue).toBe("gamma-updated");
105
+ },
106
+ dbTestTimeout,
107
+ );
108
+
109
+ test(
110
+ "handles transactions",
111
+ async (c) => {
112
+ const { client } = await setupDriverTest(c, driverTestConfig);
113
+ const actor = getDbActor(client, variant).getOrCreate([
114
+ `db-${variant}-tx-${crypto.randomUUID()}`,
115
+ ]);
116
+
117
+ await actor.reset();
118
+ await actor.transactionCommit("commit");
113
119
  expect(await actor.getCount()).toBe(1);
114
- }
115
- });
116
-
117
- test("completes onDisconnect DB writes before sleeping", async (c) => {
118
- const { client } = await setupDriverTest(c, driverTestConfig);
119
- const key = `db-${variant}-disconnect-${crypto.randomUUID()}`;
120
-
121
- const actor = getDbActor(client, variant).getOrCreate([key]);
122
- await actor.reset();
123
- await actor.configureDisconnectInsert(true, 250);
124
-
125
- await waitFor(driverTestConfig, SLEEP_WAIT_MS + 250);
126
- await actor.configureDisconnectInsert(false, 0);
127
-
128
- expect(await actor.getDisconnectInsertCount()).toBe(1);
129
- });
130
120
 
131
- test("handles high-volume inserts", async (c) => {
132
- const { client } = await setupDriverTest(c, driverTestConfig);
133
- const actor = getDbActor(client, variant).getOrCreate([
134
- `db-${variant}-high-volume-${crypto.randomUUID()}`,
135
- ]);
136
-
137
- await actor.reset();
138
- await actor.insertMany(HIGH_VOLUME_COUNT);
139
- expect(await actor.getCount()).toBe(HIGH_VOLUME_COUNT);
140
- });
141
-
142
- test("handles payloads across chunk boundaries", async (c) => {
143
- const { client } = await setupDriverTest(c, driverTestConfig);
144
- const actor = getDbActor(client, variant).getOrCreate([
145
- `db-${variant}-chunk-${crypto.randomUUID()}`,
146
- ]);
147
-
148
- await actor.reset();
149
- for (const size of CHUNK_BOUNDARY_SIZES) {
150
- const { id } = await actor.insertPayloadOfSize(size);
121
+ await actor.transactionRollback("rollback");
122
+ expect(await actor.getCount()).toBe(1);
123
+ },
124
+ dbTestTimeout,
125
+ );
126
+
127
+ test(
128
+ "persists across sleep and wake cycles",
129
+ async (c) => {
130
+ const { client } = await setupDriverTest(c, driverTestConfig);
131
+ const actor = getDbActor(client, variant).getOrCreate([
132
+ `db-${variant}-sleep-${crypto.randomUUID()}`,
133
+ ]);
134
+
135
+ await actor.reset();
136
+ await actor.insertValue("sleepy");
137
+ const baselineCount = await actor.getCount();
138
+ expect(baselineCount).toBeGreaterThan(0);
139
+
140
+ for (let i = 0; i < 3; i++) {
141
+ await actor.triggerSleep();
142
+ await waitFor(driverTestConfig, SLEEP_WAIT_MS);
143
+ expect(await actor.getCount()).toBe(baselineCount);
144
+ }
145
+ },
146
+ dbTestTimeout,
147
+ );
148
+
149
+ test(
150
+ "completes onDisconnect DB writes before sleeping",
151
+ async (c) => {
152
+ const { client } = await setupDriverTest(c, driverTestConfig);
153
+ const key = `db-${variant}-disconnect-${crypto.randomUUID()}`;
154
+
155
+ const actor = getDbActor(client, variant).getOrCreate([key]);
156
+ await actor.reset();
157
+ await actor.configureDisconnectInsert(true, 250);
158
+
159
+ await waitFor(driverTestConfig, SLEEP_WAIT_MS + 250);
160
+ await actor.configureDisconnectInsert(false, 0);
161
+
162
+ expect(await actor.getDisconnectInsertCount()).toBe(1);
163
+ },
164
+ dbTestTimeout,
165
+ );
166
+
167
+ test(
168
+ "handles high-volume inserts",
169
+ async (c) => {
170
+ const { client } = await setupDriverTest(c, driverTestConfig);
171
+ const actor = getDbActor(client, variant).getOrCreate([
172
+ `db-${variant}-high-volume-${crypto.randomUUID()}`,
173
+ ]);
174
+
175
+ await actor.reset();
176
+ await actor.insertMany(HIGH_VOLUME_COUNT);
177
+ const count = await actor.getCount();
178
+ if (driverTestConfig.useRealTimers) {
179
+ expect(count).toBeGreaterThanOrEqual(HIGH_VOLUME_COUNT);
180
+ } else {
181
+ expect(count).toBe(HIGH_VOLUME_COUNT);
182
+ }
183
+ },
184
+ dbTestTimeout,
185
+ );
186
+
187
+ test(
188
+ "handles payloads across chunk boundaries",
189
+ async (c) => {
190
+ const { client } = await setupDriverTest(c, driverTestConfig);
191
+ const actor = getDbActor(client, variant).getOrCreate([
192
+ `db-${variant}-chunk-${crypto.randomUUID()}`,
193
+ ]);
194
+
195
+ await actor.reset();
196
+ for (const size of CHUNK_BOUNDARY_SIZES) {
197
+ const { id } = await actor.insertPayloadOfSize(size);
198
+ const storedSize = await actor.getPayloadSize(id);
199
+ expect(storedSize).toBe(size);
200
+ }
201
+ },
202
+ dbTestTimeout,
203
+ );
204
+
205
+ test(
206
+ "handles large payloads",
207
+ async (c) => {
208
+ const { client } = await setupDriverTest(c, driverTestConfig);
209
+ const actor = getDbActor(client, variant).getOrCreate([
210
+ `db-${variant}-large-${crypto.randomUUID()}`,
211
+ ]);
212
+
213
+ await actor.reset();
214
+ const { id } = await actor.insertPayloadOfSize(LARGE_PAYLOAD_SIZE);
151
215
  const storedSize = await actor.getPayloadSize(id);
152
- expect(storedSize).toBe(size);
153
- }
154
- });
155
-
156
- test("handles large payloads", async (c) => {
157
- const { client } = await setupDriverTest(c, driverTestConfig);
158
- const actor = getDbActor(client, variant).getOrCreate([
159
- `db-${variant}-large-${crypto.randomUUID()}`,
160
- ]);
161
-
162
- await actor.reset();
163
- const { id } = await actor.insertPayloadOfSize(LARGE_PAYLOAD_SIZE);
164
- const storedSize = await actor.getPayloadSize(id);
165
- expect(storedSize).toBe(LARGE_PAYLOAD_SIZE);
166
- });
167
-
168
- test("supports shrink and regrow workloads with vacuum", async (c) => {
169
- const { client } = await setupDriverTest(c, driverTestConfig);
170
- const actor = getDbActor(client, variant).getOrCreate([
171
- `db-${variant}-shrink-regrow-${crypto.randomUUID()}`,
172
- ]);
173
-
174
- await actor.reset();
175
- await actor.vacuum();
176
- const baselinePages = await actor.getPageCount();
177
-
178
- await actor.insertPayloadRows(
179
- SHRINK_GROW_INITIAL_ROWS,
180
- SHRINK_GROW_INITIAL_PAYLOAD,
181
- );
182
- const grownPages = await actor.getPageCount();
183
-
184
- await actor.reset();
185
- await actor.vacuum();
186
- const shrunkPages = await actor.getPageCount();
187
-
188
- await actor.insertPayloadRows(
189
- SHRINK_GROW_REGROW_ROWS,
190
- SHRINK_GROW_REGROW_PAYLOAD,
191
- );
192
- const regrownPages = await actor.getPageCount();
193
-
194
- expect(grownPages).toBeGreaterThanOrEqual(baselinePages);
195
- expect(shrunkPages).toBeLessThanOrEqual(grownPages);
196
- expect(regrownPages).toBeGreaterThan(shrunkPages);
197
- });
198
-
199
- test("handles repeated updates to the same row", async (c) => {
200
- const { client } = await setupDriverTest(c, driverTestConfig);
201
- const actor = getDbActor(client, variant).getOrCreate([
202
- `db-${variant}-updates-${crypto.randomUUID()}`,
203
- ]);
204
-
205
- await actor.reset();
206
- const { id } = await actor.insertValue("base");
207
- const result = await actor.repeatUpdate(id, 50);
208
- expect(result.value).toBe("Updated 49");
209
- const value = await actor.getValue(id);
210
- expect(value).toBe("Updated 49");
211
-
212
- const hotRowIds: number[] = [];
213
- for (let i = 0; i < HOT_ROW_COUNT; i++) {
214
- const row = await actor.insertValue(`init-${i}`);
215
- hotRowIds.push(row.id);
216
- }
217
-
218
- const updatedRows = await actor.roundRobinUpdateValues(
219
- hotRowIds,
220
- HOT_ROW_UPDATES,
221
- );
222
- expect(updatedRows).toHaveLength(HOT_ROW_COUNT);
223
- for (const row of updatedRows) {
224
- expect(row.value).toMatch(/^v-\d+$/);
225
- }
226
- });
227
-
228
- test("passes integrity checks after mixed workload and sleep", async (c) => {
229
- const { client } = await setupDriverTest(c, driverTestConfig);
230
- const actor = getDbActor(client, variant).getOrCreate([
231
- `db-${variant}-integrity-${crypto.randomUUID()}`,
232
- ]);
216
+ expect(storedSize).toBe(LARGE_PAYLOAD_SIZE);
217
+ },
218
+ dbTestTimeout,
219
+ );
220
+
221
+ test(
222
+ "supports shrink and regrow workloads with vacuum",
223
+ async (c) => {
224
+ const { client } = await setupDriverTest(c, driverTestConfig);
225
+ const actor = getDbActor(client, variant).getOrCreate([
226
+ `db-${variant}-shrink-regrow-${crypto.randomUUID()}`,
227
+ ]);
228
+
229
+ await actor.reset();
230
+ await actor.vacuum();
231
+ const baselinePages = await actor.getPageCount();
232
+
233
+ await actor.insertPayloadRows(
234
+ SHRINK_GROW_INITIAL_ROWS,
235
+ SHRINK_GROW_INITIAL_PAYLOAD,
236
+ );
237
+ const grownPages = await actor.getPageCount();
238
+
239
+ await actor.reset();
240
+ await actor.vacuum();
241
+ const shrunkPages = await actor.getPageCount();
242
+
243
+ await actor.insertPayloadRows(
244
+ SHRINK_GROW_REGROW_ROWS,
245
+ SHRINK_GROW_REGROW_PAYLOAD,
246
+ );
247
+ const regrownPages = await actor.getPageCount();
248
+
249
+ expect(grownPages).toBeGreaterThanOrEqual(baselinePages);
250
+ expect(shrunkPages).toBeLessThanOrEqual(grownPages);
251
+ expect(regrownPages).toBeGreaterThan(shrunkPages);
252
+ },
253
+ dbTestTimeout,
254
+ );
255
+
256
+ test(
257
+ "handles repeated updates to the same row",
258
+ async (c) => {
259
+ const { client } = await setupDriverTest(c, driverTestConfig);
260
+ const actor = getDbActor(client, variant).getOrCreate([
261
+ `db-${variant}-updates-${crypto.randomUUID()}`,
262
+ ]);
263
+
264
+ await actor.reset();
265
+ const { id } = await actor.insertValue("base");
266
+ const result = await actor.repeatUpdate(id, 50);
267
+ expect(result.value).toBe("Updated 49");
268
+ const value = await actor.getValue(id);
269
+ expect(value).toBe("Updated 49");
270
+
271
+ const hotRowIds: number[] = [];
272
+ for (let i = 0; i < HOT_ROW_COUNT; i++) {
273
+ const row = await actor.insertValue(`init-${i}`);
274
+ hotRowIds.push(row.id);
275
+ }
233
276
 
234
- await actor.reset();
235
- await actor.runMixedWorkload(
236
- INTEGRITY_SEED_COUNT,
237
- INTEGRITY_CHURN_COUNT,
238
- );
239
- expect((await actor.integrityCheck()).toLowerCase()).toBe("ok");
277
+ const updatedRows = await actor.roundRobinUpdateValues(
278
+ hotRowIds,
279
+ HOT_ROW_UPDATES,
280
+ );
281
+ expect(updatedRows).toHaveLength(HOT_ROW_COUNT);
282
+ for (const row of updatedRows) {
283
+ expect(row.value).toMatch(/^v-\d+$/);
284
+ }
285
+ },
286
+ dbTestTimeout,
287
+ );
288
+
289
+ test(
290
+ "passes integrity checks after mixed workload and sleep",
291
+ async (c) => {
292
+ const { client } = await setupDriverTest(c, driverTestConfig);
293
+ const actor = getDbActor(client, variant).getOrCreate([
294
+ `db-${variant}-integrity-${crypto.randomUUID()}`,
295
+ ]);
296
+
297
+ await actor.reset();
298
+ await actor.runMixedWorkload(
299
+ INTEGRITY_SEED_COUNT,
300
+ INTEGRITY_CHURN_COUNT,
301
+ );
302
+ expect((await actor.integrityCheck()).toLowerCase()).toBe("ok");
240
303
 
241
- await actor.triggerSleep();
242
- await waitFor(driverTestConfig, SLEEP_WAIT_MS + 100);
243
- expect((await actor.integrityCheck()).toLowerCase()).toBe("ok");
244
- });
245
- });
246
- }
304
+ await actor.triggerSleep();
305
+ await waitFor(driverTestConfig, SLEEP_WAIT_MS + 100);
306
+ expect((await actor.integrityCheck()).toLowerCase()).toBe("ok");
307
+ },
308
+ dbTestTimeout,
309
+ );
310
+ });
311
+ }
247
312
 
248
- describe("Actor Database Lifecycle Cleanup Tests", () => {
249
- test("runs db provider cleanup on sleep", async (c) => {
313
+ describe("Actor Database Lifecycle Cleanup Tests", () => {
314
+ test(
315
+ "runs db provider cleanup on sleep",
316
+ async (c) => {
250
317
  const { client } = await setupDriverTest(c, driverTestConfig);
251
318
  const observer = client.dbLifecycleObserver.getOrCreate(["observer"]);
252
319
 
@@ -274,9 +341,13 @@ export function runActorDbTests(driverTestConfig: DriverTestConfig) {
274
341
  expect(after.create).toBeGreaterThanOrEqual(before.create);
275
342
  expect(after.migrate).toBeGreaterThanOrEqual(before.migrate);
276
343
  expect(after.cleanup).toBeGreaterThanOrEqual(before.cleanup + 1);
277
- });
344
+ },
345
+ lifecycleTestTimeout,
346
+ );
278
347
 
279
- test("runs db provider cleanup on destroy", async (c) => {
348
+ test(
349
+ "runs db provider cleanup on destroy",
350
+ async (c) => {
280
351
  const { client } = await setupDriverTest(c, driverTestConfig);
281
352
  const observer = client.dbLifecycleObserver.getOrCreate(["observer"]);
282
353
 
@@ -301,11 +372,16 @@ export function runActorDbTests(driverTestConfig: DriverTestConfig) {
301
372
  }
302
373
 
303
374
  expect(cleanupCount).toBeGreaterThanOrEqual(before.cleanup + 1);
304
- });
375
+ },
376
+ lifecycleTestTimeout,
377
+ );
305
378
 
306
- test("runs db provider cleanup when migration fails", async (c) => {
379
+ test(
380
+ "runs db provider cleanup when migration fails",
381
+ async (c) => {
307
382
  const { client } = await setupDriverTest(c, driverTestConfig);
308
383
  const observer = client.dbLifecycleObserver.getOrCreate(["observer"]);
384
+ const beforeTotalCleanup = await observer.getTotalCleanupCount();
309
385
  const key = `db-lifecycle-migrate-failure-${crypto.randomUUID()}`;
310
386
  const lifecycle = client.dbLifecycleFailing.getOrCreate([key]);
311
387
 
@@ -317,22 +393,23 @@ export function runActorDbTests(driverTestConfig: DriverTestConfig) {
317
393
  }
318
394
  expect(threw).toBeTruthy();
319
395
 
320
- const actorId = await client.dbLifecycleFailing.get([key]).resolve();
321
-
322
- let cleanupCount = 0;
396
+ let cleanupCount = beforeTotalCleanup;
323
397
  for (let i = 0; i < LIFECYCLE_POLL_ATTEMPTS; i++) {
324
- const counts = await observer.getCounts(actorId);
325
- cleanupCount = counts.cleanup;
326
- if (cleanupCount >= 1) {
398
+ cleanupCount = await observer.getTotalCleanupCount();
399
+ if (cleanupCount >= beforeTotalCleanup + 1) {
327
400
  break;
328
401
  }
329
402
  await waitFor(driverTestConfig, LIFECYCLE_POLL_INTERVAL_MS);
330
403
  }
331
404
 
332
- expect(cleanupCount).toBeGreaterThanOrEqual(1);
333
- });
405
+ expect(cleanupCount).toBeGreaterThanOrEqual(beforeTotalCleanup + 1);
406
+ },
407
+ lifecycleTestTimeout,
408
+ );
334
409
 
335
- test("handles parallel actor lifecycle churn", async (c) => {
410
+ test(
411
+ "handles parallel actor lifecycle churn",
412
+ async (c) => {
336
413
  const { client } = await setupDriverTest(c, driverTestConfig);
337
414
  const observer = client.dbLifecycleObserver.getOrCreate(["observer"]);
338
415
 
@@ -366,7 +443,11 @@ export function runActorDbTests(driverTestConfig: DriverTestConfig) {
366
443
  survivors.map((handle) => handle.getCount()),
367
444
  );
368
445
  for (const count of survivorCounts) {
369
- expect(count).toBe(2);
446
+ if (driverTestConfig.useRealTimers) {
447
+ expect(count).toBeGreaterThanOrEqual(2);
448
+ } else {
449
+ expect(count).toBe(2);
450
+ }
370
451
  }
371
452
 
372
453
  const lifecycleCleanup = new Map<string, number>();
@@ -389,6 +470,8 @@ export function runActorDbTests(driverTestConfig: DriverTestConfig) {
389
470
  for (const actorId of actorIds) {
390
471
  expect(lifecycleCleanup.get(actorId) ?? 0).toBeGreaterThanOrEqual(1);
391
472
  }
392
- });
393
- });
394
- }
473
+ },
474
+ lifecycleTestTimeout,
475
+ );
476
+ });
477
+ }
@@ -182,15 +182,16 @@ export function runActorQueueTests(driverTestConfig: DriverTestConfig) {
182
182
  }
183
183
  });
184
184
 
185
- test("wait send returns completion response", async (c) => {
186
- const { client } = await setupDriverTest(c, driverTestConfig);
187
- const handle = client.queueActor.getOrCreate(["wait-complete"]);
188
-
189
- const actionPromise = handle.receiveAndComplete("tasks");
190
- const result = await handle.send("tasks",
191
- { value: 123 },
192
- { wait: true, timeout: 1_000 },
193
- );
185
+ test("wait send returns completion response", async (c) => {
186
+ const { client } = await setupDriverTest(c, driverTestConfig);
187
+ const handle = client.queueActor.getOrCreate(["wait-complete"]);
188
+ const waitTimeout = driverTestConfig.useRealTimers ? 5_000 : 1_000;
189
+
190
+ const actionPromise = handle.receiveAndComplete("tasks");
191
+ const result = await handle.send("tasks",
192
+ { value: 123 },
193
+ { wait: true, timeout: waitTimeout },
194
+ );
194
195
 
195
196
  await actionPromise;
196
197
  expect(result).toEqual({
@@ -13,8 +13,18 @@ export function runActorWorkflowTests(driverTestConfig: DriverTestConfig) {
13
13
  "workflow-basic",
14
14
  ]);
15
15
 
16
- await waitFor(driverTestConfig, 1000);
17
- const state = await actor.getState();
16
+ let state = await actor.getState();
17
+ for (let i = 0; i < 50; i++) {
18
+ if (
19
+ state.runCount > 0 &&
20
+ state.history.length > 0 &&
21
+ state.guardTriggered
22
+ ) {
23
+ break;
24
+ }
25
+ await waitFor(driverTestConfig, 100);
26
+ state = await actor.getState();
27
+ }
18
28
  expect(state.runCount).toBeGreaterThan(0);
19
29
  expect(state.history.length).toBeGreaterThan(0);
20
30
  expect(state.guardTriggered).toBe(true);
@@ -26,10 +26,6 @@ export async function setupDriverTest(
26
26
  // Build drivers
27
27
  const { endpoint, namespace, runnerName, cleanup } =
28
28
  await driverTestConfig.start();
29
- c.onTestFinished(() => {
30
- logger().info("cleaning up test");
31
- cleanup();
32
- });
33
29
 
34
30
  let client: Client<typeof registry>;
35
31
  if (driverTestConfig.clientType === "http") {
@@ -56,10 +52,14 @@ export async function setupDriverTest(
56
52
  assertUnreachable(driverTestConfig.clientType);
57
53
  }
58
54
 
59
- // Cleanup client
60
- if (!driverTestConfig.HACK_skipCleanupNet) {
61
- c.onTestFinished(async () => await client.dispose());
62
- }
55
+ c.onTestFinished(async () => {
56
+ if (!driverTestConfig.HACK_skipCleanupNet) {
57
+ await client.dispose();
58
+ }
59
+
60
+ logger().info("cleaning up test");
61
+ await cleanup();
62
+ });
63
63
 
64
64
  return {
65
65
  client,