Skip to content
quarry Artifact [458fc0b6ca]
Login

Artifact [458fc0b6ca]

Artifact 458fc0b6ca969f46e1c054805f310e7fd71d8310b7422f5abbe9898151e00cd3:


import { test } from "node:test";
import assert from "node:assert/strict";
import {
  initialState, step, timelineBroken, formatDuration, composeMessage, sendAlert, STARTING_GRACE_MS,
} from "../src/logic.js";

const up = (version = "v1", node = "n1") => ({ health: { status: 200, ready: true, version, node }, timelineStatus: 200 });
const down = (status = 502) => ({ health: { status, ready: false } });
const T = 60_000;

function run(obsList, start = initialState(), t0 = 1_000_000) {
  let s = start;
  const all = [];
  obsList.forEach((o, i) => {
    const r = step(s, o, t0 + i * T);
    s = r.state;
    all.push(...r.actions);
  });
  return { s, all };
}

test("healthy checks record version and node, no actions", () => {
  const { s, all } = run([up("v1", "a"), up("v1", "a")]);
  assert.deepEqual(all, []);
  assert.equal(s.version, "v1");
  assert.equal(s.node, "a");
  assert.equal(s.incident, null);
});

test("one unhealthy check does not alert", () => {
  const { all } = run([up(), down(), up()]);
  assert.deepEqual(all, []);
});

test("two consecutive unhealthy checks alert once", () => {
  const { s, all } = run([up(), down(), down(), down(), down()]);
  assert.equal(all.length, 1);
  assert.equal(all[0].kind, "down");
  assert.equal(all[0].since, 1_000_000 + T);
  assert.equal(s.incident, "down");
});

test("ready:false with 200 counts as unhealthy", () => {
  const notReady = { health: { status: 200, ready: false, version: "v1" } };
  const { all } = run([up(), notReady, notReady]);
  assert.equal(all[0].kind, "down");
});

test("recovery reports outage length from first failure", () => {
  const { s, all } = run([up(), down(), down(), down(), up()]);
  assert.deepEqual(all.map((a) => a.kind), ["down", "recovered"]);
  assert.equal(all[1].outageMs, 3 * T);
  assert.equal(s.incident, null);
});

test("no recovery message without a prior alert", () => {
  const { all } = run([up(), down(), up()]);
  assert.deepEqual(all, []);
});

test("timeline 5xx twice alerts broken once", () => {
  const bad = { ...up(), timelineStatus: 500 };
  const { s, all } = run([up(), bad, bad, bad]);
  assert.deepEqual(all.map((a) => a.kind), ["broken"]);
  assert.equal(s.incident, "broken");
});

test("single timeline 5xx does not alert", () => {
  const bad = { ...up(), timelineStatus: 500 };
  assert.deepEqual(run([up(), bad, up()]).all, []);
});

test("broken recovers when timeline answers", () => {
  const bad = { ...up(), timelineStatus: 500 };
  const { all } = run([up(), bad, bad, up()]);
  assert.deepEqual(all.map((a) => a.kind), ["broken", "recovered"]);
});

test("503 within grace of a version change is not an incident", () => {
  const starting = { ...up("v2"), timelineStatus: 503 };
  const { all, s } = run([up("v1"), starting, starting, starting]);
  assert.deepEqual(all, []);
  assert.equal(s.brokenStreak, 0);
});

test("503 after the grace window counts", () => {
  const starting = { ...up("v2"), timelineStatus: 503 };
  const n = STARTING_GRACE_MS / T + 3;
  const { all } = run([up("v1"), ...Array(n).fill(starting)]);
  assert.deepEqual(all.map((a) => a.kind), ["broken"]);
});

test("503 without a version change counts", () => {
  const bad = { ...up(), timelineStatus: 503 };
  assert.deepEqual(run([up(), bad, bad]).all.map((a) => a.kind), ["broken"]);
});

test("timelineBroken ignores null and 4xx", () => {
  assert.equal(timelineBroken(null, null, 0), false);
  assert.equal(timelineBroken(404, null, 0), false);
  assert.equal(timelineBroken(500, null, 0), true);
});

test("down then host back but timeline still broken hands over to broken", () => {
  const bad = { ...up(), timelineStatus: 500 };
  const { s, all } = run([up(), down(), down(), bad]);
  assert.deepEqual(all.map((a) => a.kind), ["down", "recovered"]);
  assert.equal(s.incident, "broken");
});

test("first ever observation is not a version change", () => {
  const { s } = run([up("v1")]);
  assert.equal(s.versionChangedAt, null);
});

test("formatDuration", () => {
  assert.equal(formatDuration(45_000), "45s");
  assert.equal(formatDuration(125_000), "2m 5s");
  assert.equal(formatDuration(3_700_000), "1h 1m");
});

test("composeMessage carries state and link", () => {
  const s = { ...initialState(), lastStatus: 502, version: "v9", node: "n7" };
  const m = composeMessage({ kind: "down", since: 0 }, s, "https://forge.example");
  assert.match(m.subject, /1970-01-01T00:00:00.000Z/);
  for (const part of ["502", "v9", "n7", "https://forge.example"]) assert.ok(m.body.includes(part));
  const r = composeMessage({ kind: "recovered", since: 0, outageMs: 90_000 }, s, "u");
  assert.ok(r.subject.includes("1m 30s"));
});

test("sendAlert calls the Email Sending binding with the documented shape", async () => {
  const calls = [];
  const env = { ALERT_TO: "[email protected]", ALERT_FROM: "[email protected]", ALERT_EMAIL: { send: async (m) => calls.push(m) } };
  const state = { ...initialState(), lastStatus: 502 };
  await sendAlert(env, { kind: "down", since: 0 }, state, "https://forge.example");
  assert.equal(calls.length, 1);
  assert.deepEqual(Object.keys(calls[0]).sort(), ["from", "html", "subject", "text", "to"]);
  assert.equal(calls[0].to, "[email protected]");
  assert.equal(calls[0].from.email, "[email protected]");
  assert.equal(typeof calls[0].from.name, "string");
  assert.ok(calls[0].text.includes("https://forge.example"));
});

test("the alert carries quarry's card as its html part, and the text part stays", () => {
  const s = { ...initialState(), lastStatus: 502, version: "v9<x>", node: "n7" };
  for (const action of [{ kind: "down", since: 0 }, { kind: "broken", since: 0 }, { kind: "recovered", since: 0, outageMs: 90_000 }]) {
    const m = composeMessage(action, s, "https://forge.example");
    assert.ok(m.body.includes("last status: 502"), "text part unchanged");
    const h = m.html;
    assert.equal((h.match(/class="q-card"/g) || []).length, 1, "one card");
    assert.ok(h.includes("@media (prefers-color-scheme: dark)"));
    assert.ok(h.includes("max-width:600px") && h.includes("#f4f4f4"));
    assert.ok(h.includes('href="https://forge.example"'), "button to the forge");
    // Application email: the logo and the wordmark, whose alt text survives a forge that is down.
    assert.equal((h.match(/>QUARRY</g) || []).length, 2, "the word in header and footer, as text");
    assert.ok(h.includes("'Iosevka Fixed','Iosevka','Arial Narrow'") && h.includes("text-transform:uppercase"));
    assert.ok(h.includes(".q-word { color:#f0ece4 !important; }"), "white in the dark block");
    assert.ok(!h.includes("lockup") && !h.includes("wordmark") && !h.toLowerCase().includes("b9541a"));
    assert.ok(!h.includes(">quarry<"));
    assert.ok(!h.includes("v9<x>") && h.includes("v9&lt;x&gt;"), "values are escaped");
    assert.ok(!h.includes("<script"));
    // Nothing remote but the font sheet and the forge's own images; every link absolute.
    for (const m2 of h.matchAll(/(?:src|href)="([^"]*)"/g)) assert.match(m2[1], /^https:\/\//);
    const remote = [...h.matchAll(/(?:src|href)="(https:\/\/[^"]*)"/g)].map((x) => x[1]).filter((u) => !u.startsWith("https://zeitforge.app") && u !== "https://forge.example");
    assert.deepEqual(remote, ["https://cdn.jsdelivr.net/npm/@fontsource/iosevka/600.css", "https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;600;700&family=IBM+Plex+Mono&display=swap"]);
  }
});