Path: blob/master/src/packages/backend/conat/test/setup.ts
1450 views
import getPort from "@cocalc/backend/get-port";1import { type Client } from "@cocalc/conat/core/client";2import {3init as createConatServer,4type Options,5type ConatServer,6} from "@cocalc/conat/core/server";7import getLogger from "@cocalc/backend/logger";8import { setConatClient } from "@cocalc/conat/client";9import { server as createPersistServer } from "@cocalc/backend/conat/persist";10import { syncFiles } from "@cocalc/conat/persist/context";11import { mkdtemp, rm } from "node:fs/promises";12import { tmpdir } from "node:os";13import { join } from "path";14export { wait } from "@cocalc/backend/conat/test/util";15export { delay } from "awaiting";16export { setDefaultTimeouts } from "@cocalc/conat/core/client";17export { once } from "@cocalc/util/async-utils";18import { spawn, ChildProcess } from "node:child_process";1920const logger = getLogger("conat:test:setup");2122export const path = "/conat";2324export async function initConatServer(25options: Partial<Options> = {},26): Promise<ConatServer> {27logger.debug("init");28if (!options?.port) {29const port = await getPort();30options = { ...options, port };31}3233return createConatServer(options);34}3536export let tempDir;37export let server: any = null;38export let persistServer: any = null;3940export async function createServer(opts?) {41const port = await getPort();42server = await initConatServer({ port, path, ...opts });43return server;44}4546export async function restartServer() {47const port = server.options.port;48await server.close();49await createServer({ port });50}5152export async function restartPersistServer() {53await persistServer.close();54client = connect();55persistServer = createPersistServer({ client });56}5758// one pre-made client59export let client;60export async function before() {61tempDir = await mkdtemp(join(tmpdir(), "conat-test"));62server = await createServer();63client = connect();64persistServer = createPersistServer({ client });65syncFiles.local = join(tempDir, "local");66syncFiles.archive = join(tempDir, "archive");67setConatClient({68conat: connect,69getLogger,70});71}7273const clients: Client[] = [];74export function connect(opts?): Client {75const cn = server.client({ noCache: true, ...opts });76clients.push(cn);77return cn;78}7980export async function after() {81persistServer?.close();82await rm(tempDir, { force: true, recursive: true });83await server?.close();84for (const cn of clients) {85cn.close();86}87for (const { close } of valkeys) {88close();89}90}9192process.once("exit", () => {93for (const { close } of valkeys) {94try {95close();96} catch {}97}98});99["SIGINT", "SIGTERM", "SIGQUIT"].forEach((sig) => {100process.once(sig, () => {101process.exit();102});103});104105// runs a new ephemeral valkey server on an available port,106// returning that port.107const valkeys: any[] = [];108export async function runValkey(): Promise<{109port: number;110address: string;111close: () => void;112password: string;113}> {114const port = await getPort();115const password = "testpass";116117// sapwn valkey-server listening on port running in a mode where118// data is never saved to disk using the nodejs spawn command:119// // Start valkey-server with in-memory only, no persistence120const child: ChildProcess = spawn(121"valkey-server",122[123"--port",124String(port),125"--save",126"",127"--appendonly",128"no",129"--requirepass",130password,131],132{133stdio: "ignore", // or "inherit" for debugging134detached: false,135},136);137138let closed = false;139const close = () => {140if (closed) return;141closed = true;142if (!child?.pid) return;143try {144process.kill(child.pid, "SIGKILL");145} catch {146// already dead or not found147}148};149150const server = {151port,152close,153address: `valkey://:${password}@localhost:${port}`,154password,155};156valkeys.push(server);157158return server;159}160161162