startContainers.ts•2.4 kB
import { execSync } from "child_process";
import net from "net";
import path from "path";
import { fileURLToPath } from "url";
import type { GlobalSetupContext } from "vitest/node";
import { waitUntil } from "../utils.js";
async function getRandomPort(): Promise<number> {
const server = net.createServer();
return new Promise<number>((resolve, reject) => {
server.unref();
server.on("error", reject);
server.listen(0, () => {
const port = (server.address() as net.AddressInfo).port;
server.close(() => resolve(port));
});
});
}
async function waitForHealthy(
ingressPort: number,
adminPort: number,
timeout = 60000,
): Promise<void> {
await waitUntil(
async () => {
const response = await fetch(`http://localhost:${adminPort}/health`);
return response.ok;
},
"Restate admin API is healthy",
timeout,
);
await waitUntil(
async () => {
const response = await fetch(
`http://localhost:${ingressPort}/restate/health`,
);
return response.ok;
},
"Restate ingress is healthy",
timeout,
);
}
export default async function ({ provide }: GlobalSetupContext) {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ingressPort = await getRandomPort();
const adminPort = await getRandomPort();
console.log(
`Starting Restate on ports ${ingressPort} (ingress) and ${adminPort} (admin)...`,
);
execSync(`docker compose up -d`, {
cwd: path.join(__dirname, ".."),
stdio: "ignore",
env: {
...process.env,
RESTATE_INGRESS_PORT: ingressPort.toString(),
RESTATE_ADMIN_PORT: adminPort.toString(),
},
});
console.log("Waiting for Restate to become healthy...");
await waitForHealthy(ingressPort, adminPort);
provide("restateIngressPort", ingressPort);
provide("restateAdminPort", adminPort);
process.env.RESTATE_INGRESS_ADDR = `http://localhost:${ingressPort}`;
process.env.RESTATE_ADMIN_ADDR = `http://localhost:${adminPort}`;
process.env.RESTATE_LISTEN_PORT = "9080";
return async () => {
console.log("Stopping Restate...");
execSync("docker compose down", {
cwd: path.join(__dirname, ".."),
stdio: "ignore",
});
return Promise.resolve();
};
}
declare module "vitest" {
export interface ProvidedContext {
restateIngressPort: number;
restateAdminPort: number;
}
}