diff --git a/packages/db/test/helpers/migrated-connection.ts b/packages/db/test/helpers/migrated-connection.ts index 6c8136d2df..63b57eb331 100644 --- a/packages/db/test/helpers/migrated-connection.ts +++ b/packages/db/test/helpers/migrated-connection.ts @@ -3,6 +3,25 @@ import type { DbConnection } from "../../src/index.js"; let migratedTemplate: Buffer | null = null; +function getMigratedTemplate(): Buffer { + if (migratedTemplate === null) { + const db = createConnection(":memory:"); + try { + migrate(db); + migratedTemplate = db.$client.serialize(); + } finally { + db.$client.close(); + } + } + + return migratedTemplate; +} + +/** Build the shared template outside a test's timeout budget. */ +export function prepareMigratedConnectionTemplate(): void { + getMigratedTemplate(); +} + /** * A fresh in-memory database with every migration applied, exactly as * `createConnection(":memory:")` followed by `migrate(db)` leaves it. The @@ -10,13 +29,10 @@ let migratedTemplate: Buffer | null = null; * call opens an independent copy of that image. Replaying the 100+ * migrations costs ~57ms, which the data suites paid once per test. * - * Suites that exercise `migrate` itself keep calling it directly. + * Tests that exercise the initial migration keep calling `migrate` directly. + * Migration tests may use this only for current-schema setup that they rewind + * before exercising a later `migrate` boundary. */ export function createMigratedConnection(): DbConnection { - if (migratedTemplate === null) { - const db = createConnection(":memory:"); - migrate(db); - migratedTemplate = db.$client.serialize(); - } - return createConnection(migratedTemplate); + return createConnection(getMigratedTemplate()); } diff --git a/packages/db/test/migrate.test.ts b/packages/db/test/migrate.test.ts index bc3966d342..bd06dce395 100644 --- a/packages/db/test/migrate.test.ts +++ b/packages/db/test/migrate.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it, vi } from "vitest"; import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -17,6 +17,10 @@ import { type DbConnection, type MigrationWarningLogger, } from "../src/index.js"; +import { + createMigratedConnection, + prepareMigratedConnectionTemplate, +} from "./helpers/migrated-connection.js"; type InsertMigrationParameters = [string, number]; type DeleteMigrationParameters = [number]; @@ -1451,6 +1455,13 @@ function deleteDeferredCleanupMigrationRows(db: DbConnection): void { } describe("migrate", () => { + beforeAll(() => { + // The large-value replay cases need a current database only as a rewind + // fixture. Build that shared image outside either case's timeout budget; + // each case still exercises the real migrate() boundary after rewinding. + prepareMigratedConnectionTemplate(); + }); + it("backfills the first checkout commit component for every artifact shape", () => { const db = createConnection(":memory:"); const commit = "d".repeat(40); @@ -4305,10 +4316,9 @@ describe("migrate", () => { }); it("skips legacy large event value round trip when values are already inline", () => { - const db = createConnection(":memory:"); + const db = createMigratedConnection(); try { - migrate(db); dropRewindAddedTables(db); seedEventLargeValueBackfillThread(db); const values = seedEventLargeValueBackfillEvents(db); @@ -4359,10 +4369,9 @@ describe("migrate", () => { }); it("restores legacy large event values to inline payloads", () => { - const db = createConnection(":memory:"); + const db = createMigratedConnection(); try { - migrate(db); dropRewindAddedTables(db); seedEventLargeValueBackfillThread(db); const values = seedEventLargeValueBackfillEvents(db);