1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import { describe, expect, it } from "bun:test";
import { uptimePctFromIncidents, UPTIME_WINDOW_MS } from "../routes/status";
const NOW = new Date("2026-07-28T12:00:00.000Z").getTime();
const HOUR = 3_600_000;
describe("no incidents means full uptime", () => {
it("reports 100 with an empty incident list", () => {
expect(uptimePctFromIncidents([], NOW)).toBe(100);
});
it("ignores incidents that ended before the window", () => {
const old = [
{
startedAt: new Date(NOW - 40 * HOUR),
resolvedAt: new Date(NOW - 30 * HOUR),
},
];
expect(uptimePctFromIncidents(old, NOW)).toBe(100);
});
});
describe("downtime is subtracted accurately", () => {
it("a 1h resolved incident costs 1/24th", () => {
const rows = [
{ startedAt: new Date(NOW - 5 * HOUR), resolvedAt: new Date(NOW - 4 * HOUR) },
];
const pct = uptimePctFromIncidents(rows, NOW);
expect(pct).toBeCloseTo((23 / 24) * 100, 5);
});
it("an unresolved incident counts as ongoing up to now", () => {
const rows = [{ startedAt: new Date(NOW - 2 * HOUR), resolvedAt: null }];
expect(uptimePctFromIncidents(rows, NOW)).toBeCloseTo((22 / 24) * 100, 5);
});
it("clamps an incident that began before the window to the window edge", () => {
const rows = [
{ startedAt: new Date(NOW - 30 * HOUR), resolvedAt: new Date(NOW - 20 * HOUR) },
];
expect(uptimePctFromIncidents(rows, NOW)).toBeCloseTo((20 / 24) * 100, 5);
});
});
describe("overlapping incidents are merged, not double-counted", () => {
it("two fully overlapping incidents count once", () => {
const rows = [
{ startedAt: new Date(NOW - 6 * HOUR), resolvedAt: new Date(NOW - 4 * HOUR) },
{ startedAt: new Date(NOW - 5 * HOUR), resolvedAt: new Date(NOW - 4 * HOUR) },
];
expect(uptimePctFromIncidents(rows, NOW)).toBeCloseTo((22 / 24) * 100, 5);
});
it("partially overlapping incidents merge into one span", () => {
const rows = [
{ startedAt: new Date(NOW - 6 * HOUR), resolvedAt: new Date(NOW - 4 * HOUR) },
{ startedAt: new Date(NOW - 5 * HOUR), resolvedAt: new Date(NOW - 3 * HOUR) },
];
expect(uptimePctFromIncidents(rows, NOW)).toBeCloseTo((21 / 24) * 100, 5);
});
it("never goes below 0 even if incidents blanket the window many times over", () => {
const rows = Array.from({ length: 10 }, () => ({
startedAt: new Date(NOW - 48 * HOUR),
resolvedAt: null,
}));
expect(uptimePctFromIncidents(rows, NOW)).toBe(0);
});
it("is order-independent", () => {
const a = { startedAt: new Date(NOW - 3 * HOUR), resolvedAt: new Date(NOW - 2 * HOUR) };
const b = { startedAt: new Date(NOW - 9 * HOUR), resolvedAt: new Date(NOW - 8 * HOUR) };
expect(uptimePctFromIncidents([a, b], NOW)).toBeCloseTo(
uptimePctFromIncidents([b, a], NOW),
10
);
});
});
describe("malformed rows do not corrupt the figure", () => {
it("skips unparseable timestamps rather than producing NaN", () => {
const rows = [
{ startedAt: "not-a-date", resolvedAt: null },
{ startedAt: new Date(NOW - 2 * HOUR), resolvedAt: new Date(NOW - 1 * HOUR) },
];
const pct = uptimePctFromIncidents(rows, NOW);
expect(Number.isFinite(pct)).toBe(true);
expect(pct).toBeCloseTo((23 / 24) * 100, 5);
});
it("skips a resolvedAt earlier than its startedAt", () => {
const rows = [
{ startedAt: new Date(NOW - 1 * HOUR), resolvedAt: new Date(NOW - 5 * HOUR) },
];
expect(uptimePctFromIncidents(rows, NOW)).toBe(100);
});
});
describe("window constant", () => {
it("is 24 hours", () => {
expect(UPTIME_WINDOW_MS).toBe(24 * 60 * 60 * 1000);
});
});
|