90 lines
2.3 KiB
JavaScript
90 lines
2.3 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { execFile } from "node:child_process";
|
|
import { mkdtemp, mkdir, writeFile } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { promisify } from "node:util";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const root = path.resolve(import.meta.dirname, "..");
|
|
|
|
async function dockerAvailable() {
|
|
try {
|
|
await execFileAsync("docker", ["info"], { timeout: 15_000 });
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
test("Docker image starts against PostgreSQL and applies migrations", async (t) => {
|
|
if (!(await dockerAvailable())) {
|
|
t.skip("Docker daemon is unavailable");
|
|
return;
|
|
}
|
|
const temp = await mkdtemp(
|
|
path.join(os.tmpdir(), "roast-planner-container-"),
|
|
);
|
|
const agentDir = path.join(temp, "pi-agent");
|
|
await mkdir(agentDir);
|
|
const envFile = path.join(temp, "compose.env");
|
|
await writeFile(
|
|
envFile,
|
|
`POSTGRES_PASSWORD=container-test-password\nBOOTSTRAP_SETUP_TOKEN=\nPI_AGENT_CONFIG_DIR=${agentDir}\nAPP_PORT=18090\n`,
|
|
);
|
|
const project = `roastplanner${Date.now()}`;
|
|
const compose = (args, options = {}) =>
|
|
execFileAsync(
|
|
"docker",
|
|
["compose", "--project-name", project, "--env-file", envFile, ...args],
|
|
{ cwd: root, timeout: 120_000, ...options },
|
|
);
|
|
t.after(async () => {
|
|
try {
|
|
await compose(["down", "--volumes", "--remove-orphans"]);
|
|
} catch {
|
|
// Preserve the startup failure rather than masking it with cleanup.
|
|
}
|
|
});
|
|
await compose(["up", "--build", "--detach"]);
|
|
|
|
let lastError;
|
|
for (let attempt = 0; attempt < 30; attempt++) {
|
|
try {
|
|
await compose([
|
|
"exec",
|
|
"-T",
|
|
"app",
|
|
"node",
|
|
"--input-type=module",
|
|
"-e",
|
|
"const response = await fetch('http://127.0.0.1:8090/'); process.exit(response.ok ? 0 : 1)",
|
|
]);
|
|
lastError = null;
|
|
break;
|
|
} catch (error) {
|
|
lastError = error;
|
|
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
}
|
|
}
|
|
assert.equal(
|
|
lastError,
|
|
null,
|
|
"application never became ready in its container",
|
|
);
|
|
const migration = await compose([
|
|
"exec",
|
|
"-T",
|
|
"db",
|
|
"psql",
|
|
"-U",
|
|
"roast",
|
|
"-d",
|
|
"roast",
|
|
"-tAc",
|
|
"SELECT count(*) FROM schema_migrations WHERE filename = '001_auth.sql'",
|
|
]);
|
|
assert.equal(migration.stdout.trim(), "1");
|
|
});
|