Skip to content

Commit e533856

Browse files
Fix PostgreSQL container restart (#914)
1 parent 3b48cc0 commit e533856

File tree

4 files changed

+46
-9
lines changed

4 files changed

+46
-9
lines changed

packages/modules/postgresql/src/postgresql-container.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,35 @@ describe("PostgreSqlContainer", () => {
8383
await container.stop();
8484
});
8585
// }
86+
87+
it("should work with restarted container", async () => {
88+
const container = await new PostgreSqlContainer().start();
89+
await container.restart();
90+
91+
const client = new Client({
92+
host: container.getHost(),
93+
port: container.getPort(),
94+
database: container.getDatabase(),
95+
user: container.getUsername(),
96+
password: container.getPassword(),
97+
});
98+
await client.connect();
99+
100+
const result = await client.query("SELECT 1");
101+
expect(result.rows[0]).toEqual({ "?column?": 1 });
102+
103+
await client.end();
104+
await container.stop();
105+
});
106+
107+
it("should allow custom healthcheck", async () => {
108+
const container = new PostgreSqlContainer().withHealthCheck({
109+
test: ["CMD-SHELL", "exit 1"],
110+
interval: 100,
111+
retries: 0,
112+
timeout: 0,
113+
});
114+
115+
await expect(() => container.start()).rejects.toThrow();
116+
});
86117
});

packages/modules/postgresql/src/postgresql-container.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export class PostgreSqlContainer extends GenericContainer {
99

1010
constructor(image = "postgres:13.3-alpine") {
1111
super(image);
12-
this.withExposedPorts(POSTGRES_PORT)
13-
.withWaitStrategy(Wait.forLogMessage(/.*database system is ready to accept connections.*/, 2))
14-
.withStartupTimeout(120_000);
12+
this.withExposedPorts(POSTGRES_PORT);
13+
this.withWaitStrategy(Wait.forHealthCheck());
14+
this.withStartupTimeout(120_000);
1515
}
1616

1717
public withDatabase(database: string): this {
@@ -35,25 +35,30 @@ export class PostgreSqlContainer extends GenericContainer {
3535
POSTGRES_USER: this.username,
3636
POSTGRES_PASSWORD: this.password,
3737
});
38+
if (!this.healthCheck) {
39+
this.withHealthCheck({
40+
test: ["CMD-SHELL", `PGPASSWORD=${this.password} psql -U ${this.username} -d ${this.database} -c 'SELECT 1;'`],
41+
interval: 250,
42+
timeout: 1000,
43+
retries: 1000,
44+
});
45+
}
3846
return new StartedPostgreSqlContainer(await super.start(), this.database, this.username, this.password);
3947
}
4048
}
4149

4250
export class StartedPostgreSqlContainer extends AbstractStartedContainer {
43-
private readonly port: number;
44-
4551
constructor(
4652
startedTestContainer: StartedTestContainer,
4753
private readonly database: string,
4854
private readonly username: string,
4955
private readonly password: string
5056
) {
5157
super(startedTestContainer);
52-
this.port = startedTestContainer.getMappedPort(POSTGRES_PORT);
5358
}
5459

5560
public getPort(): number {
56-
return this.port;
61+
return super.getMappedPort(POSTGRES_PORT);
5762
}
5863

5964
public getDatabase(): string {

packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,7 @@ export class DockerContainerClient implements ContainerClient {
120120

121121
async inspect(container: Dockerode.Container): Promise<ContainerInspectInfo> {
122122
try {
123-
log.debug(`Inspecting container...`, { containerId: container.id });
124123
const inspectInfo = await container.inspect();
125-
log.debug(`Inspected container`, { containerId: container.id });
126124
return inspectInfo;
127125
} catch (err) {
128126
log.error(`Failed to inspect container: ${err}`, { containerId: container.id });

packages/testcontainers/src/generic-container/generic-container.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export class GenericContainer implements TestContainer {
5757
protected filesToCopy: FileToCopy[] = [];
5858
protected directoriesToCopy: DirectoryToCopy[] = [];
5959
protected contentsToCopy: ContentToCopy[] = [];
60+
protected healthCheck?: HealthCheck;
6061

6162
constructor(image: string) {
6263
this.imageName = ImageName.fromString(image);
@@ -387,13 +388,15 @@ export class GenericContainer implements TestContainer {
387388
public withHealthCheck(healthCheck: HealthCheck): this {
388389
const toNanos = (duration: number): number => duration * 1e6;
389390

391+
this.healthCheck = healthCheck;
390392
this.createOpts.Healthcheck = {
391393
Test: healthCheck.test,
392394
Interval: healthCheck.interval ? toNanos(healthCheck.interval) : 0,
393395
Timeout: healthCheck.timeout ? toNanos(healthCheck.timeout) : 0,
394396
Retries: healthCheck.retries || 0,
395397
StartPeriod: healthCheck.startPeriod ? toNanos(healthCheck.startPeriod) : 0,
396398
};
399+
397400
return this;
398401
}
399402

0 commit comments

Comments
 (0)