@harperfast/integration-testing 0.5.0 → 0.5.1

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.
@@ -0,0 +1,262 @@
1
+ import { ChildProcess } from 'node:child_process';
2
+ import { type SuiteContext, type TestContext } from 'node:test';
3
+ /**
4
+ * Minimal context interface required by startHarper/teardownHarper.
5
+ *
6
+ * This is intentionally loose so it can be satisfied by:
7
+ * - node:test SuiteContext/TestContext objects (via ContextWithHarper)
8
+ * - Plain objects (e.g. Playwright worker fixtures: `createHarperContext()`)
9
+ */
10
+ export interface HarperTestContext {
11
+ /** Optional name used for log directory naming (e.g. suite name or Playwright worker index). */
12
+ name?: string;
13
+ /** Populated by startHarper(). May be pre-seeded with dataRootDir/hostname to reuse across restarts. */
14
+ harper?: Partial<HarperContext>;
15
+ }
16
+ /**
17
+ * A started context — harper is fully populated after startHarper() resolves.
18
+ */
19
+ export interface StartedHarperTestContext extends HarperTestContext {
20
+ harper: HarperContext;
21
+ }
22
+ /**
23
+ * Creates a plain object satisfying HarperTestContext, for use outside node:test
24
+ * (e.g. as a Playwright worker fixture).
25
+ *
26
+ * @param name Optional name for log directory naming (e.g. Playwright worker index).
27
+ */
28
+ export declare function createHarperContext(name?: string): HarperTestContext;
29
+ export declare const OPERATIONS_API_PORT = 9925;
30
+ export declare const DEFAULT_ADMIN_USERNAME = "admin";
31
+ export declare const DEFAULT_ADMIN_PASSWORD = "Abc1234!";
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 declare const DEFAULT_STARTUP_TIMEOUT_MS: number;
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 declare const DEFAULT_STARTUP_MAX_MS: number;
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 declare const DEFAULT_TEARDOWN_GRACE_MS: number;
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 declare const DEFAULT_PORT_RELEASE_TIMEOUT_MS: number;
66
+ /**
67
+ * The runtime to use for running Harper during tests.
68
+ * Set via the HARPER_RUNTIME environment variable ('node' or 'bun').
69
+ * Defaults to 'node'.
70
+ */
71
+ export declare const HARPER_RUNTIME: 'node' | 'bun';
72
+ /**
73
+ * Marker emitted on stdout by startHarper() so the test runner (run.ts) can map
74
+ * a Harper instance's log directory to the currently executing test file via
75
+ * the node:test `test:stdout` event.
76
+ */
77
+ export declare const LOG_DIR_MARKER_PREFIX = "[Harper] Logs for this instance will be stored in:";
78
+ /**
79
+ * Options for setting up a Harper instance.
80
+ */
81
+ export interface StartHarperOptions {
82
+ /**
83
+ * Maximum time (ms) to wait between chunks of startup output before treating Harper as hung.
84
+ * Resets on every chunk of output, so it bounds silence, not total boot time.
85
+ * Falls back to {@link DEFAULT_STARTUP_TIMEOUT_MS} (60s).
86
+ */
87
+ startupTimeoutMs?: number;
88
+ /**
89
+ * Absolute ceiling (ms) on total startup time, regardless of ongoing output.
90
+ * Falls back to {@link DEFAULT_STARTUP_MAX_MS} (120s locally, 300s under CI).
91
+ */
92
+ startupMaxMs?: number;
93
+ /**
94
+ * Additional configuration options to pass to the Harper CLI.
95
+ */
96
+ config?: any;
97
+ /**
98
+ * Environment variables to set when running Harper.
99
+ */
100
+ env?: any;
101
+ /**
102
+ * Explicit path to the Harper CLI script (dist/bin/harper.js).
103
+ * If not provided, resolution order is:
104
+ * 1. This option
105
+ * 2. HARPER_INTEGRATION_TEST_INSTALL_SCRIPT environment variable
106
+ * 3. Auto-resolved from 'harper' package in node_modules
107
+ */
108
+ harperBinPath?: string;
109
+ }
110
+ export interface HarperContext {
111
+ /** Absolute path to the Harper installation directory */
112
+ dataRootDir: string;
113
+ /** Admin credentials for the Harper instance */
114
+ admin: {
115
+ /** Admin username (default: 'admin') */
116
+ username: string;
117
+ /** Admin password (default: 'Abc1234!') */
118
+ password: string;
119
+ };
120
+ /** HTTP URL for the Harper instance (e.g., 'http://127.0.0.2:9926') */
121
+ httpURL: string;
122
+ /** Operations API URL (e.g., 'http://127.0.0.2:9925') */
123
+ operationsAPIURL: string;
124
+ /** Assigned loopback IP address (e.g., '127.0.0.2') */
125
+ hostname: string;
126
+ /** Child process for the Harper instance */
127
+ process: ChildProcess;
128
+ /** Absolute path to the log directory for this suite (only set when HARPER_INTEGRATION_TEST_LOG_DIR is configured) */
129
+ logDir?: string;
130
+ /** Captured stdout/stderr from Harper startup, up to the point it reported ready. */
131
+ startupOutput?: {
132
+ stdout: string;
133
+ stderr: string;
134
+ };
135
+ }
136
+ /**
137
+ * Test context interface with Harper instance details, for use with node:test.
138
+ *
139
+ * This interface is populated by `startHarper()` and contains
140
+ * all necessary information to interact with the test Harper instance.
141
+ *
142
+ * For use outside node:test (e.g. Playwright), use `createHarperContext()` to
143
+ * create a plain object satisfying `HarperTestContext` instead.
144
+ */
145
+ export interface ContextWithHarper extends SuiteContext, TestContext {
146
+ harper: HarperContext;
147
+ }
148
+ /**
149
+ * Error thrown when a Harper process fails to start or times out.
150
+ * Includes captured stdout and stderr for diagnostics.
151
+ */
152
+ export declare class HarperStartupError extends Error {
153
+ stdout: string;
154
+ stderr: string;
155
+ constructor(message: string, stdout: string, stderr: string);
156
+ }
157
+ interface RunHarperCommandOptions {
158
+ args: string[];
159
+ env: any;
160
+ completionMessage?: string;
161
+ /** When set, stdout and stderr are written to files in this directory */
162
+ logDir?: string;
163
+ harperBinPath?: string;
164
+ /** Idle timeout (ms): max time between output chunks before treating the process as hung. Resets on output. Falls back to DEFAULT_STARTUP_TIMEOUT_MS. */
165
+ timeoutMs?: number;
166
+ /** Absolute timeout (ms): ceiling on total time regardless of output. Falls back to DEFAULT_STARTUP_MAX_MS. */
167
+ maxMs?: number;
168
+ }
169
+ interface RunHarperCommandResult {
170
+ process: ChildProcess;
171
+ /** Captured stdout up to the point the process was considered ready or exited. */
172
+ stdout: string;
173
+ /** Captured stderr up to the point the process was considered ready or exited. */
174
+ stderr: string;
175
+ }
176
+ /**
177
+ * Runs a Harper CLI command and captures output.
178
+ *
179
+ * When `logDir` is provided, stdout and stderr are also written to files
180
+ * (`stdout.log` and `stderr.log`) in that directory.
181
+ *
182
+ * @throws {HarperStartupError} If the command times out or exits with a non-zero status code
183
+ *
184
+ * Exported for unit testing; not part of the public API (not re-exported from `index.ts`).
185
+ */
186
+ export declare function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath, timeoutMs, maxMs, }: RunHarperCommandOptions): Promise<RunHarperCommandResult>;
187
+ /**
188
+ * Sets up a Harper instance with a component pre-installed from a local directory.
189
+ *
190
+ * Copies `fixturePath` into `{dataRootDir}/components/{name}` before Harper starts,
191
+ * so the component is available on the first request without a post-startup deploy.
192
+ * Use this when tests need a known route available at startup (e.g. mTLS cert tests).
193
+ *
194
+ * @param ctx - The test context to populate with Harper instance details
195
+ * @param fixturePath - Absolute path to the component directory to pre-install
196
+ * @param options - Optional configuration for the setup process
197
+ */
198
+ export declare function setupHarperWithFixture(ctx: HarperTestContext, fixturePath: string, options?: StartHarperOptions): Promise<StartedHarperTestContext>;
199
+ /**
200
+ * Sets up and starts a Harper instance for testing.
201
+ *
202
+ * @param ctx - The test context to populate with Harper instance details
203
+ * @param options - Optional configuration for the setup process
204
+ * @returns The context with the `harper` property populated
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * suite('My tests', (ctx: ContextWithHarper) => {
209
+ * before(async () => {
210
+ * await startHarper(ctx);
211
+ * });
212
+ *
213
+ * after(async () => {
214
+ * await teardownHarper(ctx);
215
+ * });
216
+ *
217
+ * test('can connect', async () => {
218
+ * const response = await fetch(ctx.harper.httpURL);
219
+ * // ...
220
+ * });
221
+ * });
222
+ * ```
223
+ */
224
+ export declare function startHarper(ctx: HarperTestContext, options?: StartHarperOptions): Promise<StartedHarperTestContext>;
225
+ /**
226
+ * Kill harper process (can be used for teardown, or killing it before a restart).
227
+ *
228
+ * Sends SIGTERM to Harper's whole process tree first and gives it a grace period to shut down
229
+ * cleanly (flush RocksDB, release ports, reap worker children) before escalating to SIGKILL.
230
+ * After SIGKILL it waits briefly for the process to actually exit, so callers can rely on it
231
+ * being gone — and, since a dead process releases its listening sockets, on its ports being free.
232
+ *
233
+ * @param ctx
234
+ * @param options.graceMs Time to wait after SIGTERM before sending SIGKILL. Defaults to
235
+ * {@link DEFAULT_TEARDOWN_GRACE_MS}.
236
+ */
237
+ export declare function killHarper(ctx: StartedHarperTestContext, options?: {
238
+ graceMs?: number;
239
+ }): Promise<void>;
240
+ /**
241
+ * Tears down a Harper instance and cleans up all resources.
242
+ *
243
+ * This function stops the Harper instance, releases the loopback address,
244
+ * and removes the installation directory.
245
+ * @param ctx - The test context with Harper instance details
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * suite('My tests', (ctx: ContextWithHarper) => {
250
+ * before(async () => {
251
+ * await startHarper(ctx);
252
+ * });
253
+ *
254
+ * after(async () => {
255
+ * await teardownHarper(ctx);
256
+ * });
257
+ * });
258
+ * ```
259
+ */
260
+ export declare function teardownHarper(ctx: StartedHarperTestContext): Promise<void>;
261
+ export declare function sendOperation(context: HarperContext, operation: any): Promise<any>;
262
+ export {};