diff --git a/packages/modules/cockroachdb/src/cockroachdb-container.test.ts b/packages/modules/cockroachdb/src/cockroachdb-container.test.ts index 9c338e159..19655ab59 100644 --- a/packages/modules/cockroachdb/src/cockroachdb-container.test.ts +++ b/packages/modules/cockroachdb/src/cockroachdb-container.test.ts @@ -2,12 +2,12 @@ import { Client } from "pg"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { CockroachDbContainer } from "./cockroachdb-container"; -const IMAGE = getImage(__dirname); +const IMAGES = ["cockroachdb/cockroach:v24.3.36", "cockroachdb/cockroach:v25.4.17", getImage(__dirname)]; -describe("CockroachDbContainer", { timeout: 180_000 }, () => { - it("should connect and return a query result", async () => { +describe.each(IMAGES)("CockroachDbContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => { + it.concurrent("should connect and return a query result", async () => { // cockroachConnect { - await using container = await new CockroachDbContainer(IMAGE).start(); + await using container = await new CockroachDbContainer(image).start(); const client = new Client({ host: container.getHost(), @@ -26,9 +26,9 @@ describe("CockroachDbContainer", { timeout: 180_000 }, () => { // } }); - it("should work with database URI", async () => { + it.concurrent("should work with database URI", async () => { // uriConnect { - await using container = await new CockroachDbContainer(IMAGE).start(); + await using container = await new CockroachDbContainer(image).start(); const client = new Client({ connectionString: container.getConnectionUri(), @@ -43,9 +43,9 @@ describe("CockroachDbContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should set database", async () => { + it.concurrent("should set database", async () => { // setDatabase { - await using container = await new CockroachDbContainer(IMAGE).withDatabase("custom_database").start(); + await using container = await new CockroachDbContainer(image).withDatabase("custom_database").start(); // } const client = new Client({ @@ -63,9 +63,9 @@ describe("CockroachDbContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should set username", async () => { + it.concurrent("should set username", async () => { // setUsername { - await using container = await new CockroachDbContainer(IMAGE).withUsername("custom_username").start(); + await using container = await new CockroachDbContainer(image).withUsername("custom_username").start(); // } const client = new Client({ @@ -83,8 +83,8 @@ describe("CockroachDbContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should work with restarted container", async () => { - await using container = await new CockroachDbContainer(IMAGE).start(); + it.concurrent("should work with restarted container", async () => { + await using container = await new CockroachDbContainer(image).start(); await container.restart(); const client = new Client({ @@ -101,8 +101,8 @@ describe("CockroachDbContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should allow custom healthcheck", async () => { - const container = new CockroachDbContainer(IMAGE).withHealthCheck({ + it.concurrent("should allow custom healthcheck", async () => { + const container = new CockroachDbContainer(image).withHealthCheck({ test: ["CMD-SHELL", "exit 1"], interval: 100, retries: 0, diff --git a/packages/modules/mariadb/src/mariadb-container.test.ts b/packages/modules/mariadb/src/mariadb-container.test.ts index a82390b06..4666b6f56 100644 --- a/packages/modules/mariadb/src/mariadb-container.test.ts +++ b/packages/modules/mariadb/src/mariadb-container.test.ts @@ -2,12 +2,12 @@ import { createConnection } from "mariadb"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { MariaDbContainer } from "./mariadb-container"; -const IMAGE = getImage(__dirname); +const IMAGES = ["mariadb:10.11.19", "mariadb:11.8.9", "mariadb:12.3.3", getImage(__dirname)]; -describe("MariaDbContainer", { timeout: 240_000 }, () => { - it("should connect and execute query", async () => { +describe.each(IMAGES)("MariaDbContainer (%s)", { concurrent: false, timeout: 240_000 }, (image) => { + it.concurrent("should connect and execute query", async () => { // mariaDbConnect { - await using container = await new MariaDbContainer(IMAGE).start(); + await using container = await new MariaDbContainer(image).start(); const client = await createConnection({ host: container.getHost(), @@ -24,14 +24,14 @@ describe("MariaDbContainer", { timeout: 240_000 }, () => { // } }); - it("should work with database URI", async () => { + it.concurrent("should work with database URI", async () => { // mariaDbUriConnect { const username = "testUser"; const password = "testPassword"; const database = "testDB"; // Test non-root user - await using container = await new MariaDbContainer(IMAGE) + await using container = await new MariaDbContainer(image) .withUsername(username) .withUserPassword(password) .withDatabase(database) @@ -42,7 +42,7 @@ describe("MariaDbContainer", { timeout: 240_000 }, () => { ); // Test root user - await using rootContainer = await new MariaDbContainer(IMAGE) + await using rootContainer = await new MariaDbContainer(image) .withRootPassword(password) .withDatabase(database) .start(); @@ -53,9 +53,9 @@ describe("MariaDbContainer", { timeout: 240_000 }, () => { // } }); - it("should set database", async () => { + it.concurrent("should set database", async () => { // mariaDbSetDatabase { - await using container = await new MariaDbContainer(IMAGE).withDatabase("customDatabase").start(); + await using container = await new MariaDbContainer(image).withDatabase("customDatabase").start(); const client = await createConnection({ host: container.getHost(), @@ -72,9 +72,9 @@ describe("MariaDbContainer", { timeout: 240_000 }, () => { // } }); - it("should set username", async () => { + it.concurrent("should set username", async () => { // mariaDbSetUsername { - await using container = await new MariaDbContainer(IMAGE).withUsername("customUsername").start(); + await using container = await new MariaDbContainer(image).withUsername("customUsername").start(); const client = await createConnection({ host: container.getHost(), @@ -91,8 +91,8 @@ describe("MariaDbContainer", { timeout: 240_000 }, () => { // } }); - it("should work with restarted container", async () => { - await using container = await new MariaDbContainer(IMAGE).start(); + it.concurrent("should work with restarted container", async () => { + await using container = await new MariaDbContainer(image).start(); await container.restart(); const client = await createConnection({ diff --git a/packages/modules/mysql/src/mysql-container.test.ts b/packages/modules/mysql/src/mysql-container.test.ts index 3b0a4ebea..f873610e6 100644 --- a/packages/modules/mysql/src/mysql-container.test.ts +++ b/packages/modules/mysql/src/mysql-container.test.ts @@ -2,12 +2,12 @@ import { createConnection } from "mysql2/promise"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { MySqlContainer } from "./mysql-container"; -const IMAGE = getImage(__dirname); +const IMAGES = ["mysql:8.4.11", "mysql:9.7.2", getImage(__dirname)]; -describe("MySqlContainer", { timeout: 240_000 }, () => { - it("should connect and execute query", async () => { +describe.each(IMAGES)("MySqlContainer (%s)", { concurrent: false, timeout: 240_000 }, (image) => { + it.concurrent("should connect and execute query", async () => { // mysqlConnect { - await using container = await new MySqlContainer(IMAGE).start(); + await using container = await new MySqlContainer(image).start(); const client = await createConnection({ host: container.getHost(), @@ -24,13 +24,13 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { // } }); - it("should work with database URI", async () => { + it.concurrent("should work with database URI", async () => { // mysqlUriConnect { const username = "testUser"; const password = "testPassword"; const database = "testDB"; - await using container = await new MySqlContainer(IMAGE) + await using container = await new MySqlContainer(image) .withUsername(username) .withUserPassword(password) .withDatabase(database) @@ -40,7 +40,7 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { `mysql://${username}:${password}@${container.getHost()}:${container.getPort()}/${database}` ); - await using rootContainer = await new MySqlContainer(IMAGE) + await using rootContainer = await new MySqlContainer(image) .withRootPassword(password) .withDatabase(database) .start(); @@ -51,9 +51,9 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { // } }); - it("should set database", async () => { + it.concurrent("should set database", async () => { // mysqlSetDatabase { - await using container = await new MySqlContainer(IMAGE).withDatabase("customDatabase").start(); + await using container = await new MySqlContainer(image).withDatabase("customDatabase").start(); const client = await createConnection({ host: container.getHost(), @@ -71,8 +71,8 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { }); // mysqlSetUsername { - it("should set username", async () => { - await using container = await new MySqlContainer(IMAGE).withUsername("customUsername").start(); + it.concurrent("should set username", async () => { + await using container = await new MySqlContainer(image).withUsername("customUsername").start(); const client = await createConnection({ host: container.getHost(), @@ -89,17 +89,17 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { }); // } - it("should execute a query and return the result", async () => { + it.concurrent("should execute a query and return the result", async () => { // mysqlExecuteQuery { - await using container = await new MySqlContainer(IMAGE).start(); + await using container = await new MySqlContainer(image).start(); const result = await container.executeQuery("SELECT 1 as res"); expect(result).toEqual(expect.stringContaining("res\n1\n")); // } }); - it("should execute a query as root user", async () => { - await using container = await new MySqlContainer(IMAGE).withUsername("customUsername").start(); + it.concurrent("should execute a query as root user", async () => { + await using container = await new MySqlContainer(image).withUsername("customUsername").start(); // Test non-root user const queryResult = await container.executeQuery("SELECT CURRENT_USER() as user"); @@ -110,8 +110,8 @@ describe("MySqlContainer", { timeout: 240_000 }, () => { expect(rootQueryResult).toEqual(expect.stringContaining("user\nroot")); }); - it("should work with restarted container", async () => { - await using container = await new MySqlContainer(IMAGE).start(); + it.concurrent("should work with restarted container", async () => { + await using container = await new MySqlContainer(image).start(); await container.restart(); const client = await createConnection({ diff --git a/packages/modules/postgresql/Dockerfile b/packages/modules/postgresql/Dockerfile index 38f750c05..3a45116dd 100644 --- a/packages/modules/postgresql/Dockerfile +++ b/packages/modules/postgresql/Dockerfile @@ -1 +1,4 @@ FROM postgres:18.6-alpine +FROM pgvector/pgvector:0.8.7-pg18 +FROM postgis/postgis:18-3.6 +FROM timescale/timescaledb:2.30.2-pg18 diff --git a/packages/modules/postgresql/src/pgvector-container.test.ts b/packages/modules/postgresql/src/pgvector-container.test.ts index 2b48b58ab..8f10a46bd 100644 --- a/packages/modules/postgresql/src/pgvector-container.test.ts +++ b/packages/modules/postgresql/src/pgvector-container.test.ts @@ -3,7 +3,7 @@ import { Client } from "pg"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { PostgreSqlContainer } from "./postgresql-container"; -const IMAGE = getImage(__dirname); +const IMAGE = getImage(__dirname, 1); const SSL_SERVER_CERT = path.resolve(__dirname, "test-certs/server.crt"); const SSL_SERVER_KEY = path.resolve(__dirname, "test-certs/server.key"); diff --git a/packages/modules/postgresql/src/postgis-container.test.ts b/packages/modules/postgresql/src/postgis-container.test.ts index e5e3ebcd4..362104f90 100644 --- a/packages/modules/postgresql/src/postgis-container.test.ts +++ b/packages/modules/postgresql/src/postgis-container.test.ts @@ -3,13 +3,15 @@ import { Client } from "pg"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { PostgreSqlContainer } from "./postgresql-container"; -const IMAGE = getImage(__dirname); +const IMAGE = getImage(__dirname, 2); +// postgis/postgis publishes no arm64 image. +const PLATFORM = "linux/amd64"; const SSL_SERVER_CERT = path.resolve(__dirname, "test-certs/server.crt"); const SSL_SERVER_KEY = path.resolve(__dirname, "test-certs/server.key"); describe("PostgisContainer", { timeout: 180_000 }, () => { it("should work", async () => { - await using container = await new PostgreSqlContainer(IMAGE).start(); + await using container = await new PostgreSqlContainer(IMAGE).withPlatform(PLATFORM).start(); const client = new Client({ host: container.getHost(), @@ -27,7 +29,7 @@ describe("PostgisContainer", { timeout: 180_000 }, () => { }); it("should restart", async () => { - await using container = await new PostgreSqlContainer(IMAGE).start(); + await using container = await new PostgreSqlContainer(IMAGE).withPlatform(PLATFORM).start(); await container.restart(); const client = new Client({ @@ -46,7 +48,10 @@ describe("PostgisContainer", { timeout: 180_000 }, () => { }); it("should connect with SSL", async () => { - await using container = await new PostgreSqlContainer(IMAGE).withSSL(SSL_SERVER_CERT, SSL_SERVER_KEY).start(); + await using container = await new PostgreSqlContainer(IMAGE) + .withPlatform(PLATFORM) + .withSSL(SSL_SERVER_CERT, SSL_SERVER_KEY) + .start(); const client = new Client({ host: container.getHost(), diff --git a/packages/modules/postgresql/src/postgresql-container-snapshot.test.ts b/packages/modules/postgresql/src/postgresql-container-snapshot.test.ts index e85838374..ab3c2f5ef 100644 --- a/packages/modules/postgresql/src/postgresql-container-snapshot.test.ts +++ b/packages/modules/postgresql/src/postgresql-container-snapshot.test.ts @@ -1,206 +1,208 @@ import { Client } from "pg"; -import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { PostgreSqlContainer } from "./postgresql-container"; - -const IMAGE = getImage(__dirname); - -describe("PostgreSqlContainer snapshot and restore", { timeout: 180_000 }, () => { - it("should create and restore from snapshot", async () => { - // createAndRestoreFromSnapshot { - await using container = await new PostgreSqlContainer(IMAGE).start(); - - // Connect to the database - let client = new Client({ - connectionString: container.getConnectionUri(), +import { IMAGES } from "./test-helper"; + +describe.each(IMAGES)( + "PostgreSqlContainer snapshot and restore (%s)", + { concurrent: false, timeout: 180_000 }, + (image) => { + it.concurrent("should create and restore from snapshot", async () => { + // createAndRestoreFromSnapshot { + await using container = await new PostgreSqlContainer(image).start(); + + // Connect to the database + let client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); + + // Create some test data + await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); + await client.query("INSERT INTO test_table (name) VALUES ('initial data')"); + + // Close connection before snapshot (otherwise we'll get an error because user is already connected) + await client.end(); + + // Take a snapshot + await container.snapshot(); + + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); + + // Modify the database + await client.query("INSERT INTO test_table (name) VALUES ('data after snapshot')"); + + // Verify both records exist + let result = await client.query("SELECT * FROM test_table ORDER BY id"); + expect(result.rows).toHaveLength(2); + expect(result.rows[0].name).toEqual("initial data"); + expect(result.rows[1].name).toEqual("data after snapshot"); + + // Close connection before restore (same reason as above) + await client.end(); + + // Restore to the snapshot + await container.restoreSnapshot(); + + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); + + // Verify only the initial data exists after restore + result = await client.query("SELECT * FROM test_table ORDER BY id"); + expect(result.rows).toHaveLength(1); + expect(result.rows[0].name).toEqual("initial data"); + + await client.end(); + // } }); - await client.connect(); - // Create some test data - await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); - await client.query("INSERT INTO test_table (name) VALUES ('initial data')"); + it.concurrent("should use custom snapshot name", async () => { + await using container = await new PostgreSqlContainer(image).start(); + const customSnapshotName = "my_custom_snapshot"; - // Close connection before snapshot (otherwise we'll get an error because user is already connected) - await client.end(); + // Connect to the database + let client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Take a snapshot - await container.snapshot(); + // Create a test table and insert data + await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); + await client.query("INSERT INTO test_table (name) VALUES ('initial data')"); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); - - // Modify the database - await client.query("INSERT INTO test_table (name) VALUES ('data after snapshot')"); + // Close connection before snapshot + await client.end(); - // Verify both records exist - let result = await client.query("SELECT * FROM test_table ORDER BY id"); - expect(result.rows).toHaveLength(2); - expect(result.rows[0].name).toEqual("initial data"); - expect(result.rows[1].name).toEqual("data after snapshot"); + // Take a snapshot with custom name + await container.snapshot(customSnapshotName); - // Close connection before restore (same reason as above) - await client.end(); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Restore to the snapshot - await container.restoreSnapshot(); + // Modify the database + await client.query("INSERT INTO test_table (name) VALUES ('data after snapshot')"); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Close connection before restore + await client.end(); - // Verify only the initial data exists after restore - result = await client.query("SELECT * FROM test_table ORDER BY id"); - expect(result.rows).toHaveLength(1); - expect(result.rows[0].name).toEqual("initial data"); + // Restore using the custom snapshot name + await container.restoreSnapshot(customSnapshotName); - await client.end(); - // } - }); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - it("should use custom snapshot name", async () => { - await using container = await new PostgreSqlContainer(IMAGE).start(); - const customSnapshotName = "my_custom_snapshot"; + // Verify only the initial data exists after restore + const result = await client.query("SELECT * FROM test_table ORDER BY id"); + expect(result.rows).toHaveLength(1); + expect(result.rows[0].name).toEqual("initial data"); - // Connect to the database - let client = new Client({ - connectionString: container.getConnectionUri(), + await client.end(); }); - await client.connect(); - // Create a test table and insert data - await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); - await client.query("INSERT INTO test_table (name) VALUES ('initial data')"); + it.concurrent("should handle multiple snapshots", async () => { + await using container = await new PostgreSqlContainer(image).start(); - // Close connection before snapshot - await client.end(); + // Connect to the database + let client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Take a snapshot with custom name - await container.snapshot(customSnapshotName); + // Create a test table + await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Close connection before snapshot + await client.end(); - // Modify the database - await client.query("INSERT INTO test_table (name) VALUES ('data after snapshot')"); + // Take first snapshot with empty table + await container.snapshot("snapshot1"); - // Close connection before restore - await client.end(); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Restore using the custom snapshot name - await container.restoreSnapshot(customSnapshotName); + // Add first record + await client.query("INSERT INTO test_table (name) VALUES ('data for snapshot 2')"); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Close connection before snapshot + await client.end(); - // Verify only the initial data exists after restore - const result = await client.query("SELECT * FROM test_table ORDER BY id"); - expect(result.rows).toHaveLength(1); - expect(result.rows[0].name).toEqual("initial data"); + // Take second snapshot with one record + await container.snapshot("snapshot2"); - await client.end(); - }); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - it("should handle multiple snapshots", async () => { - await using container = await new PostgreSqlContainer(IMAGE).start(); + // Add second record + await client.query("INSERT INTO test_table (name) VALUES ('data after snapshots')"); - // Connect to the database - let client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Verify we have two records + let result = await client.query("SELECT COUNT(*) as count FROM test_table"); + expect(result.rows[0].count).toEqual("2"); - // Create a test table - await client.query("CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)"); + // Close connection before restore + await client.end(); - // Close connection before snapshot - await client.end(); + // Restore to first snapshot (empty table) + await container.restoreSnapshot("snapshot1"); - // Take first snapshot with empty table - await container.snapshot("snapshot1"); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Verify table is empty + result = await client.query("SELECT COUNT(*) as count FROM test_table"); + expect(result.rows[0].count).toEqual("0"); - // Add first record - await client.query("INSERT INTO test_table (name) VALUES ('data for snapshot 2')"); + // Close connection before restore + await client.end(); - // Close connection before snapshot - await client.end(); + // Restore to second snapshot (one record) + await container.restoreSnapshot("snapshot2"); - // Take second snapshot with one record - await container.snapshot("snapshot2"); + // Reconnect to database + client = new Client({ + connectionString: container.getConnectionUri(), + }); + await client.connect(); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), - }); - await client.connect(); + // Verify we have one record + result = await client.query("SELECT * FROM test_table"); + expect(result.rows).toHaveLength(1); + expect(result.rows[0].name).toEqual("data for snapshot 2"); - // Add second record - await client.query("INSERT INTO test_table (name) VALUES ('data after snapshots')"); - - // Verify we have two records - let result = await client.query("SELECT COUNT(*) as count FROM test_table"); - expect(result.rows[0].count).toEqual("2"); - - // Close connection before restore - await client.end(); - - // Restore to first snapshot (empty table) - await container.restoreSnapshot("snapshot1"); - - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), + await client.end(); }); - await client.connect(); - - // Verify table is empty - result = await client.query("SELECT COUNT(*) as count FROM test_table"); - expect(result.rows[0].count).toEqual("0"); - // Close connection before restore - await client.end(); + it.concurrent("should throw an error when trying to snapshot postgres system database", async () => { + await using container = await new PostgreSqlContainer(image).withDatabase("postgres").start(); - // Restore to second snapshot (one record) - await container.restoreSnapshot("snapshot2"); + await expect(container.snapshot()).rejects.toThrow( + "Snapshot feature is not supported when using the postgres system database" + ); - // Reconnect to database - client = new Client({ - connectionString: container.getConnectionUri(), + await expect(container.restoreSnapshot()).rejects.toThrow( + "Snapshot feature is not supported when using the postgres system database" + ); }); - await client.connect(); - - // Verify we have one record - result = await client.query("SELECT * FROM test_table"); - expect(result.rows).toHaveLength(1); - expect(result.rows[0].name).toEqual("data for snapshot 2"); - - await client.end(); - }); - - it("should throw an error when trying to snapshot postgres system database", async () => { - await using container = await new PostgreSqlContainer(IMAGE).withDatabase("postgres").start(); - - await expect(container.snapshot()).rejects.toThrow( - "Snapshot feature is not supported when using the postgres system database" - ); - - await expect(container.restoreSnapshot()).rejects.toThrow( - "Snapshot feature is not supported when using the postgres system database" - ); - }); -}); + } +); diff --git a/packages/modules/postgresql/src/postgresql-container.test.ts b/packages/modules/postgresql/src/postgresql-container.test.ts index ee1338a16..d44b27523 100644 --- a/packages/modules/postgresql/src/postgresql-container.test.ts +++ b/packages/modules/postgresql/src/postgresql-container.test.ts @@ -1,17 +1,16 @@ import path from "node:path"; import { Client } from "pg"; -import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { PostgreSqlContainer } from "./postgresql-container"; +import { IMAGES } from "./test-helper"; -const IMAGE = getImage(__dirname); const SSL_CA_CERT = path.resolve(__dirname, "test-certs/ca.crt"); const SSL_SERVER_CERT = path.resolve(__dirname, "test-certs/server.crt"); const SSL_SERVER_KEY = path.resolve(__dirname, "test-certs/server.key"); -describe("PostgreSqlContainer", { timeout: 180_000 }, () => { - it("should connect and return a query result", async () => { +describe.each(IMAGES)("PostgreSqlContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => { + it.concurrent("should connect and return a query result", async () => { // pgConnect { - await using container = await new PostgreSqlContainer(IMAGE).start(); + await using container = await new PostgreSqlContainer(image).start(); const client = new Client({ host: container.getHost(), @@ -29,9 +28,9 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { // } }); - it("should work with database URI", async () => { + it.concurrent("should work with database URI", async () => { // pgUriConnect { - await using container = await new PostgreSqlContainer(IMAGE).start(); + await using container = await new PostgreSqlContainer(image).start(); const client = new Client({ connectionString: container.getConnectionUri(), @@ -45,9 +44,9 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should set database", async () => { + it.concurrent("should set database", async () => { // pgSetDatabase { - await using container = await new PostgreSqlContainer(IMAGE).withDatabase("customDatabase").start(); + await using container = await new PostgreSqlContainer(image).withDatabase("customDatabase").start(); // } const client = new Client({ @@ -65,9 +64,9 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should set username", async () => { + it.concurrent("should set username", async () => { // pgSetUsername { - await using container = await new PostgreSqlContainer(IMAGE).withUsername("customUsername").start(); + await using container = await new PostgreSqlContainer(image).withUsername("customUsername").start(); // } const client = new Client({ @@ -85,8 +84,8 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should work with restarted container", async () => { - await using container = await new PostgreSqlContainer(IMAGE).start(); + it.concurrent("should work with restarted container", async () => { + await using container = await new PostgreSqlContainer(image).start(); await container.restart(); const client = new Client({ @@ -104,8 +103,8 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { await client.end(); }); - it("should allow custom healthcheck", async () => { - const container = new PostgreSqlContainer(IMAGE).withHealthCheck({ + it.concurrent("should allow custom healthcheck", async () => { + const container = new PostgreSqlContainer(image).withHealthCheck({ test: ["CMD-SHELL", "exit 1"], interval: 100, retries: 0, @@ -115,9 +114,9 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { await expect(() => container.start()).rejects.toThrow(); }); - it("should connect with SSL", async () => { + it.concurrent("should connect with SSL", async () => { // pgSslConnect { - await using container = await new PostgreSqlContainer(IMAGE) + await using container = await new PostgreSqlContainer(image) .withSSLCert(SSL_CA_CERT, SSL_SERVER_CERT, SSL_SERVER_KEY) .start(); @@ -140,8 +139,8 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => { // } }); - it("should validate SSL certificate paths", () => { - const container = new PostgreSqlContainer(IMAGE); + it.concurrent("should validate SSL certificate paths", () => { + const container = new PostgreSqlContainer(image); expect(() => container.withSSL("", "server.key")).toThrow("SSL certificate file should not be empty."); expect(() => container.withSSL("server.crt", "")).toThrow("SSL key file should not be empty."); diff --git a/packages/modules/postgresql/src/test-helper.ts b/packages/modules/postgresql/src/test-helper.ts new file mode 100644 index 000000000..a6c67a5f3 --- /dev/null +++ b/packages/modules/postgresql/src/test-helper.ts @@ -0,0 +1,3 @@ +import { getImage } from "../../../testcontainers/src/utils/test-helper"; + +export const IMAGES = ["postgres:15.19-alpine", "postgres:16.15-alpine", "postgres:17.11-alpine", getImage(__dirname)]; diff --git a/packages/modules/postgresql/src/timescale-container.test.ts b/packages/modules/postgresql/src/timescale-container.test.ts index 00db75557..2d1126bae 100644 --- a/packages/modules/postgresql/src/timescale-container.test.ts +++ b/packages/modules/postgresql/src/timescale-container.test.ts @@ -3,7 +3,7 @@ import { Client } from "pg"; import { getImage } from "../../../testcontainers/src/utils/test-helper"; import { PostgreSqlContainer } from "./postgresql-container"; -const IMAGE = getImage(__dirname); +const IMAGE = getImage(__dirname, 3); const SSL_SERVER_CERT = path.resolve(__dirname, "test-certs/server.crt"); const SSL_SERVER_KEY = path.resolve(__dirname, "test-certs/server.key"); diff --git a/packages/modules/postgresql/tsconfig.build.json b/packages/modules/postgresql/tsconfig.build.json index 91dc68846..aba4d4661 100644 --- a/packages/modules/postgresql/tsconfig.build.json +++ b/packages/modules/postgresql/tsconfig.build.json @@ -1,6 +1,6 @@ { "extends": "./tsconfig.json", - "exclude": ["build", "src/**/*.test.ts"], + "exclude": ["build", "src/**/*.test.ts", "src/test-helper.ts"], "references": [ { "path": "../../testcontainers"