Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
269 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { components } from "./components.ts";
5import {
6 type DayRow,
7 barFor,
8 buildPage,
9 classify,
10 dayState,
11 effectiveState,
12 lastDays,
13 maintenanceState,
14 openOn,
15 percent,
16 recentIncidents,
17 summarize,
18 uptimeOf,
19 uptimeOver,
20} from "./model.ts";
21
22const VARS = {
23 SITE_URL: "https://g1t.sh",
24 API_URL: "https://api.g1t.sh",
25 MCP_URL: "https://mcp.g1t.sh",
26 DOCS_URL: "https://docs.g1t.sh",
27 PAGES_URL: "https://g1t.page",
28 PROBE_REPO: "flagon-io/g1t",
29};
30
31const row = (component: string, day: string, up: number, degraded = 0, down = 0): DayRow => ({
32 component,
33 day,
34 checks: up + degraded + down,
35 up,
36 degraded,
37 down,
38 latency_total: (up + degraded) * 100,
39 latency_count: up + degraded,
40});
41
42test("classify: fast is up, slow is degraded, failed is down, none is unmonitored", () => {
43 assert.equal(classify({ ok: true, ms: 84.4 }).state, "up");
44 assert.equal(classify({ ok: true, ms: 84.4 }).detail, "Answered in 84 ms");
45 assert.equal(classify({ ok: true, ms: 2000 }).state, "degraded");
46 assert.deepEqual(classify({ ok: false, ms: 5000, error: "timed out" }), { state: "down", detail: "Failed: timed out" });
47 assert.equal(classify(null).state, "unmonitored");
48});
49
50test("uptime rounds down, so one failure never reads as 100%", () => {
51 assert.equal(uptimeOf(1439, 1440), 99.93);
52 assert.equal(uptimeOf(99999, 100000), 99.99);
53 assert.equal(uptimeOf(10, 10), 100);
54 assert.equal(uptimeOf(0, 0), null);
55 assert.equal(percent(100), "100%");
56 assert.equal(percent(99.5), "99.50%");
57 assert.equal(percent(null), "No data");
58});
59
60test("a day's colour: a blip stays green, a bad hour is degraded, worse is down", () => {
61 assert.equal(dayState(null), "none");
62 assert.equal(dayState({ checks: 1440, up: 1439, degraded: 0, down: 1 }), "up");
63 assert.equal(dayState({ checks: 1440, up: 1380, degraded: 0, down: 60 }), "degraded");
64 assert.equal(dayState({ checks: 1440, up: 1000, degraded: 0, down: 440 }), "down");
65 // Answering, but slow much of the day.
66 assert.equal(dayState({ checks: 100, up: 60, degraded: 40, down: 0 }), "degraded");
67 // An incident colours the day at least as badly as its impact.
68 assert.equal(dayState({ checks: 1440, up: 1440, degraded: 0, down: 0 }, "down"), "down");
69 assert.equal(dayState(null, "degraded"), "degraded");
70});
71
72test("lastDays ends today, oldest first", () => {
73 const days = lastDays(new Date("2026-10-05T12:00:00Z"));
74 assert.equal(days.length, 90);
75 assert.equal(days.at(-1), "2026-10-05");
76 assert.equal(days[0], "2026-07-08");
77});
78
79test("an incident is on every day it was open", () => {
80 const incident = { started_at: "2026-10-03T23:30:00Z", resolved_at: "2026-10-04T00:10:00Z" };
81 assert.equal(openOn(incident, "2026-10-02"), false);
82 assert.equal(openOn(incident, "2026-10-03"), true);
83 assert.equal(openOn(incident, "2026-10-04"), true);
84 assert.equal(openOn(incident, "2026-10-05"), false);
85 assert.equal(openOn({ started_at: "2026-10-01T00:00:00Z", resolved_at: null }, "2026-10-05"), true);
86});
87
88test("bars and 90-day uptime come from the daily tally", () => {
89 const days = ["2026-10-03", "2026-10-04", "2026-10-05"];
90 const rows = [row("api", "2026-10-04", 1439, 0, 1), row("api", "2026-10-05", 600), row("git", "2026-10-05", 10)];
91 const bar = barFor("api", rows, [], days);
92 assert.deepEqual(
93 bar.map((d) => d.state),
94 ["none", "up", "up"],
95 );
96 assert.equal(bar[1]!.failed, 1);
97 assert.equal(bar[1]!.avg_ms, 100);
98 assert.equal(uptimeOver("api", rows), uptimeOf(2039, 2040));
99 assert.equal(uptimeOver("docs", rows), null);
100});
101
102test("a bar marks the days an incident on its part was open", () => {
103 const incident = {
104 id: "1",
105 title: "Clones failing",
106 impact: "down" as const,
107 status: "resolved" as const,
108 components: ["git"],
109 component_impacts: [{ key: "git", impact: "major_outage" as const }],
110 started_at: "2026-10-04T10:00:00Z",
111 resolved_at: "2026-10-04T11:00:00Z",
112 url: "https://status.g1t.sh/incidents/1",
113 postmortem_published_at: null,
114 updates: [],
115 };
116 const days = ["2026-10-04", "2026-10-05"];
117 const git = barFor("git", [row("git", "2026-10-04", 1440)], [incident], days);
118 assert.equal(git[0]!.state, "down");
119 assert.deepEqual(git[0]!.incidents, ["Clones failing"]);
120 assert.equal(barFor("api", [row("api", "2026-10-04", 1440)], [incident], days)[0]!.state, "up");
121});
122
123test("summarize: core down is a major outage, others partial, slow is degraded performance", () => {
124 const core = new Set(["site", "api"]);
125 const up = { key: "api", name: "API", state: "up" as const };
126 assert.equal(summarize([up], core).title, "All systems normal");
127 assert.equal(summarize([{ ...up, state: "down" }], core).title, "Major outage");
128 assert.equal(summarize([up, { key: "docs", name: "Documentation", state: "down" }], core).title, "Partial outage");
129 const slow = summarize([up, { key: "docs", name: "Documentation", state: "degraded" }], core);
130 assert.equal(slow.title, "Degraded performance");
131 assert.match(slow.line, /Documentation/);
132 assert.equal(summarize([{ key: "sandboxes", name: "Sandboxes", state: "unmonitored" }], core).state, "unknown");
133 const incident = summarize([up], core, [{ title: "Pushes failing", impact: "degraded", status: "identified" }]);
134 assert.equal(incident.title, "Partial outage");
135 assert.equal(incident.line, "Identified: Pushes failing.");
136});
137
138test("recent incidents: open ones and those resolved in 90 days, newest first", () => {
139 const now = new Date("2026-10-05T00:00:00Z");
140 const list = recentIncidents(
141 [
142 { id: "old", started_at: "2026-01-01T00:00:00Z", resolved_at: "2026-01-01T01:00:00Z" },
143 { id: "open", started_at: "2026-01-02T00:00:00Z", resolved_at: null },
144 { id: "new", started_at: "2026-10-01T00:00:00Z", resolved_at: "2026-10-01T01:00:00Z" },
145 ],
146 now,
147 );
148 assert.deepEqual(
149 list.map((i) => i.id),
150 ["new", "open"],
151 );
152});
153
154test("buildPage: parts with no check are unmonitored and have no uptime; staleness is noticed", () => {
155 const now = new Date("2026-10-05T12:00:00Z");
156 const parts = components(VARS, true);
157 const current = new Map(parts.map((p) => [p.key, { state: "up" as const, detail: "Answered in 80 ms", latency_ms: 80 }]));
158 const page = buildPage({
159 parts,
160 current,
161 checkedAt: "2026-10-05T11:59:30Z",
162 days: [row("api", "2026-10-05", 700)],
163 incidents: [],
164 now,
165 });
166 const sandboxes = page.report.components.find((c) => c.key === "sandboxes")!;
167 assert.equal(sandboxes.state, "unmonitored");
168 assert.equal(sandboxes.uptime_90d, null);
169 assert.equal(page.report.components.find((c) => c.key === "api")!.uptime_90d, 100);
170 assert.equal(page.report.overall.title, "All systems normal");
171 assert.equal(page.stale, false);
172 assert.equal(page.bars.api!.length, 90);
173 assert.equal(buildPage({ parts, current, checkedAt: "2026-10-05T11:00:00Z", days: [], incidents: [], now }).stale, true);
174});
175
176test("components: an installation without a host leaves that part off", () => {
177 const keys = components({ SITE_URL: "http://localhost:8787", API_URL: "http://localhost:8787/api", PROBE_REPO: "me/demo" }, false).map(
178 (c) => c.key,
179 );
180 assert.deepEqual(keys, ["site", "api", "git", "speed"]);
181 const bare = components({ SITE_URL: "http://g1t:8787" }, false);
182 assert.deepEqual(
183 bare.map((c) => c.key),
184 ["site"],
185 );
186 assert.equal(bare[0]!.check.kind === "http" && bare[0]!.check.steps.length, 1);
187 const all = components(VARS, true);
188 assert.deepEqual(
189 all.map((c) => c.key),
190 ["site", "api", "git", "speed", "mcp", "docs", "deployments", "sandboxes", "billing"],
191 );
192 const speed = all.find((c) => c.key === "speed")!;
193 assert.deepEqual(speed.check, { kind: "http", steps: [{ url: "https://g1t.sh/flagon-io/g1t", browser: true }, { url: "https://g1t.sh/explore", browser: true }] });
194 assert.equal(classify({ ok: true, ms: 900 }, speed.slowMs).state, "degraded");
195 assert.equal(classify({ ok: true, ms: 300 }, speed.slowMs).state, "up");
196 const git = all.find((c) => c.key === "git")!;
197 assert.deepEqual(git.check, { kind: "http", steps: [{ url: "https://g1t.sh/flagon-io/g1t.git/info/refs?service=git-upload-pack" }] });
198});
199
200test("a part's state: the worse of its check and open incidents; maintenance unless an incident says worse", () => {
201 assert.equal(effectiveState("up", [], false), "up");
202 assert.equal(effectiveState("up", ["partial_outage"], false), "partial");
203 assert.equal(effectiveState("down", ["degraded"], false), "down", "a failing check beats a milder report");
204 assert.equal(effectiveState("degraded", ["major_outage", "degraded"], false), "down", "the worst impact wins");
205 assert.equal(effectiveState("up", ["operational"], false), "up");
206 assert.equal(effectiveState("unmonitored", ["degraded"], false), "degraded", "an incident speaks for a part with no check");
207 assert.equal(effectiveState("down", [], true), "maintenance", "failing checks in a window are expected");
208 assert.equal(effectiveState("up", ["major_outage"], true), "down", "an incident during maintenance still shows");
209});
210
211test("maintenance moves with its window, and cancelled or completed stays put", () => {
212 const m = { state: "scheduled" as const, starts_at: "2026-10-05T12:00:00Z", ends_at: "2026-10-05T13:00:00Z" };
213 assert.equal(maintenanceState(m, new Date("2026-10-05T11:59:00Z")), "scheduled");
214 assert.equal(maintenanceState(m, new Date("2026-10-05T12:00:00Z")), "in_progress");
215 assert.equal(maintenanceState(m, new Date("2026-10-05T13:00:00Z")), "completed");
216 assert.equal(maintenanceState({ ...m, state: "in_progress" }, new Date("2026-10-05T11:00:00Z")), "in_progress", "started early by hand");
217 assert.equal(maintenanceState({ ...m, state: "cancelled" }, new Date("2026-10-05T12:30:00Z")), "cancelled");
218 assert.equal(maintenanceState({ ...m, state: "completed" }, new Date("2026-10-05T12:30:00Z")), "completed", "finished early by hand");
219});
220
221test("buildPage: incident impacts and maintenance reach the parts and the banner", () => {
222 const now = new Date("2026-10-05T12:30:00Z");
223 const parts = components(VARS, false);
224 const current = new Map(parts.map((p) => [p.key, { state: "up" as const, detail: "Answered in 80 ms", latency_ms: 80 }]));
225 current.set("docs", { state: "down", detail: "Failed: HTTP 502", latency_ms: null });
226 const maintenance = [
227 { id: "m1", title: "Docs move", message: "Moving docs.", components: ["docs"], starts_at: "2026-10-05T12:00:00Z", ends_at: "2026-10-05T13:00:00Z", state: "scheduled" as const, url: "", updates: [] },
228 { id: "m2", title: "Later", message: "Later.", components: ["api"], starts_at: "2026-10-06T12:00:00Z", ends_at: "2026-10-06T13:00:00Z", state: "scheduled" as const, url: "", updates: [] },
229 { id: "m3", title: "Called off", message: "No.", components: ["api"], starts_at: "2026-10-05T12:00:00Z", ends_at: "2026-10-05T13:00:00Z", state: "cancelled" as const, url: "", updates: [] },
230 ];
231 const quiet = buildPage({ parts, current, checkedAt: "2026-10-05T12:29:30Z", days: [], incidents: [], maintenance, now });
232 const docs = quiet.report.components.find((c) => c.key === "docs")!;
233 assert.equal(docs.state, "maintenance");
234 assert.equal(docs.check_state, "down");
235 assert.equal(quiet.report.overall.state, "maintenance");
236 assert.equal(quiet.report.overall.title, "Under maintenance");
237 assert.deepEqual(quiet.report.maintenance.map((m) => [m.id, m.state]), [["m1", "in_progress"], ["m2", "scheduled"]]);
238
239 const incident = {
240 id: "i1",
241 title: "API errors",
242 impact: "degraded" as const,
243 status: "identified" as const,
244 components: ["api"],
245 component_impacts: [{ key: "api", impact: "partial_outage" as const }],
246 started_at: "2026-10-05T12:10:00Z",
247 resolved_at: null,
248 url: "",
249 postmortem_published_at: null,
250 updates: [],
251 };
252 const busy = buildPage({ parts, current, checkedAt: "2026-10-05T12:29:30Z", days: [], incidents: [incident], maintenance, now });
253 assert.equal(busy.report.components.find((c) => c.key === "api")!.state, "partial");
254 assert.equal(busy.report.overall.title, "Partial outage");
255 assert.equal(busy.report.overall.line, "Identified: API errors.");
256 const resolved = buildPage({ parts, current, checkedAt: "2026-10-05T12:29:30Z", days: [], incidents: [{ ...incident, resolved_at: "2026-10-05T12:20:00Z" }], now });
257 assert.equal(resolved.report.components.find((c) => c.key === "api")!.state, "up", "a resolved incident no longer colours its part");
258});
259
260test("git storage is listed only with the repos service, and degraded says why", () => {
261 assert.equal(components(VARS, true).some((part) => part.key === "storage"), false);
262 const storage = components(VARS, true, true).find((part) => part.key === "storage");
263 assert.equal(storage?.check.kind, "storage");
264 assert.equal(storage?.core, false);
265 assert.deepEqual(classify({ ok: true, ms: 40, degraded: "Rate limited 2 times in 5 minutes" }), {
266 state: "degraded",
267 detail: "Rate limited 2 times in 5 minutes",
268 });
269});