Skip to content

Commit 3cdb2bd

Browse files
committed
Add support for reusing stopped containers
1 parent 08da47b commit 3cdb2bd

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export class DockerContainerClient implements ContainerClient {
3535
const containers = await this.dockerode.listContainers({
3636
limit: 1,
3737
filters: {
38-
status: ["running"],
3938
label: [`${labelName}=${labelValue}`],
4039
},
4140
});

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe("GenericContainer reuse", () => {
8383
await container1.stop();
8484
});
8585

86-
it("should create a new container when an existing reusable container has stopped", async () => {
86+
it("should create a new container when an existing reusable container has stopped and is removed", async () => {
8787
const container1 = await new GenericContainer("cristianrgreco/testcontainer:1.1.14")
8888
.withName("there_can_only_be_one")
8989
.withExposedPorts(8080)
@@ -102,6 +102,25 @@ describe("GenericContainer reuse", () => {
102102
await container2.stop();
103103
});
104104

105+
it("should reuse container when an existing reusable container has stopped but not removed", async () => {
106+
const container1 = await new GenericContainer("cristianrgreco/testcontainer:1.1.14")
107+
.withName("there_can_only_be_one")
108+
.withExposedPorts(8080)
109+
.withReuse()
110+
.start();
111+
await container1.stop({ remove: false });
112+
113+
const container2 = await new GenericContainer("cristianrgreco/testcontainer:1.1.14")
114+
.withName("there_can_only_be_one")
115+
.withExposedPorts(8080)
116+
.withReuse()
117+
.start();
118+
await checkContainerIsHealthy(container2);
119+
120+
expect(container1.getId()).toBe(container2.getId());
121+
await container2.stop();
122+
});
123+
105124
it("should keep the labels passed in when a new reusable container is created", async () => {
106125
const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14")
107126
.withName("there_can_only_be_one")

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,14 @@ export class GenericContainer implements TestContainer {
128128
}
129129

130130
private async reuseContainer(client: ContainerRuntimeClient, container: Container) {
131-
const inspectResult = await client.container.inspect(container);
131+
let inspectResult = await client.container.inspect(container);
132+
if (!inspectResult.State.Running) {
133+
log.debug("Reused container is not running, attempting to start it");
134+
await client.container.start(container);
135+
// Refetch the inspect result to get the updated state
136+
inspectResult = await client.container.inspect(container);
137+
}
138+
132139
const mappedInspectResult = mapInspectResult(inspectResult);
133140
const boundPorts = BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter(
134141
this.exposedPorts

0 commit comments

Comments
 (0)