@actiondock/testing 2.0.11-beta.0 → 2.0.12

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/src/runtime.ts DELETED
@@ -1,380 +0,0 @@
1
- import {
2
- ActionRunner,
3
- type ExecutionStartOptions,
4
- InMemoryEventSink,
5
- type ProjectConfig,
6
- RuntimeConfig,
7
- RuntimeStateStore,
8
- setDefaultEventSink,
9
- setProcessExecutor,
10
- } from "@actiondock/core";
11
- import type {
12
- ActionDefinition,
13
- Config,
14
- ExecutionEvent,
15
- ExecutionResult,
16
- JsonValue,
17
- ProgressReporter,
18
- RuntimeError,
19
- StateStore,
20
- } from "@actiondock/sdk";
21
- import { FakeClock } from "./clock";
22
- import { MockProcessExecutor } from "./process";
23
- import { MemoryStorage } from "./storage";
24
-
25
- /**
26
- * 规范化运行时错误异常类。
27
- * 当 run 方法执行失败时抛出,完整实现 RuntimeError 契约。
28
- */
29
- export class ActionRuntimeError extends Error implements RuntimeError {
30
- public code: string;
31
- public details?: unknown;
32
- public cause?: unknown;
33
-
34
- constructor(error: RuntimeError) {
35
- super(error.message);
36
- this.name = "ActionRuntimeError";
37
- this.code = error.code;
38
- this.details = error.details;
39
- this.cause = error.cause;
40
- Object.setPrototypeOf(this, ActionRuntimeError.prototype);
41
- }
42
- }
43
-
44
- /**
45
- * 带有写入和调试能力的配置接口。
46
- */
47
- export interface TestConfig extends Config {
48
- /** 写入配置键值 */
49
- set(key: string, value: unknown): void;
50
- /** 删除指定配置键 */
51
- delete(key: string): boolean;
52
- /** 列出所有已存储配置项 */
53
- list(): Record<string, unknown>;
54
- }
55
-
56
- /**
57
- * 测试配置管理器实现。
58
- */
59
- export class TestConfigStore implements TestConfig {
60
- private runtimeConfig: RuntimeConfig;
61
- private storage: MemoryStorage;
62
-
63
- constructor(
64
- storage: MemoryStorage,
65
- projectConfig?: ProjectConfig,
66
- overrides?: Record<string, unknown>
67
- ) {
68
- this.storage = storage;
69
- this.runtimeConfig = new RuntimeConfig(
70
- storage,
71
- overrides,
72
- projectConfig,
73
- undefined
74
- );
75
- }
76
-
77
- get<T = unknown>(key: string): T | undefined;
78
- get<T = unknown>(key: string, defaultValue: T): T;
79
- get<T = unknown>(key: string, defaultValue?: T): T | undefined {
80
- return this.runtimeConfig.get(key, defaultValue as T);
81
- }
82
-
83
- has(key: string): boolean {
84
- return this.runtimeConfig.has(key);
85
- }
86
-
87
- set(key: string, value: unknown): void {
88
- this.storage.setConfig(key, value);
89
- }
90
-
91
- delete(key: string): boolean {
92
- return this.storage.deleteConfig(key);
93
- }
94
-
95
- list(): Record<string, unknown> {
96
- return this.storage.listConfig();
97
- }
98
- }
99
-
100
- /**
101
- * 测试事件接收器实现。
102
- * 记录执行期间产生的所有事件并支持历史检索。
103
- */
104
- export class TestEventSink extends InMemoryEventSink {
105
- private allEvents: ExecutionEvent[] = [];
106
- private sequenceCounter = 0;
107
-
108
- /** 获取下一个单调自增序号 */
109
- nextSequence(): number {
110
- return this.sequenceCounter++;
111
- }
112
-
113
- override emit(event: ExecutionEvent): void {
114
- this.allEvents.push(event);
115
- super.emit(event);
116
- }
117
-
118
- /**
119
- * 检索历史事件列表。
120
- *
121
- * @param runId 可选运行标识筛选
122
- */
123
- getEvents(runId?: string): ExecutionEvent[] {
124
- if (runId) {
125
- return this.allEvents.filter((e) => e.runId === runId);
126
- }
127
- return [...this.allEvents];
128
- }
129
-
130
- /**
131
- * 清理所有捕获的事件记录。
132
- */
133
- clearAll(): void {
134
- this.allEvents = [];
135
- this.sequenceCounter = 0;
136
- }
137
- }
138
-
139
- /**
140
- * 测试运行时初始化选项。
141
- */
142
- export interface TestRuntimeOptions {
143
- /** 绑定的 Package 标识 */
144
- packageId?: string;
145
- /** 初始注入的配置键值映射 */
146
- config?: Record<string, unknown>;
147
- /** 运行级别临时配置覆写字典 */
148
- configOverrides?: Record<string, unknown>;
149
- /** 初始注入的状态键值映射 */
150
- state?: Record<string, unknown>;
151
- /** 可选注入的模拟时钟实例 */
152
- clock?: FakeClock;
153
- /** 可选注入的模拟进程执行器 */
154
- process?: MockProcessExecutor;
155
- /** 可选注入的底层存储实例 */
156
- storage?: MemoryStorage;
157
- /** 项目静态配置元数据 */
158
- projectConfig?: ProjectConfig;
159
- /** 预注册的 Action 动作列表 */
160
- actions?: ActionDefinition[];
161
- }
162
-
163
- /**
164
- * 测试运行时接口。
165
- */
166
- export interface TestRuntime {
167
- /** 调试配置接口 */
168
- config: TestConfig;
169
- /** 调试状态持久化接口 */
170
- state: StateStore;
171
- /** 调试模拟时钟接口 */
172
- clock: FakeClock;
173
- /** 调试模拟进程执行接口 */
174
- process: MockProcessExecutor;
175
- /** 调试执行事件捕获接口 */
176
- events: TestEventSink;
177
- /** 底层存储引擎 */
178
- storage: MemoryStorage;
179
- /** 核心执行器引擎 */
180
- runner: ActionRunner;
181
- /** 注册 Action 动作定义 */
182
- registerAction(action: ActionDefinition): void;
183
- /** 获取已注册的 Action 动作定义 */
184
- getAction(id: string): ActionDefinition | undefined;
185
- /** 列出已注册的所有 Action 动作定义 */
186
- listActions(): ActionDefinition[];
187
- /**
188
- * 执行 Action 并直接返回业务结果数据,失败时抛出 ActionRuntimeError 规范化异常。
189
- *
190
- * @param action Action 动作定义或已注册标识
191
- * @param input 输入参数数据
192
- */
193
- run<I = unknown, O = unknown>(
194
- action: ActionDefinition<I, O> | string,
195
- input?: I
196
- ): Promise<O>;
197
- /**
198
- * 执行 Action 并返回完整的 ExecutionResult 信封结构。
199
- *
200
- * @param action Action 动作定义或已注册标识
201
- * @param input 输入参数数据
202
- * @param options 可选执行控制参数
203
- */
204
- execute<I = unknown, O = unknown>(
205
- action: ActionDefinition<I, O> | string,
206
- input?: I,
207
- options?: ExecutionStartOptions
208
- ): Promise<ExecutionResult<O>>;
209
- }
210
-
211
- /**
212
- * 创建全功能测试运行时实例。
213
- * 复用真实的 ActionRunner 执行全生命周期,并暴露配置、状态、时钟、进程与事件等调试接口。
214
- *
215
- * @param options 测试运行时选项
216
- */
217
- export function createTestRuntime(options: TestRuntimeOptions = {}): TestRuntime {
218
- const packageId = options.packageId || "test-pkg";
219
- const clock = options.clock ?? new FakeClock();
220
- const process = options.process ?? new MockProcessExecutor();
221
- const storage =
222
- options.storage ??
223
- new MemoryStorage({
224
- packageId,
225
- clock,
226
- });
227
-
228
- // 全局注入测试进程执行器
229
- setProcessExecutor(process);
230
-
231
- // 初始化配置数据
232
- if (options.config) {
233
- for (const [key, val] of Object.entries(options.config)) {
234
- storage.setConfig(key, val);
235
- }
236
- }
237
-
238
- // 初始化状态数据
239
- if (options.state) {
240
- for (const [key, val] of Object.entries(options.state)) {
241
- storage.setState("", key, val);
242
- }
243
- }
244
-
245
- const events = new TestEventSink();
246
- setDefaultEventSink(events);
247
-
248
- const actionsMap = new Map<string, ActionDefinition>();
249
- if (options.actions) {
250
- for (const act of options.actions) {
251
- actionsMap.set(act.id, act);
252
- }
253
- }
254
-
255
- const runner = new ActionRunner({
256
- packageId,
257
- storage,
258
- projectConfig: options.projectConfig,
259
- configOverrides: options.configOverrides,
260
- actions: actionsMap,
261
- process,
262
- });
263
-
264
- const testConfig = new TestConfigStore(
265
- storage,
266
- options.projectConfig,
267
- options.configOverrides
268
- );
269
-
270
- const testState = new RuntimeStateStore(storage);
271
-
272
- const registerAction = (action: ActionDefinition): void => {
273
- runner.registerAction(action);
274
- };
275
-
276
- const getAction = (id: string): ActionDefinition | undefined => {
277
- return runner.getAction(id);
278
- };
279
-
280
- const listActions = (): ActionDefinition[] => {
281
- return runner.listActions();
282
- };
283
-
284
- const execute = async <I = unknown, O = unknown>(
285
- action: ActionDefinition<I, O> | string,
286
- input: I = {} as I,
287
- execOptions: ExecutionStartOptions = {}
288
- ): Promise<ExecutionResult<O>> => {
289
- if (typeof action !== "string") {
290
- runner.registerAction(action as ActionDefinition);
291
- }
292
-
293
- const actionId = typeof action === "string" ? action : action.id;
294
-
295
- // 组合进度报告器以发射执行事件
296
- const originalProgress = execOptions.progress;
297
- const progressReporter: ProgressReporter = {
298
- report(current: number, total?: number, message?: string) {
299
- if (originalProgress) {
300
- originalProgress.report(current, total, message);
301
- }
302
- events.emit({
303
- runId: handle.runId,
304
- rootRunId: execOptions.rootRunId || handle.runId,
305
- sequence: events.nextSequence(),
306
- timestamp: clock.now().toISOString(),
307
- type: "progress",
308
- current,
309
- total,
310
- message,
311
- });
312
- },
313
- };
314
-
315
- const startOptions: ExecutionStartOptions = {
316
- ...execOptions,
317
- process: execOptions.process || process,
318
- progress: progressReporter,
319
- };
320
-
321
- const handle = runner.start(action, input, startOptions);
322
-
323
- events.emit({
324
- runId: handle.runId,
325
- rootRunId: execOptions.rootRunId || handle.runId,
326
- sequence: events.nextSequence(),
327
- timestamp: clock.now().toISOString(),
328
- type: "status",
329
- status: "running",
330
- });
331
-
332
- const result = (await handle.result) as ExecutionResult<O>;
333
-
334
- events.emit({
335
- runId: handle.runId,
336
- rootRunId: execOptions.rootRunId || handle.runId,
337
- sequence: events.nextSequence(),
338
- timestamp: clock.now().toISOString(),
339
- type: "finish",
340
- result: result as ExecutionResult<JsonValue>,
341
- });
342
-
343
- events.emit({
344
- runId: handle.runId,
345
- rootRunId: execOptions.rootRunId || handle.runId,
346
- sequence: events.nextSequence(),
347
- timestamp: clock.now().toISOString(),
348
- type: "status",
349
- status: result.ok ? "success" : "failed",
350
- });
351
-
352
- return result;
353
- };
354
-
355
- const run = async <I = unknown, O = unknown>(
356
- action: ActionDefinition<I, O> | string,
357
- input: I = {} as I
358
- ): Promise<O> => {
359
- const result = await execute<I, O>(action, input);
360
- if (!result.ok) {
361
- throw new ActionRuntimeError(result.error);
362
- }
363
- return result.data;
364
- };
365
-
366
- return {
367
- config: testConfig,
368
- state: testState,
369
- clock,
370
- process,
371
- events,
372
- storage,
373
- runner,
374
- registerAction,
375
- getAction,
376
- listActions,
377
- run,
378
- execute,
379
- };
380
- }
package/src/storage.ts DELETED
@@ -1,37 +0,0 @@
1
- import {
2
- type Clock,
3
- type RuntimeStorage,
4
- SqliteRuntimeStorage,
5
- type SqliteDriver,
6
- type StateEntry,
7
- type TerminalRunStatus,
8
- } from "@actiondock/core";
9
- import type { RuntimeError, RunRecord } from "@actiondock/sdk";
10
-
11
- /**
12
- * 内存运行时存储初始化选项。
13
- */
14
- export interface MemoryStorageOptions {
15
- /** 绑定的 Package 标识,默认为 test-pkg */
16
- packageId?: string;
17
- /** 可选注入的时间提供器,便于与模拟时钟联动 */
18
- clock?: Clock;
19
- /** 可选显式注入的底层 SQLite 驱动 */
20
- driver?: SqliteDriver;
21
- }
22
-
23
- /**
24
- * 统一内存运行时存储实现。
25
- * 基于 SqliteRuntimeStorage 构建,默认使用 :memory: 内存数据库并对接虚拟时钟,
26
- * 确保与生产环境具备完全相同的配置优先级、状态过期契约与运行终态行为。
27
- */
28
- export class MemoryStorage extends SqliteRuntimeStorage {
29
- constructor(options: MemoryStorageOptions = {}) {
30
- super({
31
- packageId: options.packageId || "test-pkg",
32
- dbPath: ":memory:",
33
- driver: options.driver,
34
- clock: options.clock,
35
- });
36
- }
37
- }