File size: 2,359 Bytes
96e86e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import {
  applyPendingMigrations,
  ensurePostgresDatabase,
} from "./client.js";
import {
  getAvailablePort,
  prepareEmbeddedPostgresTestSupport,
  readCachedEmbeddedPostgresTestSupport,
  removeDataDirWithRetries,
  startManagedEmbeddedPostgres,
  type EmbeddedPostgresTestSupport,
} from "./embedded-postgres-manager.js";

export type EmbeddedPostgresTestDatabase = {
  connectionString: string;
  cleanup(): Promise<void>;
};

export type { EmbeddedPostgresTestSupport } from "./embedded-postgres-manager.js";

let embeddedPostgresSupportPromise: Promise<EmbeddedPostgresTestSupport> | null = null;

function formatEmbeddedPostgresError(error: unknown): string {
  if (error instanceof Error && error.message.length > 0) return error.message;
  if (typeof error === "string" && error.length > 0) return error;
  return "embedded Postgres startup failed";
}

export async function getEmbeddedPostgresTestSupport(): Promise<EmbeddedPostgresTestSupport> {
  if (!embeddedPostgresSupportPromise) {
    embeddedPostgresSupportPromise = (async () => {
      const cached = await readCachedEmbeddedPostgresTestSupport();
      return cached?.supported ? cached : await prepareEmbeddedPostgresTestSupport();
    })();
  }
  return await embeddedPostgresSupportPromise;
}

export async function startEmbeddedPostgresTestDatabase(
  tempDirPrefix: string,
): Promise<EmbeddedPostgresTestDatabase> {
  const dataDir = await fs.mkdtemp(path.join(os.tmpdir(), tempDirPrefix));
  const preferredPort = await getAvailablePort();

  try {
    const handle = await startManagedEmbeddedPostgres({
      dataDir,
      preferredPort,
      registerTestInstance: true,
    });

    await ensurePostgresDatabase(handle.adminConnectionString, "paperclip");
    const connectionString = handle.connectionStringFor("paperclip");
    await applyPendingMigrations(connectionString);

    return {
      connectionString,
      cleanup: async () => {
        await handle.stop().catch(() => undefined);
        await removeDataDirWithRetries(dataDir);
      },
    };
  } catch (error) {
    await removeDataDirWithRetries(dataDir).catch(() => undefined);
    throw new Error(
      `Failed to start embedded PostgreSQL test database: ${formatEmbeddedPostgresError(error)}`,
    );
  }
}