Add deterministic-tests (#190)
Reviewed-on: https://home.schmelczer.dev/git/git/andras/vault-link/pulls/190 Co-authored-by: Andras Schmelczer <andras@schmelczer.dev> Co-committed-by: Andras Schmelczer <andras@schmelczer.dev>
This commit is contained in:
parent
4482e0155f
commit
0e3132f96c
1 changed files with 7722 additions and 1 deletions
71
frontend/deterministic-tests/src/server-manager.ts
Normal file
71
frontend/deterministic-tests/src/server-manager.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import type { ServerControl } from "./server-control";
|
||||
import type { Logger } from "sync-client";
|
||||
|
||||
export class ServerManager {
|
||||
private readonly activeServers = new Set<ServerControl>();
|
||||
private readonly logger: Logger;
|
||||
private isShuttingDown = false;
|
||||
|
||||
public constructor(logger: Logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public track(server: ServerControl): void {
|
||||
this.activeServers.add(server);
|
||||
}
|
||||
|
||||
public untrack(server: ServerControl): void {
|
||||
this.activeServers.delete(server);
|
||||
}
|
||||
|
||||
public async stopAll(): Promise<void> {
|
||||
if (this.isShuttingDown) {
|
||||
return;
|
||||
}
|
||||
this.isShuttingDown = true;
|
||||
|
||||
const servers = Array.from(this.activeServers);
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
await Promise.all(
|
||||
servers.map(async (server) => {
|
||||
try {
|
||||
await server.stop();
|
||||
} catch {
|
||||
// Best-effort cleanup during shutdown
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public installSignalHandlers(): void {
|
||||
process.on("SIGINT", () => {
|
||||
this.logger.info("Received SIGINT, shutting down...");
|
||||
void this.stopAll()
|
||||
.catch(() => {
|
||||
/* no-op */
|
||||
})
|
||||
.then(() => process.exit(130));
|
||||
});
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
this.logger.info("Received SIGTERM, shutting down...");
|
||||
void this.stopAll()
|
||||
.catch(() => {
|
||||
/* no-op */
|
||||
})
|
||||
.then(() => process.exit(143));
|
||||
});
|
||||
|
||||
// Last-resort synchronous cleanup. Runs even when the process is
|
||||
// exiting via process.exit() from unhandledRejection /
|
||||
// uncaughtException — paths where async stopAll() cannot complete.
|
||||
// SIGSTOP'd servers MUST receive SIGCONT before SIGKILL or the
|
||||
// kernel keeps them as zombies holding the test's tmpdir, and the
|
||||
// next CI run can't reuse the port.
|
||||
process.on("exit", () => {
|
||||
for (const server of this.activeServers) {
|
||||
server.forceKillSync();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue