@powerhousedao/reactor 4.1.0-staging.1 → 5.0.0-staging.2
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/bench/end-to-end-flow.bench.js +64 -36
- package/dist/bench/end-to-end-flow.bench.js.map +1 -1
- package/dist/bench/event-bus.bench.js.map +1 -1
- package/dist/bench/queue-only.bench.js +8 -2
- package/dist/bench/queue-only.bench.js.map +1 -1
- package/dist/bench/reactor-throughput.bench.js +43 -16
- package/dist/bench/reactor-throughput.bench.js.map +1 -1
- package/dist/src/events/event-bus.d.ts +2 -2
- package/dist/src/events/event-bus.d.ts.map +1 -1
- package/dist/src/events/event-bus.js +1 -1
- package/dist/src/events/event-bus.js.map +1 -1
- package/dist/src/events/interfaces.d.ts +1 -1
- package/dist/src/events/interfaces.d.ts.map +1 -1
- package/dist/src/events/types.d.ts +1 -1
- package/dist/src/events/types.d.ts.map +1 -1
- package/dist/src/events/types.js.map +1 -1
- package/dist/src/executor/interfaces.d.ts +31 -54
- package/dist/src/executor/interfaces.d.ts.map +1 -1
- package/dist/src/executor/simple-job-executor-manager.d.ts +27 -0
- package/dist/src/executor/simple-job-executor-manager.d.ts.map +1 -0
- package/dist/src/executor/simple-job-executor-manager.js +128 -0
- package/dist/src/executor/simple-job-executor-manager.js.map +1 -0
- package/dist/src/executor/simple-job-executor.d.ts +19 -0
- package/dist/src/executor/simple-job-executor.d.ts.map +1 -0
- package/dist/src/executor/simple-job-executor.js +69 -0
- package/dist/src/executor/simple-job-executor.js.map +1 -0
- package/dist/src/executor/types.d.ts +23 -8
- package/dist/src/executor/types.d.ts.map +1 -1
- package/dist/src/executor/types.js.map +1 -1
- package/dist/src/index.d.ts +9 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/reactor.d.ts +121 -0
- package/dist/src/interfaces/reactor.d.ts.map +1 -0
- package/dist/src/interfaces/reactor.js +2 -0
- package/dist/src/interfaces/reactor.js.map +1 -0
- package/dist/src/queue/interfaces.d.ts +26 -1
- package/dist/src/queue/interfaces.d.ts.map +1 -1
- package/dist/src/queue/queue.d.ts +33 -3
- package/dist/src/queue/queue.d.ts.map +1 -1
- package/dist/src/queue/queue.js +164 -17
- package/dist/src/queue/queue.js.map +1 -1
- package/dist/src/queue/types.d.ts +5 -1
- package/dist/src/queue/types.d.ts.map +1 -1
- package/dist/src/queue/types.js.map +1 -1
- package/dist/src/reactor.d.ts +109 -0
- package/dist/src/reactor.d.ts.map +1 -0
- package/dist/src/reactor.js +602 -0
- package/dist/src/reactor.js.map +1 -0
- package/dist/src/registry/implementation.d.ts +62 -0
- package/dist/src/registry/implementation.d.ts.map +1 -0
- package/dist/src/registry/implementation.js +96 -0
- package/dist/src/registry/implementation.js.map +1 -0
- package/dist/src/registry/index.d.ts +3 -0
- package/dist/src/registry/index.d.ts.map +1 -0
- package/dist/src/registry/index.js +2 -0
- package/dist/src/registry/index.js.map +1 -0
- package/dist/src/registry/interfaces.d.ts +39 -0
- package/dist/src/registry/interfaces.d.ts.map +1 -0
- package/dist/src/registry/interfaces.js +2 -0
- package/dist/src/registry/interfaces.js.map +1 -0
- package/dist/src/shared/factories.d.ts +16 -0
- package/dist/src/shared/factories.d.ts.map +1 -0
- package/dist/src/shared/factories.js +33 -0
- package/dist/src/shared/factories.js.map +1 -0
- package/dist/src/shared/types.d.ts +83 -19
- package/dist/src/shared/types.d.ts.map +1 -1
- package/dist/src/shared/types.js +30 -1
- package/dist/src/shared/types.js.map +1 -1
- package/dist/src/shared/utils.d.ts +3 -0
- package/dist/src/shared/utils.d.ts.map +1 -0
- package/dist/src/shared/utils.js +8 -0
- package/dist/src/shared/utils.js.map +1 -0
- package/dist/src/utils.d.ts +11 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +29 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/test/executor-integration.test.d.ts +2 -0
- package/dist/test/executor-integration.test.d.ts.map +1 -0
- package/dist/test/executor-integration.test.js +290 -0
- package/dist/test/executor-integration.test.js.map +1 -0
- package/dist/test/factories.d.ts +131 -0
- package/dist/test/factories.d.ts.map +1 -0
- package/dist/test/factories.js +347 -0
- package/dist/test/factories.js.map +1 -0
- package/dist/test/queue.test.js +219 -28
- package/dist/test/queue.test.js.map +1 -1
- package/dist/test/reactor-queue.test.d.ts +2 -0
- package/dist/test/reactor-queue.test.d.ts.map +1 -0
- package/dist/test/reactor-queue.test.js +328 -0
- package/dist/test/reactor-queue.test.js.map +1 -0
- package/dist/test/reactor-read.test.d.ts +2 -0
- package/dist/test/reactor-read.test.d.ts.map +1 -0
- package/dist/test/reactor-read.test.js +355 -0
- package/dist/test/reactor-read.test.js.map +1 -0
- package/dist/test/registry.test.d.ts +2 -0
- package/dist/test/registry.test.d.ts.map +1 -0
- package/dist/test/registry.test.js +182 -0
- package/dist/test/registry.test.js.map +1 -0
- package/dist/test/simple-job-executor-manager.test.d.ts +2 -0
- package/dist/test/simple-job-executor-manager.test.d.ts.map +1 -0
- package/dist/test/simple-job-executor-manager.test.js +132 -0
- package/dist/test/simple-job-executor-manager.test.js.map +1 -0
- package/dist/test/simple-job-executor.test.d.ts +2 -0
- package/dist/test/simple-job-executor.test.d.ts.map +1 -0
- package/dist/test/simple-job-executor.test.js +139 -0
- package/dist/test/simple-job-executor.test.js.map +1 -0
- package/dist/test/utils.test.d.ts +2 -0
- package/dist/test/utils.test.d.ts.map +1 -0
- package/dist/test/utils.test.js +66 -0
- package/dist/test/utils.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +11 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +6 -1
- package/dist/src/executor/job-executor.d.ts +0 -62
- package/dist/src/executor/job-executor.d.ts.map +0 -1
- package/dist/src/executor/job-executor.js +0 -325
- package/dist/src/executor/job-executor.js.map +0 -1
- package/dist/test/job-executor.test.d.ts +0 -2
- package/dist/test/job-executor.test.d.ts.map +0 -1
- package/dist/test/job-executor.test.js +0 -581
- package/dist/test/job-executor.test.js.map +0 -1
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { MemoryStorage, ReactorBuilder, driveDocumentModelModule, } from "document-drive";
|
|
2
|
+
import { documentModelDocumentModelModule, } from "document-model";
|
|
3
|
+
import { v4 as uuidv4 } from "uuid";
|
|
4
|
+
import { vi } from "vitest";
|
|
5
|
+
import { EventBus } from "../src/events/event-bus.js";
|
|
6
|
+
import { SimpleJobExecutor } from "../src/executor/simple-job-executor.js";
|
|
7
|
+
import { SimpleJobExecutorManager } from "../src/executor/simple-job-executor-manager.js";
|
|
8
|
+
import { InMemoryQueue } from "../src/queue/queue.js";
|
|
9
|
+
import { Reactor } from "../src/reactor.js";
|
|
10
|
+
import { DocumentModelRegistry } from "../src/registry/implementation.js";
|
|
11
|
+
/**
|
|
12
|
+
* Factory for creating test Job objects
|
|
13
|
+
*/
|
|
14
|
+
export function createTestJob(overrides = {}) {
|
|
15
|
+
const defaultJob = {
|
|
16
|
+
id: overrides.id || `job-${uuidv4()}`,
|
|
17
|
+
documentId: "doc-1",
|
|
18
|
+
scope: "global",
|
|
19
|
+
branch: "main",
|
|
20
|
+
operation: createTestOperation(overrides.operation ? { ...overrides.operation } : undefined),
|
|
21
|
+
createdAt: new Date().toISOString(),
|
|
22
|
+
queueHint: [],
|
|
23
|
+
retryCount: 0,
|
|
24
|
+
maxRetries: 3,
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
...defaultJob,
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Factory for creating minimal Job objects (useful for performance tests)
|
|
33
|
+
*/
|
|
34
|
+
export function createMinimalJob(overrides = {}) {
|
|
35
|
+
return {
|
|
36
|
+
id: overrides.id || `job-${uuidv4()}`,
|
|
37
|
+
documentId: overrides.documentId || "doc-1",
|
|
38
|
+
scope: overrides.scope || "global",
|
|
39
|
+
branch: overrides.branch || "main",
|
|
40
|
+
operation: createMinimalOperation(),
|
|
41
|
+
createdAt: overrides.createdAt || "2023-01-01T00:00:00.000Z",
|
|
42
|
+
queueHint: overrides.queueHint || [],
|
|
43
|
+
...overrides,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Factory for creating test Operation objects
|
|
48
|
+
*/
|
|
49
|
+
export function createTestOperation(overrides = {}) {
|
|
50
|
+
const defaultOperation = {
|
|
51
|
+
index: 1,
|
|
52
|
+
timestampUtcMs: new Date().toISOString(),
|
|
53
|
+
hash: "test-hash",
|
|
54
|
+
skip: 0,
|
|
55
|
+
action: createTestAction(overrides.action ? { ...overrides.action } : undefined),
|
|
56
|
+
id: "op-1",
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
...defaultOperation,
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Factory for creating minimal Operation objects
|
|
65
|
+
*/
|
|
66
|
+
export function createMinimalOperation(overrides = {}) {
|
|
67
|
+
return {
|
|
68
|
+
index: overrides.index ?? 0,
|
|
69
|
+
timestampUtcMs: overrides.timestampUtcMs || "2023-01-01T00:00:00.000Z",
|
|
70
|
+
hash: overrides.hash || "hash-123",
|
|
71
|
+
skip: overrides.skip ?? 0,
|
|
72
|
+
action: overrides.action || createMinimalAction(),
|
|
73
|
+
id: overrides.id || `op-${uuidv4()}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Factory for creating test Action objects
|
|
78
|
+
*/
|
|
79
|
+
export function createTestAction(overrides = {}) {
|
|
80
|
+
const defaultAction = {
|
|
81
|
+
id: uuidv4(),
|
|
82
|
+
type: "test-operation",
|
|
83
|
+
timestampUtcMs: new Date().toISOString(),
|
|
84
|
+
input: { test: "data" },
|
|
85
|
+
scope: "global",
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
...defaultAction,
|
|
89
|
+
...overrides,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Factory for creating minimal Action objects
|
|
94
|
+
*/
|
|
95
|
+
export function createMinimalAction(overrides = {}) {
|
|
96
|
+
return {
|
|
97
|
+
id: overrides.id || `action-${uuidv4()}`,
|
|
98
|
+
type: overrides.type || "CREATE",
|
|
99
|
+
timestampUtcMs: overrides.timestampUtcMs || "2023-01-01T00:00:00.000Z",
|
|
100
|
+
input: overrides.input || { data: "test" },
|
|
101
|
+
scope: overrides.scope || "global",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Factory for creating specific document model actions
|
|
106
|
+
*/
|
|
107
|
+
export function createDocumentModelAction(type, overrides = {}) {
|
|
108
|
+
const actionTypes = {
|
|
109
|
+
SET_NAME: { name: "Test Name" },
|
|
110
|
+
SET_DESCRIPTION: { description: "Test Description" },
|
|
111
|
+
CREATE: { name: "New Document" },
|
|
112
|
+
UPDATE: { data: "Updated Data" },
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
id: uuidv4(),
|
|
116
|
+
type,
|
|
117
|
+
scope: "global",
|
|
118
|
+
timestampUtcMs: String(Date.now()),
|
|
119
|
+
input: actionTypes[type] || {},
|
|
120
|
+
...overrides,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Factory for creating mock PHDocument objects
|
|
125
|
+
*/
|
|
126
|
+
export function createMockDocument(overrides = {}) {
|
|
127
|
+
const baseDocument = documentModelDocumentModelModule.utils.createDocument();
|
|
128
|
+
if (overrides.id) {
|
|
129
|
+
baseDocument.header.id = overrides.id;
|
|
130
|
+
}
|
|
131
|
+
if (overrides.slug) {
|
|
132
|
+
baseDocument.header.slug = overrides.slug;
|
|
133
|
+
}
|
|
134
|
+
if (overrides.documentType) {
|
|
135
|
+
baseDocument.header.documentType = overrides.documentType;
|
|
136
|
+
}
|
|
137
|
+
if (overrides.state) {
|
|
138
|
+
baseDocument.state = {
|
|
139
|
+
...baseDocument.state,
|
|
140
|
+
...overrides.state,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return baseDocument;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Factory for creating test EventBus instances
|
|
147
|
+
*/
|
|
148
|
+
export function createTestEventBus() {
|
|
149
|
+
return new EventBus();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Factory for creating test EventBus with mock emit
|
|
153
|
+
*/
|
|
154
|
+
export function createMockEventBus() {
|
|
155
|
+
const eventBus = new EventBus();
|
|
156
|
+
const mockEmit = vi.fn().mockResolvedValue(undefined);
|
|
157
|
+
eventBus.emit = mockEmit;
|
|
158
|
+
return {
|
|
159
|
+
eventBus,
|
|
160
|
+
mockEmit,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Factory for creating test Queue instances
|
|
165
|
+
*/
|
|
166
|
+
export function createTestQueue(eventBus) {
|
|
167
|
+
return new InMemoryQueue(eventBus || createTestEventBus());
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Factory for creating test Registry instances
|
|
171
|
+
*/
|
|
172
|
+
export function createTestRegistry(modules) {
|
|
173
|
+
const registry = new DocumentModelRegistry();
|
|
174
|
+
if (modules) {
|
|
175
|
+
modules.forEach((module) => registry.registerModules(module));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Register default module
|
|
179
|
+
registry.registerModules(documentModelDocumentModelModule);
|
|
180
|
+
}
|
|
181
|
+
return registry;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Factory for creating mock JobExecutor
|
|
185
|
+
*/
|
|
186
|
+
export function createMockJobExecutor(overrides = {}) {
|
|
187
|
+
return {
|
|
188
|
+
executeJob: vi.fn().mockResolvedValue({ success: true }),
|
|
189
|
+
...overrides,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Factory for creating mock SimpleJobExecutor with spy functions
|
|
194
|
+
*/
|
|
195
|
+
export function createMockSimpleJobExecutor() {
|
|
196
|
+
const executeJobSpy = vi.fn().mockResolvedValue({
|
|
197
|
+
success: true,
|
|
198
|
+
result: {},
|
|
199
|
+
});
|
|
200
|
+
const executor = {
|
|
201
|
+
executeJob: executeJobSpy,
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
executor,
|
|
205
|
+
executeJobSpy,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Factory for creating mock IDocumentStorage
|
|
210
|
+
*/
|
|
211
|
+
export function createMockDocumentStorage(overrides = {}) {
|
|
212
|
+
return {
|
|
213
|
+
get: vi.fn().mockResolvedValue({
|
|
214
|
+
header: {
|
|
215
|
+
id: "doc-1",
|
|
216
|
+
documentType: "powerhouse/document-model",
|
|
217
|
+
},
|
|
218
|
+
operations: { global: [] },
|
|
219
|
+
state: {},
|
|
220
|
+
}),
|
|
221
|
+
set: vi.fn().mockResolvedValue(undefined),
|
|
222
|
+
delete: vi.fn().mockResolvedValue(undefined),
|
|
223
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
224
|
+
getChildren: vi.fn().mockResolvedValue([]),
|
|
225
|
+
findByType: vi.fn().mockResolvedValue([]),
|
|
226
|
+
resolveIds: vi.fn().mockResolvedValue([]),
|
|
227
|
+
...overrides,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Factory for creating mock IDocumentOperationStorage
|
|
232
|
+
*/
|
|
233
|
+
export function createMockOperationStorage(overrides = {}) {
|
|
234
|
+
return {
|
|
235
|
+
addDocumentOperations: vi.fn().mockResolvedValue(undefined),
|
|
236
|
+
...overrides,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Factory for creating a complete test reactor setup
|
|
241
|
+
*/
|
|
242
|
+
export async function createTestReactorSetup(documentModels = [
|
|
243
|
+
documentModelDocumentModelModule,
|
|
244
|
+
driveDocumentModelModule,
|
|
245
|
+
]) {
|
|
246
|
+
const storage = new MemoryStorage();
|
|
247
|
+
const eventBus = new EventBus();
|
|
248
|
+
const queue = new InMemoryQueue(eventBus);
|
|
249
|
+
// Create real drive server
|
|
250
|
+
const builder = new ReactorBuilder(documentModels).withStorage(storage);
|
|
251
|
+
const driveServer = builder.build();
|
|
252
|
+
await driveServer.initialize();
|
|
253
|
+
// Create registry and register modules
|
|
254
|
+
const registry = new DocumentModelRegistry();
|
|
255
|
+
registry.registerModules(documentModelDocumentModelModule);
|
|
256
|
+
// Create job executor
|
|
257
|
+
const jobExecutor = new SimpleJobExecutor(registry, storage, storage);
|
|
258
|
+
// Create reactor
|
|
259
|
+
const reactor = new Reactor(driveServer, storage, eventBus, queue, jobExecutor);
|
|
260
|
+
return {
|
|
261
|
+
reactor,
|
|
262
|
+
driveServer,
|
|
263
|
+
storage,
|
|
264
|
+
eventBus,
|
|
265
|
+
queue,
|
|
266
|
+
jobExecutor,
|
|
267
|
+
registry,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Factory for creating SimpleJobExecutorManager with dependencies
|
|
272
|
+
*/
|
|
273
|
+
export function createTestJobExecutorManager(queue, eventBus, executor) {
|
|
274
|
+
const actualQueue = queue || createTestQueue();
|
|
275
|
+
const actualEventBus = eventBus || createTestEventBus();
|
|
276
|
+
const actualExecutor = executor || createMockJobExecutor();
|
|
277
|
+
const manager = new SimpleJobExecutorManager(() => actualExecutor, actualEventBus, actualQueue);
|
|
278
|
+
return {
|
|
279
|
+
manager,
|
|
280
|
+
queue: actualQueue,
|
|
281
|
+
eventBus: actualEventBus,
|
|
282
|
+
executor: actualExecutor,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Factory for creating test data sets
|
|
287
|
+
*/
|
|
288
|
+
export function createTestJobSet(count, baseOverrides = {}) {
|
|
289
|
+
return Array.from({ length: count }, (_, i) => createTestJob({
|
|
290
|
+
id: `job-${i + 1}`,
|
|
291
|
+
...baseOverrides,
|
|
292
|
+
operation: createTestOperation({
|
|
293
|
+
index: i,
|
|
294
|
+
action: createTestAction({
|
|
295
|
+
input: { name: `Action ${i + 1}` },
|
|
296
|
+
}),
|
|
297
|
+
}),
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Factory for creating jobs with dependencies
|
|
302
|
+
*/
|
|
303
|
+
export function createJobWithDependencies(id, dependencies, overrides = {}) {
|
|
304
|
+
return createTestJob({
|
|
305
|
+
id,
|
|
306
|
+
queueHint: dependencies,
|
|
307
|
+
...overrides,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Factory for creating a dependency chain of jobs
|
|
312
|
+
*/
|
|
313
|
+
export function createJobDependencyChain(length) {
|
|
314
|
+
const jobs = [];
|
|
315
|
+
for (let i = 0; i < length; i++) {
|
|
316
|
+
const dependencies = i === 0 ? [] : [`job-${i}`];
|
|
317
|
+
jobs.push(createJobWithDependencies(`job-${i + 1}`, dependencies, {
|
|
318
|
+
operation: createTestOperation({
|
|
319
|
+
index: i,
|
|
320
|
+
action: createTestAction({
|
|
321
|
+
input: { name: `Chain Action ${i + 1}` },
|
|
322
|
+
}),
|
|
323
|
+
}),
|
|
324
|
+
}));
|
|
325
|
+
}
|
|
326
|
+
return jobs;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Factory for creating multiple actions for testing
|
|
330
|
+
*/
|
|
331
|
+
export function createTestActions(count, type = "SET_NAME") {
|
|
332
|
+
return Array.from({ length: count }, (_, i) => createDocumentModelAction(type, {
|
|
333
|
+
input: { name: `Action ${i + 1}` },
|
|
334
|
+
timestampUtcMs: String(Date.now() + i * 1000),
|
|
335
|
+
}));
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Factory for creating mock documents in bulk
|
|
339
|
+
*/
|
|
340
|
+
export function createTestDocuments(count, baseOverrides = {}) {
|
|
341
|
+
return Array.from({ length: count }, (_, i) => createMockDocument({
|
|
342
|
+
id: `doc-${i + 1}`,
|
|
343
|
+
slug: `doc-${i + 1}`,
|
|
344
|
+
...baseOverrides,
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=factories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factories.js","sourceRoot":"","sources":["../../test/factories.ts"],"names":[],"mappings":"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"}
|
package/dist/test/queue.test.js
CHANGED
|
@@ -1,36 +1,15 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it
|
|
2
|
-
import { EventBus } from "../src/events/event-bus.js";
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
3
2
|
import { InMemoryQueue } from "../src/queue/queue.js";
|
|
4
3
|
import { QueueEventTypes, } from "../src/queue/types.js";
|
|
4
|
+
import { createTestJob, createMockEventBus, createTestOperation, createJobWithDependencies, createJobDependencyChain, } from "./factories.js";
|
|
5
5
|
describe("InMemoryQueue", () => {
|
|
6
6
|
let queue;
|
|
7
7
|
let eventBus;
|
|
8
8
|
let mockEventBusEmit;
|
|
9
|
-
const createTestOperation = (overrides = {}) => ({
|
|
10
|
-
index: 1,
|
|
11
|
-
timestampUtcMs: new Date().toISOString(),
|
|
12
|
-
hash: "test-hash",
|
|
13
|
-
skip: 0,
|
|
14
|
-
type: "test-operation",
|
|
15
|
-
input: { test: "data" },
|
|
16
|
-
id: "op-1",
|
|
17
|
-
...overrides,
|
|
18
|
-
});
|
|
19
|
-
const createTestJob = (overrides = {}) => ({
|
|
20
|
-
id: "job-1",
|
|
21
|
-
documentId: "doc-1",
|
|
22
|
-
scope: "global",
|
|
23
|
-
branch: "main",
|
|
24
|
-
operation: createTestOperation(),
|
|
25
|
-
createdAt: new Date().toISOString(),
|
|
26
|
-
retryCount: 0,
|
|
27
|
-
maxRetries: 3,
|
|
28
|
-
...overrides,
|
|
29
|
-
});
|
|
30
9
|
beforeEach(() => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
10
|
+
const mocks = createMockEventBus();
|
|
11
|
+
eventBus = mocks.eventBus;
|
|
12
|
+
mockEventBusEmit = mocks.mockEmit;
|
|
34
13
|
queue = new InMemoryQueue(eventBus);
|
|
35
14
|
});
|
|
36
15
|
describe("enqueue", () => {
|
|
@@ -349,6 +328,212 @@ describe("InMemoryQueue", () => {
|
|
|
349
328
|
expect(await queue.size("doc:with:colons", "scope-with-dashes", "branch_with_underscores")).toBe(1);
|
|
350
329
|
});
|
|
351
330
|
});
|
|
331
|
+
describe("dependency management", () => {
|
|
332
|
+
it("should dequeue job with no dependencies immediately", async () => {
|
|
333
|
+
const job = createTestJob({ id: "job-1", queueHint: [] });
|
|
334
|
+
await queue.enqueue(job);
|
|
335
|
+
const dequeuedJob = await queue.dequeue(job.documentId, job.scope, job.branch);
|
|
336
|
+
expect(dequeuedJob?.id).toBe("job-1");
|
|
337
|
+
});
|
|
338
|
+
it("should block job with unmet dependencies", async () => {
|
|
339
|
+
const job1 = createTestJob({ id: "job-1", queueHint: ["job-0"] });
|
|
340
|
+
await queue.enqueue(job1);
|
|
341
|
+
const dequeuedJob = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
342
|
+
expect(dequeuedJob).toBeNull();
|
|
343
|
+
expect(await queue.size(job1.documentId, job1.scope, job1.branch)).toBe(1);
|
|
344
|
+
});
|
|
345
|
+
it("should dequeue job after dependencies are completed", async () => {
|
|
346
|
+
const job1 = createTestJob({ id: "job-1", queueHint: [] });
|
|
347
|
+
const job2 = createTestJob({ id: "job-2", queueHint: ["job-1"] });
|
|
348
|
+
await queue.enqueue(job1);
|
|
349
|
+
await queue.enqueue(job2);
|
|
350
|
+
// First job should be dequeued
|
|
351
|
+
const dequeuedJob1 = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
352
|
+
expect(dequeuedJob1?.id).toBe("job-1");
|
|
353
|
+
// Second job should be blocked
|
|
354
|
+
const blockedJob = await queue.dequeue(job2.documentId, job2.scope, job2.branch);
|
|
355
|
+
expect(blockedJob).toBeNull();
|
|
356
|
+
// Complete first job
|
|
357
|
+
await queue.completeJob("job-1");
|
|
358
|
+
// Now second job should be available
|
|
359
|
+
const dequeuedJob2 = await queue.dequeue(job2.documentId, job2.scope, job2.branch);
|
|
360
|
+
expect(dequeuedJob2?.id).toBe("job-2");
|
|
361
|
+
});
|
|
362
|
+
it("should handle multiple dependencies", async () => {
|
|
363
|
+
const job1 = createTestJob({ id: "job-1", queueHint: [] });
|
|
364
|
+
const job2 = createTestJob({ id: "job-2", queueHint: [] });
|
|
365
|
+
const job3 = createTestJob({
|
|
366
|
+
id: "job-3",
|
|
367
|
+
queueHint: ["job-1", "job-2"],
|
|
368
|
+
});
|
|
369
|
+
await queue.enqueue(job1);
|
|
370
|
+
await queue.enqueue(job2);
|
|
371
|
+
await queue.enqueue(job3);
|
|
372
|
+
// Dequeue and complete first job
|
|
373
|
+
const dequeuedJob1 = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
374
|
+
expect(dequeuedJob1?.id).toBe("job-1");
|
|
375
|
+
await queue.completeJob("job-1");
|
|
376
|
+
// Next dequeue should return job-2 (not blocked), not job-3 (still blocked)
|
|
377
|
+
const nextJob = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
378
|
+
expect(nextJob?.id).toBe("job-2");
|
|
379
|
+
await queue.completeJob("job-2");
|
|
380
|
+
// Now job 3 should be available
|
|
381
|
+
const dequeuedJob3 = await queue.dequeue(job3.documentId, job3.scope, job3.branch);
|
|
382
|
+
expect(dequeuedJob3?.id).toBe("job-3");
|
|
383
|
+
});
|
|
384
|
+
it("should handle dependency chains", async () => {
|
|
385
|
+
const jobs = createJobDependencyChain(4);
|
|
386
|
+
for (const job of jobs) {
|
|
387
|
+
await queue.enqueue(job);
|
|
388
|
+
}
|
|
389
|
+
// Process in order
|
|
390
|
+
const d1 = await queue.dequeue(jobs[0].documentId, jobs[0].scope, jobs[0].branch);
|
|
391
|
+
expect(d1?.id).toBe("job-1");
|
|
392
|
+
// Others should be blocked
|
|
393
|
+
expect(await queue.dequeue(jobs[1].documentId, jobs[1].scope, jobs[1].branch)).toBeNull();
|
|
394
|
+
expect(await queue.dequeue(jobs[2].documentId, jobs[2].scope, jobs[2].branch)).toBeNull();
|
|
395
|
+
expect(await queue.dequeue(jobs[3].documentId, jobs[3].scope, jobs[3].branch)).toBeNull();
|
|
396
|
+
await queue.completeJob("job-1");
|
|
397
|
+
const d2 = await queue.dequeue(jobs[1].documentId, jobs[1].scope, jobs[1].branch);
|
|
398
|
+
expect(d2?.id).toBe("job-2");
|
|
399
|
+
// job-3 and job-4 still blocked
|
|
400
|
+
expect(await queue.dequeue(jobs[2].documentId, jobs[2].scope, jobs[2].branch)).toBeNull();
|
|
401
|
+
expect(await queue.dequeue(jobs[3].documentId, jobs[3].scope, jobs[3].branch)).toBeNull();
|
|
402
|
+
await queue.completeJob("job-2");
|
|
403
|
+
const d3 = await queue.dequeue(jobs[2].documentId, jobs[2].scope, jobs[2].branch);
|
|
404
|
+
expect(d3?.id).toBe("job-3");
|
|
405
|
+
// job-4 still blocked
|
|
406
|
+
expect(await queue.dequeue(jobs[3].documentId, jobs[3].scope, jobs[3].branch)).toBeNull();
|
|
407
|
+
await queue.completeJob("job-3");
|
|
408
|
+
const d4 = await queue.dequeue(jobs[3].documentId, jobs[3].scope, jobs[3].branch);
|
|
409
|
+
expect(d4?.id).toBe("job-4");
|
|
410
|
+
});
|
|
411
|
+
it("should dequeue jobs out of order based on dependencies", async () => {
|
|
412
|
+
const job1 = createTestJob({ id: "job-1", queueHint: ["job-0"] });
|
|
413
|
+
const job2 = createTestJob({ id: "job-2", queueHint: [] });
|
|
414
|
+
const job3 = createTestJob({ id: "job-3", queueHint: [] });
|
|
415
|
+
await queue.enqueue(job1);
|
|
416
|
+
await queue.enqueue(job2);
|
|
417
|
+
await queue.enqueue(job3);
|
|
418
|
+
// Job 1 is blocked, so job 2 should be dequeued
|
|
419
|
+
const dequeuedJob = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
420
|
+
expect(dequeuedJob?.id).toBe("job-2");
|
|
421
|
+
});
|
|
422
|
+
it("should handle dependencies across different queues", async () => {
|
|
423
|
+
const job1 = createTestJob({
|
|
424
|
+
id: "job-1",
|
|
425
|
+
documentId: "doc-1",
|
|
426
|
+
queueHint: [],
|
|
427
|
+
});
|
|
428
|
+
const job2 = createTestJob({
|
|
429
|
+
id: "job-2",
|
|
430
|
+
documentId: "doc-2",
|
|
431
|
+
queueHint: ["job-1"],
|
|
432
|
+
});
|
|
433
|
+
await queue.enqueue(job1);
|
|
434
|
+
await queue.enqueue(job2);
|
|
435
|
+
// Job 2 should be blocked even though it's in a different queue
|
|
436
|
+
const blockedJob = await queue.dequeue("doc-2", "global", "main");
|
|
437
|
+
expect(blockedJob).toBeNull();
|
|
438
|
+
// Dequeue and complete job 1
|
|
439
|
+
const dequeuedJob1 = await queue.dequeue("doc-1", "global", "main");
|
|
440
|
+
expect(dequeuedJob1?.id).toBe("job-1");
|
|
441
|
+
await queue.completeJob("job-1");
|
|
442
|
+
// Now job 2 should be available
|
|
443
|
+
const dequeuedJob2 = await queue.dequeue("doc-2", "global", "main");
|
|
444
|
+
expect(dequeuedJob2?.id).toBe("job-2");
|
|
445
|
+
});
|
|
446
|
+
it("should work with dequeueNext respecting dependencies", async () => {
|
|
447
|
+
const job1 = createTestJob({
|
|
448
|
+
id: "job-1",
|
|
449
|
+
documentId: "doc-1",
|
|
450
|
+
queueHint: ["job-0"],
|
|
451
|
+
});
|
|
452
|
+
const job2 = createTestJob({
|
|
453
|
+
id: "job-2",
|
|
454
|
+
documentId: "doc-2",
|
|
455
|
+
queueHint: [],
|
|
456
|
+
});
|
|
457
|
+
await queue.enqueue(job1);
|
|
458
|
+
await queue.enqueue(job2);
|
|
459
|
+
// Should dequeue job-2 since job-1 is blocked
|
|
460
|
+
const dequeuedJob = await queue.dequeueNext();
|
|
461
|
+
expect(dequeuedJob?.id).toBe("job-2");
|
|
462
|
+
});
|
|
463
|
+
it("should handle circular dependencies by blocking all involved jobs", async () => {
|
|
464
|
+
const job1 = createJobWithDependencies("job-1", ["job-2"]);
|
|
465
|
+
const job2 = createJobWithDependencies("job-2", ["job-1"]);
|
|
466
|
+
await queue.enqueue(job1);
|
|
467
|
+
await queue.enqueue(job2);
|
|
468
|
+
// Both jobs should be blocked
|
|
469
|
+
const dequeuedJob1 = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
470
|
+
expect(dequeuedJob1).toBeNull();
|
|
471
|
+
const dequeuedJob2 = await queue.dequeue(job2.documentId, job2.scope, job2.branch);
|
|
472
|
+
expect(dequeuedJob2).toBeNull();
|
|
473
|
+
});
|
|
474
|
+
it("should handle self-dependencies by blocking the job", async () => {
|
|
475
|
+
const job = createJobWithDependencies("job-1", ["job-1"]);
|
|
476
|
+
await queue.enqueue(job);
|
|
477
|
+
const dequeuedJob = await queue.dequeue(job.documentId, job.scope, job.branch);
|
|
478
|
+
expect(dequeuedJob).toBeNull();
|
|
479
|
+
});
|
|
480
|
+
it("should clear completed jobs tracking when clearAll is called", async () => {
|
|
481
|
+
const job1 = createTestJob({ id: "job-1", queueHint: [] });
|
|
482
|
+
const job2 = createTestJob({ id: "job-2", queueHint: ["job-1"] });
|
|
483
|
+
await queue.enqueue(job1);
|
|
484
|
+
// Complete job-1
|
|
485
|
+
await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
486
|
+
await queue.completeJob("job-1");
|
|
487
|
+
// Clear all
|
|
488
|
+
await queue.clearAll();
|
|
489
|
+
// Re-enqueue job-2 - it should be blocked again since completed jobs were cleared
|
|
490
|
+
await queue.enqueue(job2);
|
|
491
|
+
const dequeuedJob = await queue.dequeue(job2.documentId, job2.scope, job2.branch);
|
|
492
|
+
expect(dequeuedJob).toBeNull();
|
|
493
|
+
});
|
|
494
|
+
it("should handle already completed dependencies", async () => {
|
|
495
|
+
// Complete a job that doesn't exist in queue
|
|
496
|
+
await queue.completeJob("job-0");
|
|
497
|
+
// Enqueue a job that depends on it
|
|
498
|
+
const job1 = createJobWithDependencies("job-1", ["job-0"]);
|
|
499
|
+
await queue.enqueue(job1);
|
|
500
|
+
// Should be able to dequeue since dependency is already complete
|
|
501
|
+
const dequeuedJob = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
502
|
+
expect(dequeuedJob?.id).toBe("job-1");
|
|
503
|
+
});
|
|
504
|
+
it("should handle mixed dependencies (some met, some unmet)", async () => {
|
|
505
|
+
// Complete one dependency
|
|
506
|
+
await queue.completeJob("job-0");
|
|
507
|
+
// Enqueue a job with mixed dependencies
|
|
508
|
+
const job = createTestJob({
|
|
509
|
+
id: "job-3",
|
|
510
|
+
queueHint: ["job-0", "job-1", "job-2"],
|
|
511
|
+
});
|
|
512
|
+
await queue.enqueue(job);
|
|
513
|
+
// Should be blocked (job-1 and job-2 not complete)
|
|
514
|
+
let dequeuedJob = await queue.dequeue(job.documentId, job.scope, job.branch);
|
|
515
|
+
expect(dequeuedJob).toBeNull();
|
|
516
|
+
// Complete remaining dependencies
|
|
517
|
+
await queue.completeJob("job-1");
|
|
518
|
+
await queue.completeJob("job-2");
|
|
519
|
+
// Now should be available
|
|
520
|
+
dequeuedJob = await queue.dequeue(job.documentId, job.scope, job.branch);
|
|
521
|
+
expect(dequeuedJob?.id).toBe("job-3");
|
|
522
|
+
});
|
|
523
|
+
it("should handle failJob without marking as completed", async () => {
|
|
524
|
+
const job1 = createTestJob({ id: "job-1", queueHint: [] });
|
|
525
|
+
const job2 = createTestJob({ id: "job-2", queueHint: ["job-1"] });
|
|
526
|
+
await queue.enqueue(job1);
|
|
527
|
+
await queue.enqueue(job2);
|
|
528
|
+
// Dequeue and fail job 1
|
|
529
|
+
const d1 = await queue.dequeue(job1.documentId, job1.scope, job1.branch);
|
|
530
|
+
expect(d1?.id).toBe("job-1");
|
|
531
|
+
await queue.failJob("job-1", "Test error");
|
|
532
|
+
// Job 2 should still be blocked since job 1 wasn't completed
|
|
533
|
+
const dequeuedJob = await queue.dequeue(job2.documentId, job2.scope, job2.branch);
|
|
534
|
+
expect(dequeuedJob).toBeNull();
|
|
535
|
+
});
|
|
536
|
+
});
|
|
352
537
|
describe("job properties", () => {
|
|
353
538
|
it("should preserve all job properties", async () => {
|
|
354
539
|
const operation = createTestOperation({
|
|
@@ -356,8 +541,13 @@ describe("InMemoryQueue", () => {
|
|
|
356
541
|
timestampUtcMs: "2023-01-01T00:00:00.000Z",
|
|
357
542
|
hash: "custom-hash",
|
|
358
543
|
skip: 5,
|
|
359
|
-
|
|
360
|
-
|
|
544
|
+
action: {
|
|
545
|
+
id: "action-1",
|
|
546
|
+
type: "custom-operation",
|
|
547
|
+
timestampUtcMs: "2023-01-01T00:00:00.000Z",
|
|
548
|
+
input: { custom: "input" },
|
|
549
|
+
scope: "global",
|
|
550
|
+
},
|
|
361
551
|
error: "test error",
|
|
362
552
|
id: "custom-op-id",
|
|
363
553
|
});
|
|
@@ -383,6 +573,7 @@ describe("InMemoryQueue", () => {
|
|
|
383
573
|
branch: "main",
|
|
384
574
|
operation: createTestOperation(),
|
|
385
575
|
createdAt: new Date().toISOString(),
|
|
576
|
+
queueHint: [],
|
|
386
577
|
// retryCount and maxRetries are optional
|
|
387
578
|
};
|
|
388
579
|
await queue.enqueue(job);
|