UNPKG

@backstage/backend-test-utils

Version:

Test helpers library for Backstage backends

132 lines (126 loc) 4.29 kB
'use strict'; var node_crypto = require('node:crypto'); var knexFactory = require('knex'); var pgConnectionString = require('pg-connection-string'); var waitForReady = require('../util/waitForReady.cjs.js'); var types = require('./types.cjs.js'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var knexFactory__default = /*#__PURE__*/_interopDefaultCompat(knexFactory); async function waitForPostgresReady(connection) { await waitForReady.waitForReady(async () => { const knex = knexFactory__default.default({ client: "pg", connection: { // make a copy because the driver mutates this ...connection } }); try { const result = await knex.select(knex.raw("version()")); return Array.isArray(result) && Boolean(result[0]?.version); } finally { await knex.destroy(); } }, "the database"); } async function startPostgresContainer(image) { const user = "postgres"; const password = node_crypto.randomUUID(); const { GenericContainer } = require("testcontainers"); const container = await new GenericContainer(image).withExposedPorts(5432).withEnvironment({ // Since postgres 18, the default directory changed - so we pin it here PGDATA: "/var/lib/postgresql/data", POSTGRES_PASSWORD: password }).withTmpFs({ "/var/lib/postgresql/data": "rw" }).start(); const host = container.getHost(); const port = container.getMappedPort(5432); const connection = { host, port, user, password }; const stopContainer = async () => { await container.stop({ timeout: 1e4 }); }; await waitForPostgresReady(connection); return { connection, stopContainer }; } class PostgresEngine { static async create(properties) { const { connectionStringEnvironmentVariableName, dockerImageName } = properties; if (connectionStringEnvironmentVariableName) { const connectionString = process.env[connectionStringEnvironmentVariableName]; if (connectionString) { const connection = pgConnectionString.parse(connectionString); return new PostgresEngine( properties, connection ); } } if (dockerImageName) { const { connection, stopContainer } = await startPostgresContainer( dockerImageName ); return new PostgresEngine(properties, connection, stopContainer); } throw new Error(`Test databasee for ${properties.name} not configured`); } #properties; #connection; #knexInstances; #databaseNames; #stopContainer; constructor(properties, connection, stopContainer) { this.#properties = properties; this.#connection = connection; this.#knexInstances = []; this.#databaseNames = []; this.#stopContainer = stopContainer; } async createDatabaseInstance() { const adminConnection = this.#connectAdmin(); try { const databaseName = `db${node_crypto.randomBytes(16).toString("hex")}`; await adminConnection.raw("CREATE DATABASE ??", [databaseName]); this.#databaseNames.push(databaseName); const knexInstance = knexFactory__default.default({ client: this.#properties.driver, connection: { ...this.#connection, database: databaseName }, ...types.LARGER_POOL_CONFIG }); this.#knexInstances.push(knexInstance); return knexInstance; } finally { await adminConnection.destroy(); } } async shutdown() { for (const instance of this.#knexInstances) { await instance.destroy(); } const adminConnection = this.#connectAdmin(); try { for (const databaseName of this.#databaseNames) { await adminConnection.raw("DROP DATABASE ??", [databaseName]); } } finally { await adminConnection.destroy(); } await this.#stopContainer?.(); } #connectAdmin() { return knexFactory__default.default({ client: this.#properties.driver, connection: { ...this.#connection, database: "postgres" }, pool: { acquireTimeoutMillis: 1e4 } }); } } exports.PostgresEngine = PostgresEngine; exports.startPostgresContainer = startPostgresContainer; //# sourceMappingURL=postgres.cjs.js.map