Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
// Ensure `globalThis.crypto` is available in bare-Node vitest runs.
import { webcrypto } from "node:crypto";
type WritableGlobal = { crypto?: Crypto };
const g = globalThis as WritableGlobal;
if (g.crypto === undefined) {
g.crypto = webcrypto as unknown as Crypto;
}

View File

@@ -0,0 +1,135 @@
/**
* Real in-package `DiscoveryStrategy` fixture used by unit tests.
*
* This is NOT a mock. It is a complete, deterministic implementation of the
* `@suaveplan/network-bootstrap` `DiscoveryStrategy` contract whose
* behaviour is controlled entirely by constructor options. Tests configure
* the peer list, the failure mode, and the announce delay to engineer
* specific orchestrator-level scenarios (e.g. priority fallback, peer
* dedup commutativity, race-to-fastest correctness) without ever calling
* `vi.mock` or registering a module-level stub.
*
* The fixture lives under `tests/setup/` so the coverage gate ignores it
* (the `vitest.config.ts` `coverage.exclude` glob covers `tests/**`).
*/
import type { DiscoveryStrategy, PeerInfo } from "@suaveplan/network-bootstrap";
export interface TestStrategyOptions {
readonly name: string;
/** Peers to return from `discover()`. Defaults to `[]`. */
readonly peers?: readonly PeerInfo[];
/** Wall-clock delay before `discover()` resolves (ms). Default 0. */
readonly delayMs?: number;
/** If true, `discover()` rejects with `lastError`. */
readonly failsDiscover?: boolean;
/** If true, `start()` rejects with `lastError`. */
readonly failsStart?: boolean;
/** If true, `isAvailable()` returns false. */
readonly unavailable?: boolean;
/** Error to throw when `failsDiscover` or `failsStart` is true. */
readonly error?: Error;
}
export class TestStrategy implements DiscoveryStrategy {
public readonly name: string;
public startedCount = 0;
public stoppedCount = 0;
public discoverCount = 0;
private peers: PeerInfo[];
private readonly delayMs: number;
private failsDiscover: boolean;
private readonly failsStart: boolean;
private available: boolean;
private readonly error: Error;
public constructor(options: TestStrategyOptions) {
this.name = options.name;
this.peers = [...(options.peers ?? [])];
this.delayMs = options.delayMs ?? 0;
this.failsDiscover = options.failsDiscover ?? false;
this.failsStart = options.failsStart ?? false;
this.available = !(options.unavailable ?? false);
this.error =
options.error ?? new Error("TestStrategy: induced failure");
}
public async start(_signal?: AbortSignal): Promise<void> {
this.startedCount += 1;
if (this.failsStart) throw this.error;
}
public async stop(_signal?: AbortSignal): Promise<void> {
this.stoppedCount += 1;
}
public async discover(
_timeoutMs: number,
signal?: AbortSignal
): Promise<PeerInfo[]> {
this.discoverCount += 1;
if (this.delayMs > 0) await wait(this.delayMs, signal);
if (this.failsDiscover) throw this.error;
if (signal?.aborted) throw makeAbortError();
return [...this.peers];
}
public async isAvailable(_signal?: AbortSignal): Promise<boolean> {
return this.available;
}
// Test-only setters so a single fixture instance can be re-purposed
// mid-run (e.g. to simulate degradation between calls).
public setAvailable(value: boolean): void {
this.available = value;
}
public setFailsDiscover(value: boolean): void {
this.failsDiscover = value;
}
public setPeers(peers: readonly PeerInfo[]): void {
this.peers = [...peers];
}
}
function wait(ms: number, signal?: AbortSignal): Promise<void> {
return new Promise((resolve, reject) => {
if (signal?.aborted) {
reject(makeAbortError());
return;
}
const timer = setTimeout(() => {
cleanup();
resolve();
}, ms);
const onAbort = (): void => {
cleanup();
reject(makeAbortError());
};
signal?.addEventListener("abort", onAbort, { once: true });
function cleanup(): void {
clearTimeout(timer);
signal?.removeEventListener("abort", onAbort);
}
});
}
function makeAbortError(): Error {
const err = new Error("Aborted");
err.name = "AbortError";
return err;
}
export function makePeer(
peerId: string,
source: string,
lastSeen = 0
): PeerInfo {
return {
peerId,
addresses: [],
lastSeen,
source,
};
}