Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
TypeScript
at incident-api
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582import { db, eq } from "@openstatus/db";import { expect } from "@std/expect";import { afterAll, beforeAll, beforeEach, describe, test,} from "@std/testing/bdd";
import { app } from "../../index";
const testRedisStore = (globalThis as Record<string, unknown>) .__testRedisStore as Map<string, string> | undefined;import { monitorIncidentTable, maintenance, monitor, page, pageComponent, statusReport,} from "@openstatus/db/src/schema";
/** * Status Route Tests: Verify the status route uses pageComponents with single DB call * * These tests verify that the /public/status/:slug endpoint: * - Uses pageComponents instead of monitorsToPages * - Makes a single database query * - Correctly filters for active monitors only * - Correctly identifies ongoing incidents * - Correctly identifies unresolved status reports * - Correctly identifies ongoing maintenances * - Returns correct status based on the Tracker logic */
const TEST_PREFIX = "status-test";let testPageId: number;let testMonitorId: number;let testMonitor2Id: number;let testIncidentId: number;let testStatusReportId: number;let testMaintenanceId: number;
beforeAll(async () => { // Clean up any existing test data by slug/name before creating new ones await db.delete(page).where(eq(page.slug, `${TEST_PREFIX}-page`)); await db.delete(page).where(eq(page.slug, `${TEST_PREFIX}-private-page`)); await db.delete(page).where(eq(page.slug, `${TEST_PREFIX}-cache-test`)); await db.delete(monitor).where(eq(monitor.name, `${TEST_PREFIX}-monitor-1`)); await db.delete(monitor).where(eq(monitor.name, `${TEST_PREFIX}-monitor-2`));
// Create test page const testPage = await db .insert(page) .values({ workspaceId: 1, title: "Status Test Page", description: "A test page for status route tests", slug: `${TEST_PREFIX}-page`, customDomain: "", accessType: "public", }) .returning() .get(); testPageId = testPage.id;
// Create first test monitor (active) const testMonitor = await db .insert(monitor) .values({ workspaceId: 1, name: `${TEST_PREFIX}-monitor-1`, url: "https://status-test-1.example.com", periodicity: "1m", active: true, regions: "ams", jobType: "http", }) .returning() .get(); testMonitorId = testMonitor.id;
// Create second test monitor (inactive) const testMonitor2 = await db .insert(monitor) .values({ workspaceId: 1, name: `${TEST_PREFIX}-monitor-2`, url: "https://status-test-2.example.com", periodicity: "1m", active: false, // Inactive monitor regions: "ams", jobType: "http", }) .returning() .get(); testMonitor2Id = testMonitor2.id;
// Create page components for both monitors await db.insert(pageComponent).values({ workspaceId: 1, pageId: testPageId, monitorId: testMonitorId, type: "monitor", name: `${TEST_PREFIX}-monitor-1`, order: 1, });
await db.insert(pageComponent).values({ workspaceId: 1, pageId: testPageId, monitorId: testMonitor2Id, type: "monitor", name: `${TEST_PREFIX}-monitor-2`, order: 2, });});
beforeEach(() => { testRedisStore?.clear();});
afterAll(async () => { // Clean up test data if (testIncidentId) { await db .delete(monitorIncidentTable) .where(eq(monitorIncidentTable.id, testIncidentId)) .catch(() => {}); } if (testStatusReportId) { await db .delete(statusReport) .where(eq(statusReport.id, testStatusReportId)) .catch(() => {}); } if (testMaintenanceId) { await db .delete(maintenance) .where(eq(maintenance.id, testMaintenanceId)) .catch(() => {}); } await db .delete(pageComponent) .where(eq(pageComponent.pageId, testPageId)) .catch(() => {}); await db .delete(page) .where(eq(page.id, testPageId)) .catch(() => {}); await db .delete(monitor) .where(eq(monitor.id, testMonitorId)) .catch(() => {}); await db .delete(monitor) .where(eq(monitor.id, testMonitor2Id)) .catch(() => {});});
describe("Status Route: Basic functionality", () => { test("returns operational status for page with no incidents", async () => { const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("operational"); });
test("returns unknown status for non-existent page", async () => { const res = await app.request("/public/status/non-existent-page");
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("unknown"); });
test("returns unknown status for non-public page", async () => { // Create a private page const privatePage = await db .insert(page) .values({ workspaceId: 1, title: "Private Test Page", description: "A private test page", slug: `${TEST_PREFIX}-private-page`, customDomain: "", accessType: "password", password: "secret", }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-private-page`);
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("unknown");
// Clean up await db.delete(page).where(eq(page.id, privatePage.id)); });});
describe("Status Route: Active monitor filtering", () => { test("only considers active monitors for status calculation", async () => { // Create an incident for the inactive monitor const inactiveIncident = await db .insert(monitorIncidentTable) .values({ monitorId: testMonitor2Id, title: "Inactive Monitor Incident", status: "investigating", }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); // Status should still be operational because the monitor is inactive expect(data.status).toBe("operational");
// Clean up await db .delete(monitorIncidentTable) .where(eq(monitorIncidentTable.id, inactiveIncident.id)); });});
describe("Status Route: Incident detection", () => { test("returns incident status with ongoing incident", async () => { // Create an ongoing incident for the active monitor const incident = await db .insert(monitorIncidentTable) .values({ monitorId: testMonitorId, title: "Test Incident", status: "investigating", // resolvedAt is null, meaning it's ongoing }) .returning() .get(); testIncidentId = incident.id;
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("incident");
// Clean up await db .delete(monitorIncidentTable) .where(eq(monitorIncidentTable.id, testIncidentId)); testIncidentId = 0; });
test("ignores resolved incidents", async () => { // First clean up the ongoing incident from previous test if it still exists if (testIncidentId) { await db .delete(monitorIncidentTable) .where(eq(monitorIncidentTable.id, testIncidentId)) .catch(() => {}); testIncidentId = 0; }
// Create a resolved incident const resolvedIncident = await db .insert(monitorIncidentTable) .values({ monitorId: testMonitorId, title: "Resolved Incident", status: "resolved", resolvedAt: new Date(), }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); // Status should be operational because the incident is resolved expect(data.status).toBe("operational");
// Clean up await db .delete(monitorIncidentTable) .where(eq(monitorIncidentTable.id, resolvedIncident.id)); });});
describe("Status Route: Status report detection", () => { test("returns degraded_performance status with unresolved status report", async () => { // Create an unresolved status report const report = await db .insert(statusReport) .values({ workspaceId: 1, pageId: testPageId, title: "Test Status Report", status: "investigating", }) .returning() .get(); testStatusReportId = report.id;
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("degraded_performance");
// Clean up await db .delete(statusReport) .where(eq(statusReport.id, testStatusReportId)); testStatusReportId = 0; });
test("ignores resolved status reports", async () => { // First clean up the ongoing status report from previous test if it still exists if (testStatusReportId) { await db .delete(statusReport) .where(eq(statusReport.id, testStatusReportId)) .catch(() => {}); testStatusReportId = 0; }
// Create a resolved status report const resolvedReport = await db .insert(statusReport) .values({ workspaceId: 1, pageId: testPageId, title: "Resolved Status Report", status: "resolved", }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); // Status should be operational because the report is resolved expect(data.status).toBe("operational");
// Clean up await db.delete(statusReport).where(eq(statusReport.id, resolvedReport.id)); });});
describe("Status Route: Maintenance detection", () => { test("returns under_maintenance status with ongoing maintenance", async () => { // Create an ongoing maintenance const now = new Date(); const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000); const oneHourFromNow = new Date(now.getTime() + 60 * 60 * 1000);
const maint = await db .insert(maintenance) .values({ workspaceId: 1, pageId: testPageId, title: "Test Maintenance", message: "Ongoing maintenance", from: oneHourAgo, to: oneHourFromNow, }) .returning() .get(); testMaintenanceId = maint.id;
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); expect(data.status).toBe("under_maintenance");
// Clean up await db.delete(maintenance).where(eq(maintenance.id, testMaintenanceId)); testMaintenanceId = 0; });
test("ignores past maintenances", async () => { // First clean up the ongoing maintenance from previous test if it still exists if (testMaintenanceId) { await db .delete(maintenance) .where(eq(maintenance.id, testMaintenanceId)) .catch(() => {}); testMaintenanceId = 0; }
// Create a past maintenance const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000); const oneDayAgo = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000);
const pastMaint = await db .insert(maintenance) .values({ workspaceId: 1, pageId: testPageId, title: "Past Maintenance", message: "Past maintenance", from: twoDaysAgo, to: oneDayAgo, }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); // Status should be operational because the maintenance is in the past expect(data.status).toBe("operational");
// Clean up await db.delete(maintenance).where(eq(maintenance.id, pastMaint.id)); });
test("ignores future maintenances", async () => { // First clean up any ongoing maintenance from previous test if it still exists if (testMaintenanceId) { await db .delete(maintenance) .where(eq(maintenance.id, testMaintenanceId)) .catch(() => {}); testMaintenanceId = 0; }
// Create a future maintenance const oneDayFromNow = new Date(Date.now() + 1 * 24 * 60 * 60 * 1000); const twoDaysFromNow = new Date(Date.now() + 2 * 24 * 60 * 60 * 1000);
const futureMaint = await db .insert(maintenance) .values({ workspaceId: 1, pageId: testPageId, title: "Future Maintenance", message: "Future maintenance", from: oneDayFromNow, to: twoDaysFromNow, }) .returning() .get();
const res = await app.request(`/public/status/${TEST_PREFIX}-page`);
expect(res.status).toBe(200);
const data = await res.json(); // Status should be operational because the maintenance is in the future expect(data.status).toBe("operational");
// Clean up await db.delete(maintenance).where(eq(maintenance.id, futureMaint.id)); });});
describe("Status Route: Cache functionality", () => { test("returns cached status on second request if cache is available", async () => { const slug = `${TEST_PREFIX}-cache-test`;
// Create a test page for cache testing const cachePage = await db .insert(page) .values({ workspaceId: 1, title: "Cache Test Page", description: "A test page for cache testing", slug, customDomain: "", accessType: "public", }) .returning() .get();
// First request should hit the database const res1 = await app.request(`/public/status/${slug}`); expect(res1.status).toBe(200); const data1 = await res1.json(); expect(data1.status).toBe("operational"); expect(res1.headers.get("OpenStatus-Cache")).toBeNull();
// Second request may hit the cache if Redis is configured const res2 = await app.request(`/public/status/${slug}`); expect(res2.status).toBe(200); const data2 = await res2.json(); expect(data2.status).toBe("operational"); // Cache header may be "HIT" if Redis is available, or null if not const cacheHeader = res2.headers.get("OpenStatus-Cache"); if (cacheHeader !== null) { expect(cacheHeader).toBe("HIT"); }
// Clean up await db.delete(page).where(eq(page.id, cachePage.id)); });});
describe("Status Route: cache key isolation", () => { test("never serves a foreign redis key as a status", async () => { for (const key of ["1-daily-stats", "telegram:workspace_token:1"]) { testRedisStore?.set(key, JSON.stringify("leaked")); const res = await app.request( `/public/status/${encodeURIComponent(key)}`, ); expect(await res.json()).toEqual({ status: "unknown" }); } });
test("a page slug shaped like a stats key leaves that key untouched", async () => { const slug = "987654-daily-stats"; await db.delete(page).where(eq(page.slug, slug)); const collidingPage = await db .insert(page) .values({ workspaceId: 1, title: "Collision Test Page", description: "", slug, customDomain: "", accessType: "public", }) .returning() .get();
const statsKey = "stats:monitor:987654:daily"; testRedisStore?.set(statsKey, "cached-stats");
const res = await app.request(`/public/status/${slug}`); expect((await res.json()).status).toBe("operational"); expect(testRedisStore?.has(slug)).toBe(false); expect(testRedisStore?.get(statsKey)).toBe("cached-stats");
await db.delete(page).where(eq(page.id, collidingPage.id)); });
test("a protected page is never written to the cache", async () => { const slug = `${TEST_PREFIX}-uncached-private`; await db.delete(page).where(eq(page.slug, slug)); const privatePage = await db .insert(page) .values({ workspaceId: 1, title: "Uncached Private Page", description: "", slug, customDomain: "", accessType: "password", password: "secret", }) .returning() .get();
const res = await app.request(`/public/status/${slug}`); expect(await res.json()).toEqual({ status: "unknown" }); expect(testRedisStore?.has(`status:page:${slug}`)).toBe(false);
await db.delete(page).where(eq(page.id, privatePage.id)); });});