Files
ForgeFlow/tests/production-acceptance.test.mjs
T
NuklearRabbit 60e8aa8fc2
ForgeFlow quality gate / quality (push) Canceled after 0s
release: prepare ForgeFlow 0.10.1
2026-07-30 00:49:58 +02:00

130 lines
6.3 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { createRequire } from "node:module";
import { readFile, rm, writeFile } from "node:fs/promises";
const require = createRequire(import.meta.url);
const { ProductionAcceptanceHarness } = require("../src/main/production-acceptance-harness.cjs");
async function fixture(t) {
const harness = await ProductionAcceptanceHarness.create();
t.after(() => harness.cleanup());
return harness;
}
test("production harness proves clean install, portable start and configuration migration", async (t) => {
const harness = await fixture(t);
assert.equal((await harness.install("0.10.0", "portable")).mode, "portable");
const migration = await harness.migrate("1.0.0-rc.1");
assert.equal(migration.previousVersion, "0.10.0");
assert.equal(JSON.parse(await readFile(harness.paths.config, "utf8")).schemaVersion, 13);
assert.equal(JSON.parse(await readFile(migration.backup, "utf8")).schemaVersion, 12);
});
test("authentication fixtures cover token rotation, password, SSH keys and changed host keys", async (t) => {
const harness = await fixture(t);
assert.equal(harness.rotateToken().tokenVersion, 2);
assert.equal(harness.authenticate("password").authenticated, true);
assert.equal(harness.authenticate("ssh-key", { hostFingerprint: "SHA256:fixture-host" }).authenticated, true);
assert.throws(() => harness.authenticate("ssh-key", { hostFingerprint: "SHA256:changed" }), /fingerprint changed/);
});
test("new repositories deploy by server pull and Direct Copy at the exact Gitea SHA", async (t) => {
const harness = await fixture(t);
await harness.install();
harness.authenticate("ssh-key", { hostFingerprint: harness.state.hostFingerprint });
const serverSha = await harness.createCommit();
assert.equal((await harness.deploy(harness.plan(serverSha, "server-git"))).status, "success");
const copySha = await harness.createCommit("fix: direct copy fixture");
assert.equal((await harness.deploy(harness.plan(copySha, "push-bundle"))).status, "success");
assert.equal(harness.state.liveSha, copySha);
});
test("existing deployments are adopted, externally updated and reconciled without replacement", async (t) => {
const harness = await fixture(t);
assert.deepEqual(harness.adoptExisting(), { linked: true, liveSha: harness.initialSha, preserved: true });
const sha = await harness.createCommit();
assert.equal(harness.externalUpdate(sha).liveSha, sha);
assert.equal(harness.state.healthy, true);
});
test("deploy key rotation, revocation, restore and writable-key rejection fail closed", async (t) => {
const harness = await fixture(t);
harness.authenticate("password");
assert.equal(harness.rotateDeployKey().rotated, true);
assert.equal(harness.revokeDeployKey().deploymentBlocked, true);
assert.equal(harness.restoreDeployKey().restored, true);
harness.setKeyAccess(false);
assert.throws(() => harness.rotateDeployKey(), /writable/);
await assert.rejects(() => harness.deploy(harness.plan(harness.initialSha)), /Writable deploy key/);
});
test("unhealthy activation rolls back only to the exact recorded previous SHA", async (t) => {
const harness = await fixture(t);
harness.authenticate("password");
harness.adoptExisting();
const sha = await harness.createCommit();
assert.equal((await harness.deploy(harness.plan(sha), "unhealthy")).status, "failed");
assert.throws(() => harness.rollback("0".repeat(40)), /exact recorded/);
const rollback = harness.rollback(harness.initialSha);
assert.equal(rollback.status, "rolled-back");
assert.equal(rollback.liveSha, harness.initialSha);
});
test("network failures distinguish fetch from partial activation and preserve recovery", async (t) => {
const harness = await fixture(t);
harness.authenticate("password");
const sha = await harness.createCommit();
let outcome = await harness.deploy(harness.plan(sha), "fetch-network");
assert.deepEqual(outcome.failure, { message: "Network interrupted during fetch", partial: false });
outcome = await harness.deploy(harness.plan(sha), "activation-network");
assert.equal(outcome.failure.partial, true);
assert.ok(harness.state.recovery);
});
test("application shutdown is recoverable and stale plans cannot mutate state", async (t) => {
const harness = await fixture(t);
harness.authenticate("password");
const plan = harness.plan(harness.initialSha);
harness.state.liveSha = "1".repeat(40);
await assert.rejects(() => harness.deploy(plan), /Stale reconciliation plan/);
const current = harness.plan(harness.initialSha);
assert.equal((await harness.deploy(current, "shutdown")).status, "interrupted");
assert.equal(harness.recover().status, "failed");
});
test("corrupt configuration is recoverable from the migration backup", async (t) => {
const harness = await fixture(t);
await harness.install();
await harness.migrate();
const backup = `${harness.paths.config}.backup`;
await writeFile(harness.paths.config, "{broken", "utf8");
await assert.rejects(() => readFile(harness.paths.config, "utf8").then(JSON.parse));
await writeFile(harness.paths.config, await readFile(backup));
assert.equal(JSON.parse(await readFile(harness.paths.config, "utf8")).version, "0.10.0");
});
test("release verification rejects checksum failures, missing assets and drafts without requiring paid signing", async (t) => {
const harness = await fixture(t);
await harness.publishRelease("1.0.0-ok");
assert.equal((await harness.verifyRelease("1.0.0-ok")).verified, true);
for (const [version, options, error] of [
["1.0.0-checksum", { badChecksum: true }, /checksum/],
["1.0.0-missing", { missingAsset: true }, /asset is missing/],
["1.0.0-draft", { draft: true }, /draft release/],
]) {
await harness.publishRelease(version, options);
await assert.rejects(() => harness.verifyRelease(version), error);
}
});
test("large and partial inventory fixtures expose duplicates without touching production data", async (t) => {
const harness = await fixture(t);
const inventory = harness.inventory(24, true);
assert.equal(inventory.workloads.length, 24);
assert.equal(inventory.workloads.filter((item) => item.classification === "duplicate").length, 1);
assert.equal(inventory.partial, true);
assert.match(inventory.warnings[0], /unavailable/);
await rm(harness.paths.server, { recursive: true, force: true });
});