Files
HealthLog/tests/integration/setup.ts
T
Marc-André BombeckandClaude Opus 4.7 5d1ece1fd5 feat(db): HostMetric model for host-load sampling
Adds the per-minute snapshot table that backs the new admin host-load
chart above /admin/system-status. One row per minute, captured by the
pg-boss sampler in the next commit, with 7-day retention enforced
inside the worker so the table stays under a few thousand rows.

Schema mirrors what the chart needs:
  - load_avg_1/5/15 (DOUBLE PRECISION) — os.loadavg() output
  - mem_used_bytes / mem_total_bytes — derived from os.totalmem() and
    os.freemem(), kept as raw bytes so the API can compute either a
    percent or a MiB delta downstream
  - disk_read_bytes / disk_write_bytes — nullable cumulative byte
    counters from /proc/diskstats. NULL on macOS/Windows dev hosts;
    Linux production picks them up automatically. The API endpoint
    converts deltas to bytes-per-second between samples

Indexed by captured_at so the "last 2 hours" query stays index-only.

Migration 0032_host_metric. integration setup.ts adds host_metrics to
the truncate list so testcontainers stays clean across runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 23:46:56 +02:00

74 lines
2.3 KiB
TypeScript

/**
* Per-test helpers for the integration suite. The Postgres testcontainer
* is started ONCE in `global-setup.ts` and torn down at the end of the
* run, so test files only need:
*
* import { getPrismaClient, truncateAllTables } from "./setup";
*
* beforeEach(async () => { await truncateAllTables(getPrismaClient()); });
*
* No beforeAll(startTestDb) / afterAll(stopTestDb) is needed — the
* container is alive whenever the test file is loaded, and Vitest's
* worker inherits `process.env.DATABASE_URL` from globalSetup so the
* application's Prisma singleton (`src/lib/db.ts`) connects to the
* testcontainer transparently.
*/
import { prisma } from "@/lib/db";
import type { PrismaClient } from "@/generated/prisma/client";
/**
* The application's Prisma singleton. Tests use this so any code
* imported via `await import("@/lib/...")` shares the exact same client
* instance — no risk of a divergent connection pool reading stale
* truncation state.
*/
export function getPrismaClient(): PrismaClient {
return prisma;
}
/**
* Truncate every user-facing table in dependency-safe order using
* `TRUNCATE … RESTART IDENTITY CASCADE`. Call from beforeEach() to make
* tests independent. The list mirrors `prisma/schema.prisma` minus
* prisma-internal tables (_prisma_migrations).
*/
export async function truncateAllTables(client: PrismaClient): Promise<void> {
// CASCADE means we only need to enumerate the tables; FK chains are
// handled by Postgres. Listed alphabetically for diff stability.
const tables = [
"api_tokens",
"app_settings",
"audit_logs",
"auth_challenges",
"data_backups",
"devices",
"feedback",
"host_metrics",
"idempotency_keys",
"integration_statuses",
"measurements",
"medication_intake_events",
"medication_schedules",
"medications",
"mood_entries",
"notification_channels",
"notification_preferences",
"passkeys",
"push_subscriptions",
"rate_limits",
"refresh_tokens",
"reminder_phase_configs",
"sessions",
"telegram_reminder_messages",
"telegram_scheduled_deletions",
"user_achievements",
"users",
"withings_connections",
];
const quoted = tables.map((t) => `"${t}"`).join(", ");
await client.$executeRawUnsafe(
`TRUNCATE TABLE ${quoted} RESTART IDENTITY CASCADE;`,
);
}