import { describe, expect, mock, test } from "bun:test";
import { Database } from "bun:sqlite";
const notified: string[] = [];
mock.module("../repos", () => ({ loadRepoById: async () => null }));
mock.module("./deliver", () => ({
notifyQuietly: async (input: { title: string }) => void notified.push(input.title),
}));
mock.module("./recipients", () => ({ accountAdmins: async () => ["u"], repoAdmins: async () => ["u"] }));
const { ACCOUNT_SCHEMA } = await import("../scoped-db/schema.gen");
const { ACCOUNT_SCHEMA_EXTRA } = await import("../scoped-db/schema-extra");
const { nextRunnerOffline, reportOfflineRunners } = await import("./runners");
const MINUTE = 60_000;
const NOW = 1_800_000_000_000;
function store() {
const db = new Database(":memory:");
for (const statement of [...ACCOUNT_SCHEMA, ...ACCOUNT_SCHEMA_EXTRA]) db.run(statement);
const sql = {
exec: (query: string, ...params: Array<string | number | null>) => {
const rows = db.query(query).all(...params) as never[];
return { toArray: () => rows };
},
};
return { db, sql };
}
describe("offline runners", () => {
test("each outage is reported once, and checking in again clears it", async () => {
const { db, sql } = store();
db.query(
"INSERT INTO runners (id, repo_id, owner_id, name, labels, token_hash, created_at, last_seen_at) VALUES ('r', NULL, 'org', 'box', '[]', 'h', 0, ?)",
).run(NOW - 2 * MINUTE);
expect(nextRunnerOffline(sql, NOW)).toBe(NOW + 8 * MINUTE);
await reportOfflineRunners(sql, NOW + 7 * MINUTE);
expect(notified).toEqual([]);
await reportOfflineRunners(sql, NOW + 11 * MINUTE);
await reportOfflineRunners(sql, NOW + 12 * MINUTE);