g1t/apps/status/src/probe.test.ts
| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { combine, judgeStorage, runCheck, step } from "./probe.ts"; |
| 5 | |
| 6 | const answer = (status: number) => async () => new Response("x", { status }); |
| 7 | |
| 8 | test("a step works on 2xx, or on exactly the status it expects", async () => { |
| 9 | assert.equal((await step(answer(200), { url: "https://a/" })).ok, true); |
| 10 | const refused = await step(answer(502), { url: "https://a/" }); |
| 11 | assert.deepEqual([refused.ok, refused.error], [false, "HTTP 502"]); |
| 12 | assert.equal((await step(answer(401), { url: "https://a/", expect: 401 })).ok, true); |
| 13 | assert.equal((await step(answer(200), { url: "https://a/", expect: 401 })).ok, false); |
| 14 | }); |
| 15 | |
| 16 | test("a step that cannot connect, or takes too long, fails with why", async () => { |
| 17 | const broken = await step(async () => Promise.reject(new TypeError("boom")), { url: "https://a/" }); |
| 18 | assert.equal(broken.error, "could not connect"); |
| 19 | const slow = await step( |
| 20 | (_url, init) => new Promise((_, reject) => init.signal?.addEventListener("abort", () => reject(new Error("aborted")))), |
| 21 | { url: "https://a/" }, |
| 22 | 20, |
| 23 | ); |
| 24 | assert.equal(slow.error, "timed out"); |
| 25 | }); |
| 26 | |
| 27 | test("a check's steps: all must work, and it takes as long as the slowest", () => { |
| 28 | assert.deepEqual(combine([{ ok: true, ms: 10 }, { ok: true, ms: 30 }]), { ok: true, ms: 30 }); |
| 29 | assert.deepEqual(combine([{ ok: true, ms: 10 }, { ok: false, ms: 5, error: "HTTP 500" }]), { ok: false, ms: 10, error: "HTTP 500" }); |
| 30 | }); |
| 31 | |
| 32 | test("runCheck: billing without a binding, and a part with no check, are null", async () => { |
| 33 | const probers = { fetch: answer(200), billing: null }; |
| 34 | assert.equal(await runCheck({ kind: "billing" }, probers), null); |
| 35 | assert.equal(await runCheck({ kind: "none" }, probers), null); |
| 36 | assert.equal((await runCheck({ kind: "billing" }, { ...probers, billing: async () => ({ version: 1 }) }))!.ok, true); |
| 37 | assert.equal((await runCheck({ kind: "billing" }, { ...probers, billing: async () => null }))!.error, "no price book"); |
| 38 | const mixed = await runCheck({ kind: "http", steps: [{ url: "https://a/" }, { url: "https://b/", expect: 401 }] }, probers); |
| 39 | assert.equal(mixed!.ok, false); |
| 40 | }); |
| 41 | |
| 42 | test("git storage is judged by how its calls went, and quiet is up", async () => { |
| 43 | const row = (calls: number, errors: number, rate_limited: number, rejected: number, ms_total: number) => ({ |
| 44 | store: "g1t", |
| 45 | calls, |
| 46 | errors, |
| 47 | rate_limited, |
| 48 | rejected, |
| 49 | ms_total, |
| 50 | }); |
| 51 | const report = (...stores: ReturnType<typeof row>[]) => ({ minutes: 5, stores }); |
| 52 | assert.deepEqual(judgeStorage(report()), { ok: true, ms: 0 }); |
| 53 | assert.deepEqual(judgeStorage(report(row(100, 1, 0, 0, 30_000))), { ok: true, ms: 300 }); |
| 54 | // A quarter or more failing, at least five: down. |
| 55 | const down = judgeStorage(report(row(10, 3, 0, 0, 1_000), row(10, 2, 0, 0, 1_000))); |
| 56 | assert.deepEqual([down.ok, down.error], [false, "25% of calls failed"]); |
| 57 | // Too few to tell. |
| 58 | assert.equal(judgeStorage(report(row(4, 4, 0, 0, 400))).ok, true); |
| 59 | // Refused by an open breaker: down. |
| 60 | assert.equal(judgeStorage(report(row(0, 0, 0, 3, 0))).ok, false); |
| 61 | // Rate limited: degraded, not down. |
| 62 | const limited = judgeStorage(report(row(100, 2, 2, 0, 10_000))); |
| 63 | assert.deepEqual([limited.ok, limited.degraded], [true, "Rate limited 2 times in 5 minutes"]); |
| 64 | const viaCheck = await runCheck({ kind: "storage" }, { fetch: answer(200), billing: null, storage: async () => report(row(1, 0, 0, 0, 5)) }); |
| 65 | assert.deepEqual(viaCheck, { ok: true, ms: 5 }); |
| 66 | assert.equal(await runCheck({ kind: "storage" }, { fetch: answer(200), billing: null }), null); |
| 67 | }); |