Files
Announcements/server/test/storage-health.test.js
T

106 lines
3.3 KiB
JavaScript

const test = require("node:test");
const assert = require("node:assert/strict");
const express = require("express");
const { openDatabase } = require("../src/database");
const { runMigrations } = require("../src/database/migrate");
const {
createDetailedHealthRouter,
createHealthRouter,
} = require("../src/health/routes");
function config() {
return {
environment: "test",
host: "127.0.0.1",
port: 0,
timeZone: "America/Chicago",
trustProxy: true,
database: { path: ":memory:" },
storage: {
endpoint: "http://private-storage:8333",
region: "us-east-1",
bucket: "announcements-v2",
accessKeyId: "must-not-leak",
secretAccessKey: "must-not-leak-either",
forcePathStyle: true,
},
processing: {
tempDirectory: "/tmp/announcements-uploads",
maxFileBytes: 1024,
maxFiles: 2,
maxInputPixels: 1000,
},
mqtt: { url: null },
notifications: { homeAssistantWebhookUrl: null },
};
}
async function withServer(storage, callback) {
const database = openDatabase({ path: ":memory:", busyTimeoutMs: 1000 });
const migrations = runMigrations(database);
const lifecycle = { ready: true };
const app = express();
const options = { config: config(), database, lifecycle, migrations, storage };
app.use("/health", createHealthRouter(options));
app.use("/api/health", createDetailedHealthRouter(options));
const server = app.listen(0, "127.0.0.1");
await new Promise((resolve) => server.once("listening", resolve));
try {
await callback(`http://127.0.0.1:${server.address().port}`);
} finally {
await new Promise((resolve) => server.close(resolve));
database.close();
}
}
test("storage degradation is reported but does not fail API readiness", async () => {
const storage = {
health() {
return {
status: "degraded",
checkedAt: "2026-08-16T12:00:00.000Z",
lastSuccessAt: "2026-08-16T11:59:00.000Z",
code: "STORAGE_UNAVAILABLE",
};
},
};
await withServer(storage, async (baseUrl) => {
const ready = await fetch(`${baseUrl}/health/ready`);
const readyBody = await ready.json();
assert.equal(ready.status, 200);
assert.equal(readyBody.status, "ready");
assert.equal(readyBody.checks.storage, "degraded");
const detailed = await fetch(`${baseUrl}/api/health`);
const detailedBody = await detailed.json();
assert.equal(detailed.status, 200);
assert.equal(detailedBody.status, "degraded");
assert.equal(detailedBody.services.storage.status, "degraded");
assert.equal(
detailedBody.services.storage.lastSuccessAt,
"2026-08-16T11:59:00.000Z",
);
assert.equal(detailedBody.services.storage.code, "STORAGE_UNAVAILABLE");
assert.doesNotMatch(JSON.stringify(detailedBody), /must-not-leak/);
assert.doesNotMatch(JSON.stringify(detailedBody), /private-storage/);
});
});
test("healthy storage produces healthy detailed status", async () => {
const storage = {
health() {
return { status: "healthy", checkedAt: "2026-08-16T12:00:00.000Z" };
},
};
await withServer(storage, async (baseUrl) => {
const detailed = await fetch(`${baseUrl}/api/health`);
const body = await detailed.json();
assert.equal(detailed.status, 200);
assert.equal(body.status, "ok");
assert.equal(body.services.storage.status, "healthy");
});
});