g1t/services/deployments/src/moves.test.ts
| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { moveTargets, ownerOf, rebuildOutcome, retryDue, type MovedApp } from "./moves.ts"; |
| 5 | |
| 6 | const app = (over: Partial<MovedApp>): MovedApp => ({ |
| 7 | script: "lab-api-syntaqx", |
| 8 | project_id: "prj_api", |
| 9 | kind: "production", |
| 10 | branch: null, |
| 11 | number: null, |
| 12 | commit_sha: "aaa", |
| 13 | deployed_at: "2026-10-05T00:26:29Z", |
| 14 | ...over, |
| 15 | }); |
| 16 | |
| 17 | test("each stale app is one target, paused or not, with the names it replaces", () => { |
| 18 | const targets = moveTargets([ |
| 19 | app({}), |
| 20 | app({ script: "lab-api-git-v2-syntaqx", kind: "preview", branch: "v2", number: 1, commit_sha: "bbb" }), |
| 21 | app({ script: "automation-lab-syntaqx", project_id: "prj_lab", commit_sha: "ccc" }), |
| 22 | ]); |
| 23 | assert.deepEqual( |
| 24 | targets.map((t) => [t.projectId, t.kind, t.branch, t.number, t.commit, t.from]), |
| 25 | [ |
| 26 | ["prj_api", "production", null, null, "aaa", ["lab-api-syntaqx"]], |
| 27 | ["prj_api", "preview", "v2", 1, "bbb", ["lab-api-git-v2-syntaqx"]], |
| 28 | ["prj_lab", "production", null, null, "ccc", ["automation-lab-syntaqx"]], |
| 29 | ], |
| 30 | ); |
| 31 | }); |
| 32 | |
| 33 | test("an app under two old names (moved twice) is built once, replacing both", () => { |
| 34 | const targets = moveTargets([ |
| 35 | app({ script: "lab-api-acme", deployed_at: "2026-10-01T00:00:00Z", commit_sha: "old" }), |
| 36 | app({ script: "lab-api-syntaqx", deployed_at: "2026-10-05T00:00:00Z", commit_sha: "new" }), |
| 37 | ]); |
| 38 | assert.equal(targets.length, 1); |
| 39 | assert.equal(targets[0].commit, "new"); |
| 40 | assert.deepEqual(targets[0].from.sort(), ["lab-api-acme", "lab-api-syntaqx"]); |
| 41 | }); |
| 42 | |
| 43 | test("a build a move dropped is built again, at its newer commit", () => { |
| 44 | const targets = moveTargets( |
| 45 | [app({})], |
| 46 | [ |
| 47 | { project_id: "prj_api", kind: "production", branch: null, number: null, commit_sha: "newer", created_at: "2026-10-06T01:00:00Z" }, |
| 48 | { project_id: "prj_web", kind: "preview", branch: "x", number: 4, commit_sha: "w", created_at: "2026-10-06T01:00:00Z" }, |
| 49 | ], |
| 50 | ); |
| 51 | assert.deepEqual( |
| 52 | targets.map((t) => [t.projectId, t.commit, t.from]), |
| 53 | [ |
| 54 | ["prj_api", "newer", ["lab-api-syntaqx"]], |
| 55 | ["prj_web", "w", []], |
| 56 | ], |
| 57 | ); |
| 58 | }); |
| 59 | |
| 60 | test("only a queued build counts as rebuilt; refusals and errors are tried again", () => { |
| 61 | assert.equal(rebuildOutcome({ ok: true, value: { status: "queued" } }), "queued"); |
| 62 | assert.equal(rebuildOutcome({ ok: true, value: { status: "skipped" } }), "failed"); |
| 63 | assert.equal(rebuildOutcome({ ok: true, value: { status: "failed" } }), "failed"); |
| 64 | assert.equal(rebuildOutcome({ ok: false }), "failed"); |
| 65 | assert.equal(rebuildOutcome(null), "none"); |
| 66 | }); |
| 67 | |
| 68 | test("a rebuild that could not start waits before it is tried again", () => { |
| 69 | const now = Date.parse("2026-10-06T02:00:00Z"); |
| 70 | assert.equal(retryDue(null, now, 3600_000), true); |
| 71 | assert.equal(retryDue("2026-10-06T01:30:00Z", now, 3600_000), false); |
| 72 | assert.equal(retryDue("2026-10-06T01:00:00Z", now, 3600_000), true); |
| 73 | }); |
| 74 | |
| 75 | test("an app is its project's current workspace's, not the one its row names", () => { |
| 76 | const owners = new Map([["prj_api", "flagon-io"]]); |
| 77 | assert.equal(ownerOf({ project_id: "prj_api", workspace: "syntaqx" }, owners), "flagon-io"); |
| 78 | assert.equal(ownerOf({ project_id: "prj_gone", workspace: "syntaqx" }, owners), "syntaqx"); |
| 79 | }); |