Files
HealthLog/src/lib/boot/__tests__/time-zone-check.test.ts
T
Marc-André Bombeck cefc8c15c1 fix(db): pin every connection to UTC and say so at boot when it is not
Stored times are UTC in timestamp columns without a zone, and Postgres
reads now(), CURRENT_TIMESTAMP and offset-free timestamptz parameters
through the session time zone. On a database whose default is not UTC
every expiry check ran off by the offset. The Prisma pool, pg-boss, the
lock and the maintenance connections now send TimeZone=UTC as a startup
option, or SET it on connect when the startup options are disabled for
a pooler. A boot check reads SHOW TimeZone and warns on anything else.
2026-10-11 12:15:03 +02:00

60 lines
2.0 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import {
checkSessionTimeZone,
isUtcTimeZone,
runBootTimeZoneCheck,
} from "../time-zone-check";
function clientAnswering(rows: unknown) {
return { $queryRawUnsafe: vi.fn().mockResolvedValue(rows) };
}
describe("boot time zone check", () => {
afterEach(() => vi.restoreAllMocks());
it("accepts the spellings Postgres reports for UTC", () => {
for (const name of ["UTC", "Etc/UTC", "utc", "UCT", "Zulu"]) {
expect(isUtcTimeZone(name)).toBe(true);
}
for (const name of ["Europe/Berlin", "GMT+1", "America/New_York"]) {
expect(isUtcTimeZone(name)).toBe(false);
}
});
it("stays quiet on a UTC session", async () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const client = clientAnswering([{ TimeZone: "UTC" }]);
expect(await runBootTimeZoneCheck(client)).toEqual({
state: "utc",
timeZone: "UTC",
});
expect(client.$queryRawUnsafe).toHaveBeenCalledWith("SHOW TimeZone");
expect(warn).not.toHaveBeenCalled();
});
it("warns, naming the zone and the fix, on any other zone", async () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const outcome = await runBootTimeZoneCheck(
clientAnswering([{ TimeZone: "Europe/Berlin" }]),
);
expect(outcome).toEqual({ state: "mismatch", timeZone: "Europe/Berlin" });
expect(warn).toHaveBeenCalledTimes(1);
expect(warn.mock.calls[0][0]).toContain('"Europe/Berlin"');
expect(warn.mock.calls[0][0]).toContain("SET timezone TO 'UTC'");
});
it("never throws when the database cannot answer", async () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const client = {
$queryRawUnsafe: vi.fn().mockRejectedValue(new Error("down")),
};
expect(await checkSessionTimeZone(client)).toEqual({
state: "error",
message: "down",
});
await runBootTimeZoneCheck(client);
expect(warn.mock.calls[0][0]).toContain("skipped: down");
});
});