@northflare/runner 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -3
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -12
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -176
- package/coverage/lib/index.html +0 -116
- package/coverage/lib/preload-script.js.html +0 -964
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/src/collections/index.html +0 -116
- package/coverage/src/collections/runner-messages.ts.html +0 -312
- package/coverage/src/components/claude-manager.ts.html +0 -1290
- package/coverage/src/components/index.html +0 -146
- package/coverage/src/components/message-handler.ts.html +0 -730
- package/coverage/src/components/repository-manager.ts.html +0 -841
- package/coverage/src/index.html +0 -131
- package/coverage/src/index.ts.html +0 -448
- package/coverage/src/runner.ts.html +0 -1239
- package/coverage/src/utils/config.ts.html +0 -780
- package/coverage/src/utils/console.ts.html +0 -121
- package/coverage/src/utils/index.html +0 -161
- package/coverage/src/utils/logger.ts.html +0 -475
- package/coverage/src/utils/status-line.ts.html +0 -445
- package/exceptions.log +0 -24
- package/lib/codex-sdk/src/codex.ts +0 -38
- package/lib/codex-sdk/src/codexOptions.ts +0 -10
- package/lib/codex-sdk/src/events.ts +0 -80
- package/lib/codex-sdk/src/exec.ts +0 -336
- package/lib/codex-sdk/src/index.ts +0 -39
- package/lib/codex-sdk/src/items.ts +0 -127
- package/lib/codex-sdk/src/outputSchemaFile.ts +0 -40
- package/lib/codex-sdk/src/thread.ts +0 -155
- package/lib/codex-sdk/src/threadOptions.ts +0 -18
- package/lib/codex-sdk/src/turnOptions.ts +0 -6
- package/lib/codex-sdk/tests/abort.test.ts +0 -165
- package/lib/codex-sdk/tests/codexExecSpy.ts +0 -37
- package/lib/codex-sdk/tests/responsesProxy.ts +0 -225
- package/lib/codex-sdk/tests/run.test.ts +0 -687
- package/lib/codex-sdk/tests/runStreamed.test.ts +0 -211
- package/lib/codex-sdk/tsconfig.json +0 -24
- package/rejections.log +0 -68
- package/runner.log +0 -488
- package/src/components/claude-sdk-manager.ts +0 -1425
- package/src/components/codex-sdk-manager.ts +0 -1358
- package/src/components/enhanced-repository-manager.ts +0 -823
- package/src/components/message-handler-sse.ts +0 -1097
- package/src/components/repository-manager.ts +0 -337
- package/src/index.ts +0 -168
- package/src/runner-sse.ts +0 -917
- package/src/services/RunnerAPIClient.ts +0 -175
- package/src/services/SSEClient.ts +0 -258
- package/src/types/claude.ts +0 -66
- package/src/types/computer-name.d.ts +0 -4
- package/src/types/index.ts +0 -64
- package/src/types/messages.ts +0 -39
- package/src/types/runner-interface.ts +0 -36
- package/src/utils/StateManager.ts +0 -187
- package/src/utils/config.ts +0 -327
- package/src/utils/console.ts +0 -15
- package/src/utils/debug.ts +0 -18
- package/src/utils/expand-env.ts +0 -22
- package/src/utils/logger.ts +0 -134
- package/src/utils/model.ts +0 -29
- package/src/utils/status-line.ts +0 -122
- package/src/utils/tool-response-sanitizer.ts +0 -160
- package/test-debug.sh +0 -26
- package/tests/retry-strategies.test.ts +0 -410
- package/tests/sdk-integration.test.ts +0 -329
- package/tests/sdk-streaming.test.ts +0 -1180
- package/tests/setup.ts +0 -5
- package/tests/test-claude-manager.ts +0 -120
- package/tests/tool-response-sanitizer.test.ts +0 -63
- package/tsconfig.json +0 -36
- package/vitest.config.ts +0 -27
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for runner registration retry strategies
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
6
|
-
import { RunnerApp } from "../src/runner-sse";
|
|
7
|
-
import { RunnerConfig } from "../src/types";
|
|
8
|
-
|
|
9
|
-
// Mock dependencies
|
|
10
|
-
vi.mock('simple-git', () => ({
|
|
11
|
-
default: vi.fn(() => ({
|
|
12
|
-
init: vi.fn().mockResolvedValue(undefined),
|
|
13
|
-
addConfig: vi.fn().mockResolvedValue(undefined),
|
|
14
|
-
}))
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
vi.mock('fs/promises', () => ({
|
|
18
|
-
default: {
|
|
19
|
-
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
20
|
-
access: vi.fn().mockRejectedValue(new Error('Not found')),
|
|
21
|
-
readFile: vi.fn().mockResolvedValue('{}'),
|
|
22
|
-
writeFile: vi.fn().mockResolvedValue(undefined),
|
|
23
|
-
}
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
vi.mock('../src/components/message-handler-sse', () => ({
|
|
27
|
-
MessageHandler: vi.fn().mockImplementation(() => ({
|
|
28
|
-
startProcessing: vi.fn().mockResolvedValue(undefined),
|
|
29
|
-
stopProcessing: vi.fn().mockResolvedValue(undefined),
|
|
30
|
-
initializeCollectionAfterRegistration: vi.fn(),
|
|
31
|
-
}))
|
|
32
|
-
}));
|
|
33
|
-
|
|
34
|
-
vi.mock('../src/components/claude-sdk-manager', () => ({
|
|
35
|
-
ClaudeManager: vi.fn().mockImplementation(() => ({
|
|
36
|
-
stopConversation: vi.fn().mockResolvedValue(undefined),
|
|
37
|
-
}))
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
vi.mock('../src/components/enhanced-repository-manager', () => ({
|
|
41
|
-
EnhancedRepositoryManager: vi.fn().mockImplementation(() => ({
|
|
42
|
-
createLocalTaskHandle: vi.fn(),
|
|
43
|
-
createTaskWorktree: vi.fn(),
|
|
44
|
-
checkoutRepository: vi.fn(),
|
|
45
|
-
getWorkspacePath: vi.fn(),
|
|
46
|
-
}))
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
vi.mock('../src/utils/logger', () => ({
|
|
50
|
-
createLogger: vi.fn(() => ({
|
|
51
|
-
info: vi.fn(),
|
|
52
|
-
warn: vi.fn(),
|
|
53
|
-
error: vi.fn(),
|
|
54
|
-
debug: vi.fn(),
|
|
55
|
-
}))
|
|
56
|
-
}));
|
|
57
|
-
|
|
58
|
-
vi.mock('../src/utils/status-line', () => ({
|
|
59
|
-
statusLineManager: {
|
|
60
|
-
dispose: vi.fn(),
|
|
61
|
-
}
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
beforeEach(() => {
|
|
65
|
-
vi.clearAllMocks();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
afterEach(() => {
|
|
69
|
-
vi.clearAllMocks();
|
|
70
|
-
vi.clearAllTimers();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe("Runner Registration Retry Strategies", () => {
|
|
74
|
-
const baseConfig: RunnerConfig = {
|
|
75
|
-
orchestratorUrl: "http://orchestrator.test",
|
|
76
|
-
dataDir: "./test-data",
|
|
77
|
-
heartbeatInterval: 120000,
|
|
78
|
-
retryStrategy: "none",
|
|
79
|
-
retryIntervalSecs: 60,
|
|
80
|
-
retryDurationSecs: 900,
|
|
81
|
-
workspaceDir: "/test/workspace",
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
describe("No Retry Strategy", () => {
|
|
85
|
-
it("should fail immediately if registration fails", async () => {
|
|
86
|
-
const config = { ...baseConfig, retryStrategy: "none" as const };
|
|
87
|
-
const runner = new RunnerApp(config);
|
|
88
|
-
|
|
89
|
-
// Mock sendToOrchestrator to fail
|
|
90
|
-
runner.sendToOrchestrator = vi.fn().mockRejectedValue(new Error("Connection refused"));
|
|
91
|
-
|
|
92
|
-
await expect(runner.start()).rejects.toThrow("Connection refused");
|
|
93
|
-
expect(runner.sendToOrchestrator).toHaveBeenCalledTimes(1);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("should succeed on first attempt", async () => {
|
|
97
|
-
const config = { ...baseConfig, retryStrategy: "none" as const };
|
|
98
|
-
const runner = new RunnerApp(config);
|
|
99
|
-
|
|
100
|
-
// Mock successful registration
|
|
101
|
-
runner.sendToOrchestrator = vi.fn().mockResolvedValue({
|
|
102
|
-
jsonrpc: "2.0",
|
|
103
|
-
result: {
|
|
104
|
-
success: true,
|
|
105
|
-
runnerId: "runner-123"
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await runner.start();
|
|
110
|
-
expect(runner.getRunnerId()).toBe("runner-123");
|
|
111
|
-
expect(runner.sendToOrchestrator).toHaveBeenCalledTimes(1);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe("Interval Retry Strategy", () => {
|
|
116
|
-
|
|
117
|
-
it("should retry at fixed intervals until success", async () => {
|
|
118
|
-
const config = {
|
|
119
|
-
...baseConfig,
|
|
120
|
-
retryStrategy: "interval" as const,
|
|
121
|
-
retryIntervalSecs: 2, // 2 seconds for testing
|
|
122
|
-
};
|
|
123
|
-
const runner = new RunnerApp(config);
|
|
124
|
-
|
|
125
|
-
// Mock delay function to resolve immediately
|
|
126
|
-
let delayCallCount = 0;
|
|
127
|
-
runner.setDelayFunction(async (ms: number) => {
|
|
128
|
-
delayCallCount++;
|
|
129
|
-
expect(ms).toBe(2000); // Should always be 2 seconds
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// Mock: fail 2 times, then succeed
|
|
133
|
-
const mock = vi.fn()
|
|
134
|
-
.mockRejectedValueOnce(new Error("Connection refused"))
|
|
135
|
-
.mockRejectedValueOnce(new Error("Server error"))
|
|
136
|
-
.mockResolvedValueOnce({
|
|
137
|
-
jsonrpc: "2.0",
|
|
138
|
-
result: {
|
|
139
|
-
success: true,
|
|
140
|
-
runnerId: "runner-456"
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
runner.sendToOrchestrator = mock;
|
|
144
|
-
|
|
145
|
-
await runner.start();
|
|
146
|
-
|
|
147
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
|
148
|
-
expect(delayCallCount).toBe(2); // Two delays between three attempts
|
|
149
|
-
expect(runner.getRunnerId()).toBe("runner-456");
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it("should keep retrying indefinitely with interval strategy", async () => {
|
|
153
|
-
const config = {
|
|
154
|
-
...baseConfig,
|
|
155
|
-
retryStrategy: "interval" as const,
|
|
156
|
-
retryIntervalSecs: 1,
|
|
157
|
-
};
|
|
158
|
-
const runner = new RunnerApp(config);
|
|
159
|
-
|
|
160
|
-
// Track attempts
|
|
161
|
-
let attemptCount = 0;
|
|
162
|
-
const mock = vi.fn().mockImplementation(() => {
|
|
163
|
-
attemptCount++;
|
|
164
|
-
if (attemptCount <= 10) {
|
|
165
|
-
return Promise.reject(new Error("Connection refused"));
|
|
166
|
-
}
|
|
167
|
-
return Promise.resolve({
|
|
168
|
-
jsonrpc: "2.0",
|
|
169
|
-
result: { success: true, runnerId: "runner-stopped" }
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
runner.sendToOrchestrator = mock;
|
|
173
|
-
|
|
174
|
-
// Mock delay to resolve immediately but track calls
|
|
175
|
-
let delayCallCount = 0;
|
|
176
|
-
runner.setDelayFunction(async (ms: number) => {
|
|
177
|
-
delayCallCount++;
|
|
178
|
-
expect(ms).toBe(1000);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
await runner.start();
|
|
182
|
-
|
|
183
|
-
expect(mock).toHaveBeenCalledTimes(11); // Initial + 10 retries
|
|
184
|
-
expect(delayCallCount).toBe(10);
|
|
185
|
-
await runner.stop();
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
describe("Exponential Retry Strategy", () => {
|
|
190
|
-
|
|
191
|
-
it("should retry with exponential backoff", async () => {
|
|
192
|
-
const config = {
|
|
193
|
-
...baseConfig,
|
|
194
|
-
retryStrategy: "exponential" as const,
|
|
195
|
-
retryDurationSecs: 120, // 2 minutes for testing
|
|
196
|
-
};
|
|
197
|
-
const runner = new RunnerApp(config);
|
|
198
|
-
|
|
199
|
-
// Track delay calls
|
|
200
|
-
const delayCalls: number[] = [];
|
|
201
|
-
runner.setDelayFunction(async (ms: number) => {
|
|
202
|
-
delayCalls.push(ms);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Mock: fail 3 times, then succeed
|
|
206
|
-
const mock = vi.fn()
|
|
207
|
-
.mockRejectedValueOnce(new Error("Error 1"))
|
|
208
|
-
.mockRejectedValueOnce(new Error("Error 2"))
|
|
209
|
-
.mockRejectedValueOnce(new Error("Error 3"))
|
|
210
|
-
.mockResolvedValueOnce({
|
|
211
|
-
jsonrpc: "2.0",
|
|
212
|
-
result: {
|
|
213
|
-
success: true,
|
|
214
|
-
runnerId: "runner-789"
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
runner.sendToOrchestrator = mock;
|
|
218
|
-
|
|
219
|
-
await runner.start();
|
|
220
|
-
|
|
221
|
-
expect(mock).toHaveBeenCalledTimes(4);
|
|
222
|
-
expect(delayCalls).toEqual([8000, 16000, 32000]); // Exponential backoff
|
|
223
|
-
expect(runner.getRunnerId()).toBe("runner-789");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it("should stop retrying after max duration", async () => {
|
|
227
|
-
const config = {
|
|
228
|
-
...baseConfig,
|
|
229
|
-
retryStrategy: "exponential" as const,
|
|
230
|
-
retryDurationSecs: 30, // 30 seconds max
|
|
231
|
-
};
|
|
232
|
-
const runner = new RunnerApp(config);
|
|
233
|
-
|
|
234
|
-
// Mock Date.now() for precise time control
|
|
235
|
-
let currentTime = 0;
|
|
236
|
-
vi.spyOn(Date, 'now').mockImplementation(() => currentTime);
|
|
237
|
-
|
|
238
|
-
// Track delay calls
|
|
239
|
-
const delayCalls: number[] = [];
|
|
240
|
-
runner.setDelayFunction(async (ms: number) => {
|
|
241
|
-
delayCalls.push(ms);
|
|
242
|
-
currentTime += ms;
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// Always fail
|
|
246
|
-
runner.sendToOrchestrator = vi.fn().mockRejectedValue(new Error("Connection refused"));
|
|
247
|
-
|
|
248
|
-
await expect(runner.start()).rejects.toThrow("Failed to register after 30 seconds");
|
|
249
|
-
|
|
250
|
-
// Should have attempted: immediate, +8s, +16s, then final at 30s
|
|
251
|
-
expect(runner.sendToOrchestrator).toHaveBeenCalledTimes(4);
|
|
252
|
-
expect(delayCalls).toEqual([8000, 16000, 6000]); // Last delay is 6s to reach 30s total
|
|
253
|
-
|
|
254
|
-
vi.spyOn(Date, 'now').mockRestore();
|
|
255
|
-
await runner.stop();
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it("should handle final retry at max duration", async () => {
|
|
259
|
-
const config = {
|
|
260
|
-
...baseConfig,
|
|
261
|
-
retryStrategy: "exponential" as const,
|
|
262
|
-
retryDurationSecs: 60, // 1 minute
|
|
263
|
-
};
|
|
264
|
-
const runner = new RunnerApp(config);
|
|
265
|
-
|
|
266
|
-
// Mock Date.now() for precise time control
|
|
267
|
-
let currentTime = 0;
|
|
268
|
-
vi.spyOn(Date, 'now').mockImplementation(() => currentTime);
|
|
269
|
-
|
|
270
|
-
// Track delay calls
|
|
271
|
-
const delayCalls: number[] = [];
|
|
272
|
-
runner.setDelayFunction(async (ms: number) => {
|
|
273
|
-
delayCalls.push(ms);
|
|
274
|
-
currentTime += ms;
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// Fail until the final retry
|
|
278
|
-
let callCount = 0;
|
|
279
|
-
runner.sendToOrchestrator = vi.fn().mockImplementation(() => {
|
|
280
|
-
callCount++;
|
|
281
|
-
if (callCount < 4) {
|
|
282
|
-
return Promise.reject(new Error("Still failing"));
|
|
283
|
-
}
|
|
284
|
-
return Promise.resolve({
|
|
285
|
-
jsonrpc: "2.0",
|
|
286
|
-
result: {
|
|
287
|
-
success: true,
|
|
288
|
-
runnerId: "runner-final"
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
await runner.start();
|
|
294
|
-
|
|
295
|
-
expect(runner.sendToOrchestrator).toHaveBeenCalledTimes(4);
|
|
296
|
-
// First delay is 8s, second is 16s, third would be 32s but gets limited to remaining time
|
|
297
|
-
// After 8+16=24s, only 36s remain to 60s total, but next delay would be 32s, so it's min(32, 36) = 32
|
|
298
|
-
expect(delayCalls).toEqual([8000, 16000, 32000]);
|
|
299
|
-
expect(runner.getRunnerId()).toBe("runner-final");
|
|
300
|
-
|
|
301
|
-
vi.spyOn(Date, 'now').mockRestore();
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
describe("Registration Response Handling", () => {
|
|
306
|
-
it("should handle missing runnerId in response", async () => {
|
|
307
|
-
const config = { ...baseConfig, retryStrategy: "none" as const };
|
|
308
|
-
const runner = new RunnerApp(config);
|
|
309
|
-
|
|
310
|
-
// Mock response without runnerId
|
|
311
|
-
runner.sendToOrchestrator = vi.fn().mockResolvedValue({
|
|
312
|
-
jsonrpc: "2.0",
|
|
313
|
-
result: {
|
|
314
|
-
success: true
|
|
315
|
-
} // Missing runnerId
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
await expect(runner.start()).rejects.toThrow("Registration response did not include runnerId");
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("should store runnerId from successful registration", async () => {
|
|
322
|
-
const config = { ...baseConfig, retryStrategy: "none" as const };
|
|
323
|
-
const runner = new RunnerApp(config);
|
|
324
|
-
|
|
325
|
-
runner.sendToOrchestrator = vi.fn().mockResolvedValue({
|
|
326
|
-
jsonrpc: "2.0",
|
|
327
|
-
result: {
|
|
328
|
-
success: true,
|
|
329
|
-
runnerId: "runner-abc-123"
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
await runner.start();
|
|
334
|
-
expect(runner.getRunnerId()).toBe("runner-abc-123");
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("Heartbeat Behavior", () => {
|
|
339
|
-
|
|
340
|
-
it("should not start heartbeat if registration fails", async () => {
|
|
341
|
-
vi.useFakeTimers();
|
|
342
|
-
|
|
343
|
-
const config = {
|
|
344
|
-
...baseConfig,
|
|
345
|
-
retryStrategy: "none" as const,
|
|
346
|
-
heartbeatInterval: 5000,
|
|
347
|
-
};
|
|
348
|
-
const runner = new RunnerApp(config);
|
|
349
|
-
|
|
350
|
-
// Mock failed registration
|
|
351
|
-
const mock = vi.fn().mockRejectedValue(new Error("Registration failed"));
|
|
352
|
-
runner.sendToOrchestrator = mock;
|
|
353
|
-
|
|
354
|
-
await expect(runner.start()).rejects.toThrow("Registration failed");
|
|
355
|
-
|
|
356
|
-
// Advance time to check if heartbeat was started
|
|
357
|
-
await vi.advanceTimersByTimeAsync(10000);
|
|
358
|
-
|
|
359
|
-
// Should only have the registration attempt, no heartbeat calls
|
|
360
|
-
expect(mock).toHaveBeenCalledTimes(1);
|
|
361
|
-
|
|
362
|
-
vi.useRealTimers();
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
it("should start heartbeat after successful registration", async () => {
|
|
366
|
-
vi.useFakeTimers();
|
|
367
|
-
|
|
368
|
-
const config = {
|
|
369
|
-
...baseConfig,
|
|
370
|
-
retryStrategy: "none" as const,
|
|
371
|
-
heartbeatInterval: 5000,
|
|
372
|
-
};
|
|
373
|
-
const runner = new RunnerApp(config);
|
|
374
|
-
|
|
375
|
-
// Mock successful registration and heartbeat
|
|
376
|
-
const mock = vi.fn()
|
|
377
|
-
.mockResolvedValueOnce({
|
|
378
|
-
jsonrpc: "2.0",
|
|
379
|
-
result: {
|
|
380
|
-
success: true,
|
|
381
|
-
runnerId: "runner-heartbeat"
|
|
382
|
-
}
|
|
383
|
-
})
|
|
384
|
-
.mockResolvedValue({
|
|
385
|
-
jsonrpc: "2.0",
|
|
386
|
-
result: {
|
|
387
|
-
success: true
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
runner.sendToOrchestrator = mock;
|
|
391
|
-
|
|
392
|
-
await runner.start();
|
|
393
|
-
|
|
394
|
-
// Initial registration call
|
|
395
|
-
expect(mock).toHaveBeenCalledTimes(1);
|
|
396
|
-
|
|
397
|
-
// Advance time for heartbeat
|
|
398
|
-
await vi.advanceTimersByTimeAsync(5000);
|
|
399
|
-
expect(mock).toHaveBeenCalledTimes(2);
|
|
400
|
-
|
|
401
|
-
// Check heartbeat was called with correct params
|
|
402
|
-
const heartbeatCall = mock.mock.calls[1];
|
|
403
|
-
expect(heartbeatCall![0].method).toBe("runner.heartbeat");
|
|
404
|
-
expect(heartbeatCall![0].params.runnerId).toBe("runner-heartbeat");
|
|
405
|
-
|
|
406
|
-
await runner.stop();
|
|
407
|
-
vi.useRealTimers();
|
|
408
|
-
});
|
|
409
|
-
});
|
|
410
|
-
});
|