diff --git a/packages/modules/postgresql/src/postgresql-container.test.ts b/packages/modules/postgresql/src/postgresql-container.test.ts index 8b1e6511b..db102eb56 100644 --- a/packages/modules/postgresql/src/postgresql-container.test.ts +++ b/packages/modules/postgresql/src/postgresql-container.test.ts @@ -83,4 +83,35 @@ describe("PostgreSqlContainer", () => { await container.stop(); }); // } + + it("should work with restarted container", async () => { + const container = await new PostgreSqlContainer().start(); + await container.restart(); + + const client = new Client({ + host: container.getHost(), + port: container.getPort(), + database: container.getDatabase(), + user: container.getUsername(), + password: container.getPassword(), + }); + await client.connect(); + + const result = await client.query("SELECT 1"); + expect(result.rows[0]).toEqual({ "?column?": 1 }); + + await client.end(); + await container.stop(); + }); + + it("should allow custom healthcheck", async () => { + const container = new PostgreSqlContainer().withHealthCheck({ + test: ["CMD-SHELL", "exit 1"], + interval: 100, + retries: 0, + timeout: 0, + }); + + await expect(() => container.start()).rejects.toThrow(); + }); }); diff --git a/packages/modules/postgresql/src/postgresql-container.ts b/packages/modules/postgresql/src/postgresql-container.ts index 745f46710..3de192482 100755 --- a/packages/modules/postgresql/src/postgresql-container.ts +++ b/packages/modules/postgresql/src/postgresql-container.ts @@ -9,9 +9,9 @@ export class PostgreSqlContainer extends GenericContainer { constructor(image = "postgres:13.3-alpine") { super(image); - this.withExposedPorts(POSTGRES_PORT) - .withWaitStrategy(Wait.forLogMessage(/.*database system is ready to accept connections.*/, 2)) - .withStartupTimeout(120_000); + this.withExposedPorts(POSTGRES_PORT); + this.withWaitStrategy(Wait.forHealthCheck()); + this.withStartupTimeout(120_000); } public withDatabase(database: string): this { @@ -35,13 +35,19 @@ export class PostgreSqlContainer extends GenericContainer { POSTGRES_USER: this.username, POSTGRES_PASSWORD: this.password, }); + if (!this.healthCheck) { + this.withHealthCheck({ + test: ["CMD-SHELL", `PGPASSWORD=${this.password} psql -U ${this.username} -d ${this.database} -c 'SELECT 1;'`], + interval: 250, + timeout: 1000, + retries: 1000, + }); + } return new StartedPostgreSqlContainer(await super.start(), this.database, this.username, this.password); } } export class StartedPostgreSqlContainer extends AbstractStartedContainer { - private readonly port: number; - constructor( startedTestContainer: StartedTestContainer, private readonly database: string, @@ -49,11 +55,10 @@ export class StartedPostgreSqlContainer extends AbstractStartedContainer { private readonly password: string ) { super(startedTestContainer); - this.port = startedTestContainer.getMappedPort(POSTGRES_PORT); } public getPort(): number { - return this.port; + return super.getMappedPort(POSTGRES_PORT); } public getDatabase(): string { diff --git a/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts b/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts index 7367b5d18..16d449824 100644 --- a/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts +++ b/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts @@ -120,9 +120,7 @@ export class DockerContainerClient implements ContainerClient { async inspect(container: Dockerode.Container): Promise { try { - log.debug(`Inspecting container...`, { containerId: container.id }); const inspectInfo = await container.inspect(); - log.debug(`Inspected container`, { containerId: container.id }); return inspectInfo; } catch (err) { log.error(`Failed to inspect container: ${err}`, { containerId: container.id }); diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index fc6bea5c2..bf630bf22 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -57,6 +57,7 @@ export class GenericContainer implements TestContainer { protected filesToCopy: FileToCopy[] = []; protected directoriesToCopy: DirectoryToCopy[] = []; protected contentsToCopy: ContentToCopy[] = []; + protected healthCheck?: HealthCheck; constructor(image: string) { this.imageName = ImageName.fromString(image); @@ -387,6 +388,7 @@ export class GenericContainer implements TestContainer { public withHealthCheck(healthCheck: HealthCheck): this { const toNanos = (duration: number): number => duration * 1e6; + this.healthCheck = healthCheck; this.createOpts.Healthcheck = { Test: healthCheck.test, Interval: healthCheck.interval ? toNanos(healthCheck.interval) : 0, @@ -394,6 +396,7 @@ export class GenericContainer implements TestContainer { Retries: healthCheck.retries || 0, StartPeriod: healthCheck.startPeriod ? toNanos(healthCheck.startPeriod) : 0, }; + return this; }