@harperfast/integration-testing 0.5.0 → 0.5.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/harperLifecycle.d.ts +262 -0
- package/dist/harperLifecycle.js +594 -0
- package/dist/harperLifecycle.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/loopbackAddressPool.d.ts +50 -0
- package/dist/loopbackAddressPool.js +421 -0
- package/dist/loopbackAddressPool.js.map +1 -0
- package/dist/portUtils.d.ts +26 -0
- package/dist/portUtils.js +47 -0
- package/dist/portUtils.js.map +1 -0
- package/dist/run.d.ts +2 -0
- package/dist/run.js +178 -0
- package/dist/run.js.map +1 -0
- package/dist/targz.d.ts +6 -0
- package/dist/targz.js +19 -0
- package/dist/targz.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import { spawn, ChildProcess } from 'node:child_process';
|
|
2
|
+
import { createWriteStream, existsSync } from 'node:fs';
|
|
3
|
+
import { join, basename, dirname } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { mkdtemp, mkdir, rm, cp } from 'node:fs/promises';
|
|
6
|
+
import {} from 'node:test';
|
|
7
|
+
import { getNextAvailableLoopbackAddress, releaseLoopbackAddress } from "./loopbackAddressPool.js";
|
|
8
|
+
import { waitForPortsFree } from "./portUtils.js";
|
|
9
|
+
import { ok, equal } from 'node:assert';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
/**
|
|
12
|
+
* Creates a plain object satisfying HarperTestContext, for use outside node:test
|
|
13
|
+
* (e.g. as a Playwright worker fixture).
|
|
14
|
+
*
|
|
15
|
+
* @param name Optional name for log directory naming (e.g. Playwright worker index).
|
|
16
|
+
*/
|
|
17
|
+
export function createHarperContext(name) {
|
|
18
|
+
return { name };
|
|
19
|
+
}
|
|
20
|
+
// Constants
|
|
21
|
+
const HTTP_PORT = 9926;
|
|
22
|
+
const HTTPS_PORT = 9927;
|
|
23
|
+
const MQTT_PORT = 1883;
|
|
24
|
+
const MQTTS_PORT = 8883;
|
|
25
|
+
export const OPERATIONS_API_PORT = 9925;
|
|
26
|
+
export const DEFAULT_ADMIN_USERNAME = 'admin';
|
|
27
|
+
export const DEFAULT_ADMIN_PASSWORD = 'Abc1234!';
|
|
28
|
+
/** Every fixed port a Harper test instance may bind, all on its assigned loopback address. */
|
|
29
|
+
const ALL_HARPER_PORTS = [OPERATIONS_API_PORT, HTTP_PORT, HTTPS_PORT, MQTT_PORT, MQTTS_PORT];
|
|
30
|
+
/** Whether we appear to be running in CI (most CI providers set CI=true). */
|
|
31
|
+
const IS_CI = !!process.env.CI;
|
|
32
|
+
/**
|
|
33
|
+
* Maximum time to wait between chunks of Harper startup output before treating the process
|
|
34
|
+
* as hung. The startup watchdog resets this window on every chunk of output, so the limit is
|
|
35
|
+
* time-since-last-progress rather than total boot time: a slow-but-healthy boot that keeps
|
|
36
|
+
* logging never trips it — only true silence does.
|
|
37
|
+
*
|
|
38
|
+
* Override with `HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS`. Default 60s.
|
|
39
|
+
*/
|
|
40
|
+
export const DEFAULT_STARTUP_TIMEOUT_MS = parseInt(process.env.HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS || '', 10) || 60000;
|
|
41
|
+
/**
|
|
42
|
+
* Absolute ceiling on total startup time, regardless of ongoing output — a generous backstop
|
|
43
|
+
* so a process that chatters forever without ever reporting ready still fails. Higher under CI,
|
|
44
|
+
* where shared/contended runners boot more slowly.
|
|
45
|
+
*
|
|
46
|
+
* Override with `HARPER_INTEGRATION_TEST_STARTUP_MAX_MS`. Default 120s (300s under CI).
|
|
47
|
+
*/
|
|
48
|
+
export const DEFAULT_STARTUP_MAX_MS = parseInt(process.env.HARPER_INTEGRATION_TEST_STARTUP_MAX_MS || '', 10) || (IS_CI ? 300000 : 120000);
|
|
49
|
+
/**
|
|
50
|
+
* Grace period after SIGTERM before escalating to SIGKILL during teardown, giving Harper time
|
|
51
|
+
* to shut down cleanly (flush RocksDB, release ports, reap worker children).
|
|
52
|
+
*
|
|
53
|
+
* Override with `HARPER_INTEGRATION_TEST_TEARDOWN_GRACE_MS`. Default 5s.
|
|
54
|
+
*/
|
|
55
|
+
export const DEFAULT_TEARDOWN_GRACE_MS = parseInt(process.env.HARPER_INTEGRATION_TEST_TEARDOWN_GRACE_MS || '', 10) || 5000;
|
|
56
|
+
/**
|
|
57
|
+
* Time teardown's safety assertion waits for Harper's fixed ports to be free before recycling the
|
|
58
|
+
* loopback address. Killing Harper's process tree (and waiting for exit) should free them
|
|
59
|
+
* immediately, so this normally returns on the first check; it only matters if a child process
|
|
60
|
+
* escaped the kill. If the ports are still in use at the deadline, the address is recycled anyway
|
|
61
|
+
* (no worse than not waiting) and a warning is logged.
|
|
62
|
+
*
|
|
63
|
+
* Override with `HARPER_INTEGRATION_TEST_PORT_RELEASE_TIMEOUT_MS`. Default 5s.
|
|
64
|
+
*/
|
|
65
|
+
export const DEFAULT_PORT_RELEASE_TIMEOUT_MS = parseInt(process.env.HARPER_INTEGRATION_TEST_PORT_RELEASE_TIMEOUT_MS || '', 10) || 5000;
|
|
66
|
+
/** Short backstop wait for the process 'exit' event after sending SIGKILL during teardown. */
|
|
67
|
+
const SIGKILL_EXIT_WAIT_MS = 1000;
|
|
68
|
+
/**
|
|
69
|
+
* The runtime to use for running Harper during tests.
|
|
70
|
+
* Set via the HARPER_RUNTIME environment variable ('node' or 'bun').
|
|
71
|
+
* Defaults to 'node'.
|
|
72
|
+
*/
|
|
73
|
+
export const HARPER_RUNTIME = process.env.HARPER_RUNTIME || 'node';
|
|
74
|
+
/**
|
|
75
|
+
* Marker emitted on stdout by startHarper() so the test runner (run.ts) can map
|
|
76
|
+
* a Harper instance's log directory to the currently executing test file via
|
|
77
|
+
* the node:test `test:stdout` event.
|
|
78
|
+
*/
|
|
79
|
+
export const LOG_DIR_MARKER_PREFIX = '[Harper] Logs for this instance will be stored in:';
|
|
80
|
+
/**
|
|
81
|
+
* Gets the path to the Harper CLI script.
|
|
82
|
+
*
|
|
83
|
+
* Resolution order:
|
|
84
|
+
* 1. `harperBinPath` argument
|
|
85
|
+
* 2. `HARPER_INTEGRATION_TEST_INSTALL_SCRIPT` environment variable
|
|
86
|
+
* 3. Auto-resolved from 'harper' package in node_modules
|
|
87
|
+
* 4. Auto-resolved from current directory or ancestors ('dist/bin/harper.js')
|
|
88
|
+
*
|
|
89
|
+
* @returns The absolute path to the Harper CLI entry script
|
|
90
|
+
* @throws {AssertionError} If the script cannot be found
|
|
91
|
+
*/
|
|
92
|
+
function getHarperScript(harperBinPath) {
|
|
93
|
+
// 1. Explicit option
|
|
94
|
+
if (harperBinPath) {
|
|
95
|
+
ok(existsSync(harperBinPath), `Harper script not found at provided harperBinPath: ${harperBinPath}`);
|
|
96
|
+
return harperBinPath;
|
|
97
|
+
}
|
|
98
|
+
// 2. Environment variable
|
|
99
|
+
const envPath = process.env.HARPER_INTEGRATION_TEST_INSTALL_SCRIPT;
|
|
100
|
+
if (envPath) {
|
|
101
|
+
ok(existsSync(envPath), `Harper script not found at HARPER_INTEGRATION_TEST_INSTALL_SCRIPT path: ${envPath}`);
|
|
102
|
+
return envPath;
|
|
103
|
+
}
|
|
104
|
+
// 3. Auto-resolve from node_modules
|
|
105
|
+
try {
|
|
106
|
+
const require = createRequire(import.meta.url);
|
|
107
|
+
const resolved = require.resolve('harper/dist/bin/harper.js');
|
|
108
|
+
if (existsSync(resolved)) {
|
|
109
|
+
return resolved;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// harper package not found in node_modules
|
|
114
|
+
}
|
|
115
|
+
// 4. Auto-resolve from current directory or ancestors
|
|
116
|
+
let currentDir = process.cwd();
|
|
117
|
+
while (true) {
|
|
118
|
+
const potentialPath = join(currentDir, 'dist/bin/harper.js');
|
|
119
|
+
if (existsSync(potentialPath)) {
|
|
120
|
+
return potentialPath;
|
|
121
|
+
}
|
|
122
|
+
const parentDir = dirname(currentDir);
|
|
123
|
+
if (parentDir === currentDir) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
currentDir = parentDir;
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`Harper CLI script not found. Provide the path via:\n` +
|
|
129
|
+
` - harperBinPath option: startHarper(ctx, { harperBinPath: '/path/to/dist/bin/harper.js' })\n` +
|
|
130
|
+
` - HARPER_INTEGRATION_TEST_INSTALL_SCRIPT environment variable\n` +
|
|
131
|
+
` - Install 'harper' as a dependency in your project\n` +
|
|
132
|
+
` - Run tests within a directory containing 'dist/bin/harper.js'`);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Strips ANSI escape sequences (colors, bold, underline, cursor movement, etc.) from a string.
|
|
136
|
+
*/
|
|
137
|
+
// eslint-disable-next-line no-control-regex
|
|
138
|
+
const ANSI_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nq-uy=><~]/g;
|
|
139
|
+
function stripAnsi(str) {
|
|
140
|
+
return str.replace(ANSI_REGEX, '');
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sanitizes a string for use as a filesystem directory name.
|
|
144
|
+
*/
|
|
145
|
+
function sanitizeForFilesystem(name) {
|
|
146
|
+
return name
|
|
147
|
+
.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
148
|
+
.replace(/_+/g, '_')
|
|
149
|
+
.substring(0, 100);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Error thrown when a Harper process fails to start or times out.
|
|
153
|
+
* Includes captured stdout and stderr for diagnostics.
|
|
154
|
+
*/
|
|
155
|
+
export class HarperStartupError extends Error {
|
|
156
|
+
stdout;
|
|
157
|
+
stderr;
|
|
158
|
+
constructor(message, stdout, stderr) {
|
|
159
|
+
let fullMessage = message;
|
|
160
|
+
if (stdout) {
|
|
161
|
+
fullMessage += `\n\nstdout:\n${stdout}`;
|
|
162
|
+
}
|
|
163
|
+
if (stderr) {
|
|
164
|
+
fullMessage += `\n\nstderr:\n${stderr}`;
|
|
165
|
+
}
|
|
166
|
+
super(fullMessage);
|
|
167
|
+
this.name = 'HarperStartupError';
|
|
168
|
+
this.stdout = stdout;
|
|
169
|
+
this.stderr = stderr;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Runs a Harper CLI command and captures output.
|
|
174
|
+
*
|
|
175
|
+
* When `logDir` is provided, stdout and stderr are also written to files
|
|
176
|
+
* (`stdout.log` and `stderr.log`) in that directory.
|
|
177
|
+
*
|
|
178
|
+
* @throws {HarperStartupError} If the command times out or exits with a non-zero status code
|
|
179
|
+
*
|
|
180
|
+
* Exported for unit testing; not part of the public API (not re-exported from `index.ts`).
|
|
181
|
+
*/
|
|
182
|
+
export function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath, timeoutMs, maxMs, }) {
|
|
183
|
+
const harperScript = getHarperScript(harperBinPath);
|
|
184
|
+
const runtime = HARPER_RUNTIME;
|
|
185
|
+
const runtimeArgs = runtime === 'bun'
|
|
186
|
+
? [harperScript, ...args]
|
|
187
|
+
: ['--trace-warnings', '--force-node-api-uncaught-exceptions-policy=true', harperScript, ...args];
|
|
188
|
+
const proc = spawn(runtime, runtimeArgs, {
|
|
189
|
+
env: { ...process.env, ...env },
|
|
190
|
+
// On POSIX, run Harper as its own process-group leader so teardown can signal the whole
|
|
191
|
+
// group (parent + any worker children), not just the direct child. Windows has no process
|
|
192
|
+
// groups; killHarper uses `taskkill /T` there instead. stdio stays piped (not detached),
|
|
193
|
+
// and we never unref, so output capture and lifetime management are unchanged.
|
|
194
|
+
detached: process.platform !== 'win32',
|
|
195
|
+
});
|
|
196
|
+
// Reap this process's tree if the runner exits/is interrupted before teardown (it's detached,
|
|
197
|
+
// so it would otherwise survive signals sent to the runner's group).
|
|
198
|
+
trackHarperProcess(proc);
|
|
199
|
+
let stdoutStream;
|
|
200
|
+
let stderrStream;
|
|
201
|
+
if (logDir) {
|
|
202
|
+
stdoutStream = createWriteStream(join(logDir, 'stdout.log'));
|
|
203
|
+
stderrStream = createWriteStream(join(logDir, 'stderr.log'));
|
|
204
|
+
}
|
|
205
|
+
const idleTimeoutMs = timeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
206
|
+
const maxTimeoutMs = maxMs ?? DEFAULT_STARTUP_MAX_MS;
|
|
207
|
+
return new Promise((resolve, reject) => {
|
|
208
|
+
let stdout = '';
|
|
209
|
+
let stderr = '';
|
|
210
|
+
let settled = false;
|
|
211
|
+
let idleTimer;
|
|
212
|
+
let maxTimer;
|
|
213
|
+
const clearTimers = () => {
|
|
214
|
+
clearTimeout(idleTimer);
|
|
215
|
+
clearTimeout(maxTimer);
|
|
216
|
+
};
|
|
217
|
+
const failStartup = (message) => {
|
|
218
|
+
if (settled)
|
|
219
|
+
return;
|
|
220
|
+
settled = true;
|
|
221
|
+
clearTimers();
|
|
222
|
+
reject(new HarperStartupError(message, stdout, stderr));
|
|
223
|
+
// Harper is spawned detached (its own process group), so `proc.kill()` would only hit the
|
|
224
|
+
// direct child and orphan any worker children still holding ports. Reap the whole tree.
|
|
225
|
+
signalHarperTree(proc, 'SIGKILL');
|
|
226
|
+
};
|
|
227
|
+
const succeed = () => {
|
|
228
|
+
if (settled)
|
|
229
|
+
return;
|
|
230
|
+
settled = true;
|
|
231
|
+
clearTimers();
|
|
232
|
+
resolve({ process: proc, stdout, stderr });
|
|
233
|
+
};
|
|
234
|
+
// Reset on every chunk of output so the limit is time-since-last-progress, not total boot
|
|
235
|
+
// time: a slow-but-healthy boot that keeps logging never trips it, only true silence does.
|
|
236
|
+
const resetIdleTimer = () => {
|
|
237
|
+
if (settled)
|
|
238
|
+
return;
|
|
239
|
+
clearTimeout(idleTimer);
|
|
240
|
+
idleTimer = setTimeout(() => failStartup(`Harper produced no startup output for ${idleTimeoutMs}ms before reporting ready (likely hung)`), idleTimeoutMs);
|
|
241
|
+
};
|
|
242
|
+
// Absolute backstop, regardless of ongoing output.
|
|
243
|
+
maxTimer = setTimeout(() => failStartup(`Harper did not report ready within the maximum startup time of ${maxTimeoutMs}ms`), maxTimeoutMs);
|
|
244
|
+
resetIdleTimer();
|
|
245
|
+
proc.stdout?.on('data', (data) => {
|
|
246
|
+
const dataString = stripAnsi(data.toString());
|
|
247
|
+
stdoutStream?.write(dataString);
|
|
248
|
+
// Once ready, keep streaming logs to disk but stop the watchdog and capture: the
|
|
249
|
+
// returned startupOutput is a snapshot taken at readiness, and the server may run
|
|
250
|
+
// (and log) for the rest of the suite.
|
|
251
|
+
if (settled)
|
|
252
|
+
return;
|
|
253
|
+
resetIdleTimer();
|
|
254
|
+
stdout += dataString;
|
|
255
|
+
// Match against the accumulated output, not just this chunk, so a marker split across
|
|
256
|
+
// two stream chunks is still detected.
|
|
257
|
+
if (completionMessage && stdout.includes(completionMessage)) {
|
|
258
|
+
succeed();
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
proc.stderr?.on('data', (data) => {
|
|
262
|
+
const dataString = stripAnsi(data.toString());
|
|
263
|
+
stderrStream?.write(dataString);
|
|
264
|
+
if (settled)
|
|
265
|
+
return;
|
|
266
|
+
resetIdleTimer();
|
|
267
|
+
stderr += dataString;
|
|
268
|
+
});
|
|
269
|
+
proc.on('error', (error) => {
|
|
270
|
+
if (settled)
|
|
271
|
+
return;
|
|
272
|
+
settled = true;
|
|
273
|
+
clearTimers();
|
|
274
|
+
// 'exit' won't fire for a failed spawn, so close the log streams here to avoid leaking FDs.
|
|
275
|
+
stdoutStream?.end();
|
|
276
|
+
stderrStream?.end();
|
|
277
|
+
reject(error);
|
|
278
|
+
});
|
|
279
|
+
proc.on('exit', (statusCode, signal) => {
|
|
280
|
+
clearTimers();
|
|
281
|
+
if (!settled) {
|
|
282
|
+
settled = true;
|
|
283
|
+
if (statusCode === 0) {
|
|
284
|
+
resolve({ process: proc, stdout, stderr });
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
const errorMessage = `Harper process failed with exit code/signal ${statusCode ?? signal}`;
|
|
288
|
+
stderrStream?.write(errorMessage);
|
|
289
|
+
reject(new HarperStartupError(errorMessage, stdout, stderr));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
stdoutStream?.end();
|
|
293
|
+
stderrStream?.end();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Sets up a Harper instance with a component pre-installed from a local directory.
|
|
299
|
+
*
|
|
300
|
+
* Copies `fixturePath` into `{dataRootDir}/components/{name}` before Harper starts,
|
|
301
|
+
* so the component is available on the first request without a post-startup deploy.
|
|
302
|
+
* Use this when tests need a known route available at startup (e.g. mTLS cert tests).
|
|
303
|
+
*
|
|
304
|
+
* @param ctx - The test context to populate with Harper instance details
|
|
305
|
+
* @param fixturePath - Absolute path to the component directory to pre-install
|
|
306
|
+
* @param options - Optional configuration for the setup process
|
|
307
|
+
*/
|
|
308
|
+
export async function setupHarperWithFixture(ctx, fixturePath, options) {
|
|
309
|
+
const dataRootDirPrefix = join(process.env.HARPER_INTEGRATION_TEST_INSTALL_PARENT_DIR || tmpdir(), 'harper-integration-test-');
|
|
310
|
+
const dataRootDir = await mkdtemp(dataRootDirPrefix);
|
|
311
|
+
await cp(fixturePath, join(dataRootDir, 'components', basename(fixturePath)), { recursive: true, dereference: true });
|
|
312
|
+
ctx.harper = { dataRootDir };
|
|
313
|
+
return startHarper(ctx, options);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Sets up and starts a Harper instance for testing.
|
|
317
|
+
*
|
|
318
|
+
* @param ctx - The test context to populate with Harper instance details
|
|
319
|
+
* @param options - Optional configuration for the setup process
|
|
320
|
+
* @returns The context with the `harper` property populated
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```ts
|
|
324
|
+
* suite('My tests', (ctx: ContextWithHarper) => {
|
|
325
|
+
* before(async () => {
|
|
326
|
+
* await startHarper(ctx);
|
|
327
|
+
* });
|
|
328
|
+
*
|
|
329
|
+
* after(async () => {
|
|
330
|
+
* await teardownHarper(ctx);
|
|
331
|
+
* });
|
|
332
|
+
*
|
|
333
|
+
* test('can connect', async () => {
|
|
334
|
+
* const response = await fetch(ctx.harper.httpURL);
|
|
335
|
+
* // ...
|
|
336
|
+
* });
|
|
337
|
+
* });
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
export async function startHarper(ctx, options) {
|
|
341
|
+
const dataRootDirPrefix = join(process.env.HARPER_INTEGRATION_TEST_INSTALL_PARENT_DIR || tmpdir(), `harper-integration-test-`);
|
|
342
|
+
const dataRootDir = ctx.harper?.dataRootDir ?? (await mkdtemp(dataRootDirPrefix));
|
|
343
|
+
const loopbackAddress = ctx.harper?.hostname ?? (await getNextAvailableLoopbackAddress());
|
|
344
|
+
// Set up per-suite log directory when HARPER_INTEGRATION_TEST_LOG_DIR is configured
|
|
345
|
+
const logDirEnv = process.env.HARPER_INTEGRATION_TEST_LOG_DIR;
|
|
346
|
+
let logDir;
|
|
347
|
+
if (logDirEnv) {
|
|
348
|
+
const suiteName = sanitizeForFilesystem(ctx.name || 'unknown');
|
|
349
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
350
|
+
logDir = join(logDirEnv, `${suiteName}-${sanitizeForFilesystem(loopbackAddress)}-${timestamp}`);
|
|
351
|
+
await mkdir(logDir, { recursive: true });
|
|
352
|
+
// Output for the test runner (e.g. run.ts) to map this log dir to the current test file
|
|
353
|
+
process.stdout.write(`${LOG_DIR_MARKER_PREFIX} ${logDir}\n`);
|
|
354
|
+
}
|
|
355
|
+
// Point Harper's log directory to the suite log dir so hdb.log is preserved for upload
|
|
356
|
+
const config = { ...options?.config };
|
|
357
|
+
if (logDir) {
|
|
358
|
+
config.logging = { ...config.logging, root: logDir };
|
|
359
|
+
}
|
|
360
|
+
const args = [
|
|
361
|
+
`--ROOTPATH=${dataRootDir}`,
|
|
362
|
+
`--AUTHENTICATION_AUTHORIZELOCAL=true`,
|
|
363
|
+
`--HDB_ADMIN_USERNAME=${DEFAULT_ADMIN_USERNAME}`,
|
|
364
|
+
`--HDB_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD}`,
|
|
365
|
+
'--THREADS_COUNT=1',
|
|
366
|
+
'--THREADS_DEBUG=false',
|
|
367
|
+
`--NODE_HOSTNAME=${loopbackAddress}`,
|
|
368
|
+
`--HTTP_PORT=${loopbackAddress}:${HTTP_PORT}`,
|
|
369
|
+
`--OPERATIONSAPI_NETWORK_PORT=${loopbackAddress}:${OPERATIONS_API_PORT}`,
|
|
370
|
+
`--MQTT_NETWORK_PORT=${loopbackAddress}:${MQTT_PORT}`,
|
|
371
|
+
`--MQTT_NETWORK_SECUREPORT=${loopbackAddress}:${MQTTS_PORT}`,
|
|
372
|
+
'--LOGGING_LEVEL=debug',
|
|
373
|
+
'--LOGGING_STDSTREAMS=false',
|
|
374
|
+
];
|
|
375
|
+
// Bind secure port if HTTPS is needed (mTLS or other TLS config present)
|
|
376
|
+
if (options?.config?.http?.mtls !== undefined || options?.config?.tls !== undefined) {
|
|
377
|
+
args.push(`--HTTP_SECUREPORT=${loopbackAddress}:${HTTPS_PORT}`);
|
|
378
|
+
}
|
|
379
|
+
// HARPER_SET_CONFIG must be passed as an environment variable, not a CLI arg,
|
|
380
|
+
// because applyRuntimeEnvVarConfig reads from process.env.HARPER_SET_CONFIG
|
|
381
|
+
const harperEnv = {
|
|
382
|
+
HARPER_SET_CONFIG: JSON.stringify(config),
|
|
383
|
+
...options?.env,
|
|
384
|
+
};
|
|
385
|
+
const result = await runHarperCommand({
|
|
386
|
+
args,
|
|
387
|
+
env: harperEnv,
|
|
388
|
+
completionMessage: 'successfully started',
|
|
389
|
+
logDir,
|
|
390
|
+
harperBinPath: options?.harperBinPath,
|
|
391
|
+
timeoutMs: options?.startupTimeoutMs,
|
|
392
|
+
maxMs: options?.startupMaxMs,
|
|
393
|
+
});
|
|
394
|
+
ctx.harper = {
|
|
395
|
+
dataRootDir,
|
|
396
|
+
admin: {
|
|
397
|
+
username: DEFAULT_ADMIN_USERNAME,
|
|
398
|
+
password: DEFAULT_ADMIN_PASSWORD,
|
|
399
|
+
},
|
|
400
|
+
httpURL: `http://${loopbackAddress}:${HTTP_PORT}`,
|
|
401
|
+
operationsAPIURL: `http://${loopbackAddress}:${OPERATIONS_API_PORT}`,
|
|
402
|
+
hostname: loopbackAddress,
|
|
403
|
+
process: result.process,
|
|
404
|
+
logDir,
|
|
405
|
+
startupOutput: { stdout: result.stdout, stderr: result.stderr },
|
|
406
|
+
};
|
|
407
|
+
return ctx;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Signals Harper's entire process tree, not just the direct child.
|
|
411
|
+
*
|
|
412
|
+
* Harper runs its listeners in worker threads (in-process), but components can also spawn
|
|
413
|
+
* child processes, so we target the whole tree to be safe:
|
|
414
|
+
* - POSIX: Harper is spawned as its own process-group leader (`detached`), so a negative PID
|
|
415
|
+
* signals the group (parent + descendants).
|
|
416
|
+
* - Windows: there are no process groups, so we shell out to `taskkill /T` (tree). `/F` (force)
|
|
417
|
+
* is required to actually terminate console processes, so it is used for the SIGKILL step.
|
|
418
|
+
*
|
|
419
|
+
* Best-effort: errors (e.g. the process already exited) are swallowed; teardown's port assertion
|
|
420
|
+
* and the wait-for-exit are the safety nets.
|
|
421
|
+
*/
|
|
422
|
+
function signalHarperTree(proc, signal) {
|
|
423
|
+
const pid = proc.pid;
|
|
424
|
+
if (pid === undefined)
|
|
425
|
+
return;
|
|
426
|
+
if (process.platform === 'win32') {
|
|
427
|
+
const args = ['/pid', String(pid), '/T'];
|
|
428
|
+
if (signal === 'SIGKILL')
|
|
429
|
+
args.push('/F');
|
|
430
|
+
try {
|
|
431
|
+
spawn('taskkill', args, { stdio: 'ignore' }).on('error', () => { });
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
try {
|
|
435
|
+
proc.kill(signal);
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
// process already gone
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
// Negative PID => signal the whole process group (proc is the group leader via `detached`).
|
|
445
|
+
process.kill(-pid, signal);
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// Group already gone, or (defensively) not a group leader — fall back to the direct child.
|
|
449
|
+
try {
|
|
450
|
+
proc.kill(signal);
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
// process already gone
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Tracks live Harper processes so that if the test runner exits or is interrupted before teardown
|
|
459
|
+
* runs (Ctrl+C, or a CI job killing the runner), their process trees are reaped instead of left
|
|
460
|
+
* orphaned holding the fixed ports. This matters specifically because Harper is spawned `detached`
|
|
461
|
+
* (its own process group), so it would otherwise survive signals delivered to the runner's group.
|
|
462
|
+
*
|
|
463
|
+
* Best-effort: on POSIX the group SIGKILL is delivered synchronously (works even from the 'exit'
|
|
464
|
+
* handler); on Windows the `taskkill` shell-out may not complete before the runner exits.
|
|
465
|
+
*/
|
|
466
|
+
const liveHarperProcesses = new Set();
|
|
467
|
+
let runnerCleanupRegistered = false;
|
|
468
|
+
function trackHarperProcess(proc) {
|
|
469
|
+
liveHarperProcesses.add(proc);
|
|
470
|
+
proc.once('exit', () => liveHarperProcesses.delete(proc));
|
|
471
|
+
if (runnerCleanupRegistered)
|
|
472
|
+
return;
|
|
473
|
+
runnerCleanupRegistered = true;
|
|
474
|
+
const reapAll = () => {
|
|
475
|
+
for (const child of liveHarperProcesses)
|
|
476
|
+
signalHarperTree(child, 'SIGKILL');
|
|
477
|
+
};
|
|
478
|
+
process.once('exit', reapAll);
|
|
479
|
+
// SIGINT/SIGTERM don't fire 'exit'; reap, then re-raise so the runner still terminates normally.
|
|
480
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
481
|
+
process.once(signal, () => {
|
|
482
|
+
reapAll();
|
|
483
|
+
process.kill(process.pid, signal);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Kill harper process (can be used for teardown, or killing it before a restart).
|
|
489
|
+
*
|
|
490
|
+
* Sends SIGTERM to Harper's whole process tree first and gives it a grace period to shut down
|
|
491
|
+
* cleanly (flush RocksDB, release ports, reap worker children) before escalating to SIGKILL.
|
|
492
|
+
* After SIGKILL it waits briefly for the process to actually exit, so callers can rely on it
|
|
493
|
+
* being gone — and, since a dead process releases its listening sockets, on its ports being free.
|
|
494
|
+
*
|
|
495
|
+
* @param ctx
|
|
496
|
+
* @param options.graceMs Time to wait after SIGTERM before sending SIGKILL. Defaults to
|
|
497
|
+
* {@link DEFAULT_TEARDOWN_GRACE_MS}.
|
|
498
|
+
*/
|
|
499
|
+
export async function killHarper(ctx, options) {
|
|
500
|
+
const proc = ctx.harper?.process;
|
|
501
|
+
if (!proc)
|
|
502
|
+
return;
|
|
503
|
+
// Already exited — nothing to do.
|
|
504
|
+
if (proc.exitCode !== null || proc.signalCode !== null)
|
|
505
|
+
return;
|
|
506
|
+
const graceMs = options?.graceMs ?? DEFAULT_TEARDOWN_GRACE_MS;
|
|
507
|
+
await new Promise((resolve) => {
|
|
508
|
+
let done = false;
|
|
509
|
+
let sigkillTimer;
|
|
510
|
+
let backstopTimer;
|
|
511
|
+
const finish = () => {
|
|
512
|
+
if (done)
|
|
513
|
+
return;
|
|
514
|
+
done = true;
|
|
515
|
+
proc.off('exit', finish);
|
|
516
|
+
clearTimeout(sigkillTimer);
|
|
517
|
+
clearTimeout(backstopTimer);
|
|
518
|
+
resolve();
|
|
519
|
+
};
|
|
520
|
+
proc.once('exit', finish);
|
|
521
|
+
// Ask the whole Harper tree to shut down cleanly first.
|
|
522
|
+
signalHarperTree(proc, 'SIGTERM');
|
|
523
|
+
// If it hasn't exited within the grace period, force-kill the tree and wait briefly for the
|
|
524
|
+
// 'exit' event before resolving (with a backstop in case it never fires).
|
|
525
|
+
sigkillTimer = setTimeout(() => {
|
|
526
|
+
signalHarperTree(proc, 'SIGKILL');
|
|
527
|
+
backstopTimer = setTimeout(finish, SIGKILL_EXIT_WAIT_MS);
|
|
528
|
+
}, graceMs);
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Tears down a Harper instance and cleans up all resources.
|
|
533
|
+
*
|
|
534
|
+
* This function stops the Harper instance, releases the loopback address,
|
|
535
|
+
* and removes the installation directory.
|
|
536
|
+
* @param ctx - The test context with Harper instance details
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* ```ts
|
|
540
|
+
* suite('My tests', (ctx: ContextWithHarper) => {
|
|
541
|
+
* before(async () => {
|
|
542
|
+
* await startHarper(ctx);
|
|
543
|
+
* });
|
|
544
|
+
*
|
|
545
|
+
* after(async () => {
|
|
546
|
+
* await teardownHarper(ctx);
|
|
547
|
+
* });
|
|
548
|
+
* });
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
export async function teardownHarper(ctx) {
|
|
552
|
+
if (!ctx.harper)
|
|
553
|
+
return;
|
|
554
|
+
await killHarper(ctx);
|
|
555
|
+
// Safety assertion: killHarper waits for Harper's process tree to exit, which releases its
|
|
556
|
+
// listening sockets, so the fixed ports should already be free here. We still verify before
|
|
557
|
+
// recycling the address (the pool only guarantees the *address* is bindable, not that these
|
|
558
|
+
// specific ports are free) and warn if anything is somehow still holding them — that warning
|
|
559
|
+
// is a signal that a Harper child process escaped the tree kill, not normal operation. The
|
|
560
|
+
// address is recycled regardless.
|
|
561
|
+
if (ctx.harper.hostname) {
|
|
562
|
+
const portsFreed = await waitForPortsFree(ctx.harper.hostname, ALL_HARPER_PORTS, DEFAULT_PORT_RELEASE_TIMEOUT_MS);
|
|
563
|
+
if (portsFreed) {
|
|
564
|
+
await releaseLoopbackAddress(ctx.harper.hostname);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
// A Harper child escaped the tree kill and still holds this address's ports. Do NOT
|
|
568
|
+
// recycle the address — under SO_REUSEPORT a later suite could silently co-bind it
|
|
569
|
+
// (the exact failure the loopback pool exists to prevent). Leave the slot parked under
|
|
570
|
+
// this process's PID; it is reclaimed when this (per-file) process exits and its PID
|
|
571
|
+
// goes dead. The conflict canary in getNextAvailableLoopbackAddress is the backstop if
|
|
572
|
+
// the address is somehow handed out before then.
|
|
573
|
+
console.warn(`Harper ports on ${ctx.harper.hostname} still in use after teardown (${DEFAULT_PORT_RELEASE_TIMEOUT_MS}ms); NOT recycling the address (a Harper child outlived the kill). The slot will be reclaimed when this process exits.`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// a few retries are typically necessary, might take a sec for a process to finish, especially since rocksdb may be flushing
|
|
577
|
+
try {
|
|
578
|
+
await rm(ctx.harper.dataRootDir, { recursive: true, force: true, maxRetries: 10 });
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
console.error('Error removing directory', error);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
export async function sendOperation(context, operation) {
|
|
585
|
+
const response = await fetch(context.operationsAPIURL, {
|
|
586
|
+
method: 'POST',
|
|
587
|
+
headers: { 'Content-Type': 'application/json' },
|
|
588
|
+
body: JSON.stringify(operation),
|
|
589
|
+
});
|
|
590
|
+
const responseData = await response.json();
|
|
591
|
+
equal(response.status, 200, JSON.stringify(responseData));
|
|
592
|
+
return responseData;
|
|
593
|
+
}
|
|
594
|
+
//# sourceMappingURL=harperLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harperLifecycle.js","sourceRoot":"","sources":["../src/harperLifecycle.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, HarperStartupError, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, HARPER_RUNTIME, type StartHarperOptions, type HarperContext, type HarperTestContext, type StartedHarperTestContext, type ContextWithHarper, } from './harperLifecycle.ts';
|
|
2
|
+
export { validateLoopbackAddressPool, getNextAvailableLoopbackAddress, releaseLoopbackAddress, releaseAllLoopbackAddressesForCurrentProcess, } from './loopbackAddressPool.ts';
|
|
3
|
+
export { targz } from './targz.ts';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, HarperStartupError, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, HARPER_RUNTIME, } from "./harperLifecycle.js";
|
|
2
|
+
export { validateLoopbackAddressPool, getNextAvailableLoopbackAddress, releaseLoopbackAddress, releaseAllLoopbackAddressesForCurrentProcess, } from "./loopbackAddressPool.js";
|
|
3
|
+
export { targz } from "./targz.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,GAMd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,4CAA4C,GAC5C,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
|