Files
HealthLog/src/components/admin/__tests__/offhost-backups-section.test.tsx
T
Marc-André Bombeck 25f0310596 feat(backups): tell an empty ledger apart from an empty bucket
On the release that adds the ledger the table is empty, so on a host that has
been uploading nightly for months every account read Never, under a sentence
saying no copy had ever reached the bucket. That sentence is untrue on exactly
the morning an operator opens the new card for the first time, and it is a
claim the host cannot make: what is empty is the record, not the bucket.

The run now records every account it walks, not only the ones an object came
of. A walk that produced nothing moves the attempt instant and leaves the
success columns alone, so the two cases separate: no row at all is no record
yet, a row without a success is never. Never now means what the word says —
a run looked at this account and has never put anything there.

The card names the last check on the never row, so the state is a fact with a
timestamp rather than an assertion. Runbook and all seven bundles carry the
same two sentences. The integration file proves both arms against real
Postgres, including that a failed run leaves the previous good copy on the
row.
2026-09-10 10:15:31 +02:00

113 lines
3.5 KiB
TypeScript

/**
* The off-host card paints what the response says, including the case an
* operator most needs stated out loud: this host is not sending anything
* anywhere. A card that renders an empty list on an unconfigured host reads
* as "no problems".
*/
import { describe, expect, it, vi } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import type { BackupsList } from "@/types/backups";
const queryResult = vi.hoisted(() => ({
current: {
data: null as BackupsList | null,
isLoading: false,
isError: false,
},
}));
vi.mock("@tanstack/react-query", () => ({
useQuery: () => ({ ...queryResult.current, refetch: vi.fn() }),
}));
import { I18nProvider } from "@/lib/i18n/context";
import { OffhostBackupsSection } from "../offhost-backups-section";
function render(data: BackupsList["offhost"] | null): string {
queryResult.current = {
data:
data === null
? null
: ({
rows: [],
retentionDays: 90,
schedule: null,
offhost: data,
} as unknown as BackupsList),
isLoading: false,
isError: false,
};
return renderToStaticMarkup(
<I18nProvider initialLocale="en">
<OffhostBackupsSection />
</I18nProvider>,
);
}
describe("<OffhostBackupsSection>", () => {
it("says off-host backup is not configured rather than showing an empty list", () => {
const html = render({ configured: false, periodHours: 24, rows: [] });
expect(html).toContain("Off-host backup is not configured");
expect(html).not.toContain('data-slot="offhost-backup-rows"');
});
it("paints one row per account with its verdict", () => {
const html = render({
configured: true,
periodHours: 24,
rows: [
{
userId: "u1",
username: "account-one",
lastAttemptAt: "2026-09-10T06:00:00.000Z",
lastSuccessAt: "2026-09-10T06:00:00.000Z",
sizeBytes: 4096,
ageHours: 3,
freshness: "fresh",
},
{
userId: "u2",
username: "account-two",
lastAttemptAt: "2026-09-06T06:00:00.000Z",
lastSuccessAt: "2026-09-06T06:00:00.000Z",
sizeBytes: 2048,
ageHours: 99,
freshness: "stale",
},
{
userId: "u3",
username: "account-three",
lastAttemptAt: "2026-09-10T02:30:00.000Z",
lastSuccessAt: null,
sizeBytes: null,
ageHours: null,
freshness: "never",
},
{
userId: "u4",
username: "account-four",
lastAttemptAt: null,
lastSuccessAt: null,
sizeBytes: null,
ageHours: null,
freshness: "unknown",
},
],
});
expect(html).toContain('data-offhost-freshness="fresh"');
expect(html).toContain('data-offhost-freshness="stale"');
expect(html).toContain('data-offhost-freshness="never"');
expect(html).toContain('data-offhost-freshness="unknown"');
expect(html).toContain("account-two");
// The account a run walked and found nothing for says that, with the
// instant it was checked.
expect(html).toContain("Nothing has landed for this account");
// The account no run has recorded says THAT — not "never", which would
// claim the bucket is empty on the strength of an empty ledger.
expect(html).toContain("No nightly run has recorded this account yet");
// Never the bucket's own coordinates.
expect(html).not.toMatch(/secret|access[- ]key/i);
});
});