191 lines
7.6 KiB
TypeScript
191 lines
7.6 KiB
TypeScript
import { readFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { describe, expect, it } from "vitest";
|
|
import { parse } from "yaml";
|
|
|
|
interface ComposeService {
|
|
environment?: Record<string, string>;
|
|
healthcheck?: unknown;
|
|
image?: string;
|
|
ports?: string[];
|
|
volumes?: string[];
|
|
}
|
|
|
|
interface ComposeDocument {
|
|
services?: Record<string, ComposeService>;
|
|
volumes?: Record<string, unknown>;
|
|
}
|
|
|
|
interface PackageDocument {
|
|
scripts?: Record<string, string>;
|
|
}
|
|
|
|
interface WorkflowJob {
|
|
needs?: string;
|
|
steps?: WorkflowStep[];
|
|
"timeout-minutes"?: number;
|
|
}
|
|
|
|
interface WorkflowStep {
|
|
run?: string;
|
|
uses?: string;
|
|
}
|
|
|
|
interface TurboDocument {
|
|
tasks?: Record<string, unknown>;
|
|
}
|
|
|
|
interface WorkspaceDocument {
|
|
packages?: string[];
|
|
}
|
|
|
|
const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
|
describe("development infrastructure", () => {
|
|
it("has valid, local-only, version-pinned Compose services", async () => {
|
|
const source = await readFile(
|
|
path.join(repositoryRoot, "infrastructure", "compose.yaml"),
|
|
"utf8",
|
|
);
|
|
const compose = parse(source) as ComposeDocument;
|
|
const postgres = compose.services?.postgres;
|
|
const objectStorage = compose.services?.["object-storage"];
|
|
|
|
expect(postgres?.image).toBe("postgres:18.4-alpine3.24");
|
|
expect(objectStorage?.image).toBe("chrislusf/seaweedfs:4.28");
|
|
expect(postgres?.healthcheck).toBeDefined();
|
|
expect(objectStorage?.healthcheck).toBeDefined();
|
|
expect(postgres?.environment?.POSTGRES_INITDB_ARGS).toContain("--auth-host=scram-sha-256");
|
|
|
|
for (const service of [postgres, objectStorage]) {
|
|
expect(service).toBeDefined();
|
|
expect(service?.image).not.toMatch(/:latest$/u);
|
|
expect(service?.ports?.every((port) => port.startsWith("127.0.0.1:"))).toBe(true);
|
|
expect(service?.volumes?.length).toBeGreaterThan(0);
|
|
}
|
|
|
|
expect(compose.volumes).toHaveProperty("postgres-data");
|
|
expect(compose.volumes).toHaveProperty("object-storage-data");
|
|
});
|
|
|
|
it("has a parseable CI workflow with static and live infrastructure gates", async () => {
|
|
const source = await readFile(
|
|
path.join(repositoryRoot, ".github", "workflows", "ci.yml"),
|
|
"utf8",
|
|
);
|
|
const workflow = parse(source) as {
|
|
jobs?: Record<string, WorkflowJob>;
|
|
name?: string;
|
|
};
|
|
const verify = workflow.jobs?.verify;
|
|
const infrastructure = workflow.jobs?.["infrastructure-smoke"];
|
|
const migration = workflow.jobs?.["migration-smoke"];
|
|
const commands = verify?.steps?.flatMap((step) => step.run ?? []) ?? [];
|
|
const infrastructureCommands = infrastructure?.steps?.flatMap((step) => step.run ?? []) ?? [];
|
|
const migrationCommands = migration?.steps?.flatMap((step) => step.run ?? []) ?? [];
|
|
const verifyActions = verify?.steps?.flatMap((step) => step.uses ?? []) ?? [];
|
|
const migrationActions = migration?.steps?.flatMap((step) => step.uses ?? []) ?? [];
|
|
|
|
expect(workflow.name).toBe("CI");
|
|
expect(verify).toBeDefined();
|
|
expect(commands).toContain("pnpm install --frozen-lockfile");
|
|
expect(commands).toContain("pnpm ci:verify");
|
|
expect(infrastructureCommands).toContain("bash scripts/smoke-infrastructure.sh");
|
|
expect(migration?.needs).toBe("verify");
|
|
expect(migration?.["timeout-minutes"]).toBe(15);
|
|
expect(migrationActions).toEqual(verifyActions);
|
|
expect(migrationCommands).toContain("pnpm install --frozen-lockfile");
|
|
expect(migrationCommands).toContain("pnpm test:migrations:integration");
|
|
});
|
|
|
|
it("routes containerized S3 smoke checks through the isolated Compose network", async () => {
|
|
const source = await readFile(
|
|
path.join(repositoryRoot, "scripts", "smoke-infrastructure.sh"),
|
|
"utf8",
|
|
);
|
|
const helper = await readFile(
|
|
path.join(repositoryRoot, "scripts", "lib", "compose-job-network.sh"),
|
|
"utf8",
|
|
);
|
|
|
|
expect(source).toContain('source "$repository_root/scripts/lib/compose-job-network.sh"');
|
|
expect(source).toContain(`compose_job_network_connect object-storage "\${compose[@]}"`);
|
|
expect(source).toContain('s3_endpoint="http://object-storage:8333"');
|
|
expect(source).toContain('s3_endpoint="http://127.0.0.1:$s3_port"');
|
|
expect(source).not.toContain("0.0.0.0:${S3_PORT");
|
|
expect(source.indexOf("compose_job_network_disconnect")).toBeLessThan(
|
|
source.indexOf(`"\${compose[@]}" down`),
|
|
);
|
|
|
|
expect(helper).toContain("[[ ! -f /.dockerenv ]]");
|
|
expect(helper).toContain('"$@" ps -q "$service"');
|
|
expect(helper).toContain("docker inspect");
|
|
expect(helper).toContain("docker network connect");
|
|
expect(helper).toContain("docker network disconnect");
|
|
});
|
|
|
|
it("provisions isolated PostgreSQL for the live migration suite", async () => {
|
|
const packageSource = await readFile(path.join(repositoryRoot, "package.json"), "utf8");
|
|
const packageDocument = JSON.parse(packageSource) as PackageDocument;
|
|
const source = await readFile(
|
|
path.join(repositoryRoot, "scripts", "test-migrations-integration.sh"),
|
|
"utf8",
|
|
);
|
|
|
|
expect(packageDocument.scripts?.["test:migrations:integration"]).toBe(
|
|
"pnpm build && bash scripts/test-migrations-integration.sh",
|
|
);
|
|
expect(source).toContain('source "$repository_root/scripts/lib/compose-job-network.sh"');
|
|
expect(source).toContain('export POSTGRES_PORT="0"');
|
|
expect(source).toContain("up --detach --wait --wait-timeout 120 postgres");
|
|
expect(source).toContain(`compose_job_network_connect postgres "\${compose[@]}"`);
|
|
expect(source).toContain('database_host="postgres"');
|
|
expect(source).toContain('database_port="5432"');
|
|
expect(source).toContain('database_host="127.0.0.1"');
|
|
expect(source).toContain(
|
|
'EKKLESIA_MIGRATION_TEST_DATABASE_URL="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$database_host:$database_port/$POSTGRES_DB"',
|
|
);
|
|
expect(source).toContain("--config vitest.migrations.integration.config.ts");
|
|
expect(source).not.toContain("0.0.0.0");
|
|
expect(source).not.toContain('compose[@]}" logs');
|
|
expect(source.indexOf("compose_job_network_disconnect")).toBeLessThan(
|
|
source.indexOf("down --volumes --remove-orphans"),
|
|
);
|
|
});
|
|
|
|
it("includes every official platform layer in the workspace", async () => {
|
|
const source = await readFile(path.join(repositoryRoot, "pnpm-workspace.yaml"), "utf8");
|
|
const workspace = parse(source) as WorkspaceDocument;
|
|
|
|
expect(workspace.packages).toEqual(
|
|
expect.arrayContaining([
|
|
"apps/*",
|
|
"builders/*",
|
|
"core",
|
|
"modules/*",
|
|
"surfaces/*",
|
|
"templates/*",
|
|
]),
|
|
);
|
|
});
|
|
|
|
it("dispatches root and future package quality tasks through Turborepo", async () => {
|
|
const packageSource = await readFile(path.join(repositoryRoot, "package.json"), "utf8");
|
|
const turboSource = await readFile(path.join(repositoryRoot, "turbo.json"), "utf8");
|
|
const packageDocument = JSON.parse(packageSource) as PackageDocument;
|
|
const turboDocument = JSON.parse(turboSource) as TurboDocument;
|
|
|
|
expect(packageDocument.scripts?.lint).toBe("turbo run lint lint:root");
|
|
expect(packageDocument.scripts?.test).toBe("turbo run test test:root");
|
|
expect(packageDocument.scripts?.typecheck).toBe("turbo run typecheck typecheck:root");
|
|
expect(packageDocument.scripts?.["modules:validate"]).toBe(
|
|
"turbo run build && node core/dist/cli/validate-modules.js",
|
|
);
|
|
expect(packageDocument.scripts?.verify).toContain("pnpm modules:validate");
|
|
expect(turboDocument.tasks).toHaveProperty("//#lint:root");
|
|
expect(turboDocument.tasks).toHaveProperty("//#test:root");
|
|
expect(turboDocument.tasks).toHaveProperty("//#typecheck:root");
|
|
});
|
|
});
|