Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/features/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ await environment.stop();

## Interacting with the containers

Interact with the containers in your compose environment as you would any other Generic Container. Note that the container name suffix has changed from `_` to `-` between docker-compose v1 and v2 respectively.
Interact with the containers in your compose environment as you would any other Generic Container. Compose-managed container names use the `<service-name>-<index>` format.

```js
const container = environment.getContainer("alpine-1");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
version: "3.5"

services:
service_1:
service-a:
image: cristianrgreco/testcontainer:1.1.14
ports:
- 8080
service_2:
service-b:
image: cristianrgreco/testcontainer:1.1.14
ports:
- 8080
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { parseComposeContainerName } from "./parse-compose-container-name";

describe("parseComposeContainerName", () => {
it("should remove project name label", () => {
const name = "/project-name_container_1";
const expected = "container_1";
const name = "/project-name-container-1";
const expected = "container-1";

expect(parseComposeContainerName("project-name", name)).toBe(expected);
});
Expand All @@ -16,8 +16,8 @@ describe("parseComposeContainerName", () => {
});

it("should throw error if unable to resolve container name", () => {
expect(() => parseComposeContainerName("project-name", "container_1")).toThrowError(
`Unable to resolve container name for container name: "container_1", project name: "project-name"`
expect(() => parseComposeContainerName("project-name", "container-1")).toThrowError(
`Unable to resolve container name for container name: "container-1", project name: "project-name"`
);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function parseComposeContainerName(projectName: string, containerName: string): string {
if (containerName.includes(projectName)) {
return containerName.substring(`/${projectName}_`.length);
if (containerName.startsWith(`/${projectName}-`)) {
return containerName.substring(`/${projectName}-`.length);
} else if (containerName.startsWith("/")) {
return containerName.substring(1);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { randomUuid } from "../common/uuid";
import { PullPolicy } from "../utils/pull-policy";
import {
checkEnvironmentContainerIsHealthy,
composeContainerName,
getDockerEventStream,
getRunningContainerNames,
getVolumeNames,
Expand All @@ -24,7 +23,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
await using startedEnvironment = await new DockerComposeEnvironment(fixtures, "docker-compose.yml").up();

await Promise.all(
[await composeContainerName("container"), await composeContainerName("another_container")].map(
["container-1", "another_container-1"].map(
async (containerName) => await checkEnvironmentContainerIsHealthy(startedEnvironment, containerName)
)
);
Expand All @@ -43,7 +42,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
it("should work with buildkit", async () => {
const buildkitFixtures = path.resolve(fixtures, "docker-compose-with-buildkit");
await using startedEnvironment = await new DockerComposeEnvironment(buildkitFixtures, "docker-compose.yml").up();
await checkEnvironmentContainerIsHealthy(startedEnvironment, await composeContainerName("container"));
await checkEnvironmentContainerIsHealthy(startedEnvironment, "container-1");
});
}

Expand All @@ -63,12 +62,12 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
it("should use pull policy for specific service", async () => {
const env = new DockerComposeEnvironment(fixtures, "docker-compose-with-many-services.yml");

await using _ = await env.up(["service_2"]);
await using _ = await env.up(["service-b"]);

{
await using dockerEventStream = await getDockerEventStream();
const dockerPullEventPromise = waitForDockerEvent(dockerEventStream.events, "pull");
await using _ = await env.withPullPolicy(PullPolicy.alwaysPull()).up(["service_2"]);
await using _ = await env.withPullPolicy(PullPolicy.alwaysPull()).up(["service-b"]);
await dockerPullEventPromise;
}
});
Expand All @@ -80,7 +79,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
"docker-compose.yml",
"docker-compose-update.yml",
]).up();
await using container = startedEnvironment.getContainer(await composeContainerName("container"));
await using container = startedEnvironment.getContainer("container-1");

const url = `http://${container.getHost()}:${container.getMappedPort(8080)}`;
const response = await fetch(`${url}/env`);
Expand All @@ -94,17 +93,17 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
.withDefaultWaitStrategy(Wait.forHealthCheck())
.up();

await checkEnvironmentContainerIsHealthy(startedEnvironment, await composeContainerName("container"));
await checkEnvironmentContainerIsHealthy(startedEnvironment, "container-1");
});

it("should support log message wait strategy", async () => {
await using startedEnvironment = await new DockerComposeEnvironment(fixtures, "docker-compose.yml")
.withWaitStrategy(await composeContainerName("container"), Wait.forLogMessage("Listening on port 8080"))
.withWaitStrategy(await composeContainerName("another_container"), Wait.forLogMessage("Listening on port 8080"))
.withWaitStrategy("container-1", Wait.forLogMessage("Listening on port 8080"))
.withWaitStrategy("another_container-1", Wait.forLogMessage("Listening on port 8080"))
.up();

await Promise.all(
[await composeContainerName("container"), await composeContainerName("another_container")].map(
["container-1", "another_container-1"].map(
async (containerName) => await checkEnvironmentContainerIsHealthy(startedEnvironment, containerName)
)
);
Expand All @@ -125,29 +124,29 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {

it("should support health check wait strategy", async () => {
await using startedEnvironment = await new DockerComposeEnvironment(fixtures, "docker-compose-with-healthcheck.yml")
.withWaitStrategy(await composeContainerName("container"), Wait.forHealthCheck())
.withWaitStrategy("container-1", Wait.forHealthCheck())
.up();

await checkEnvironmentContainerIsHealthy(startedEnvironment, await composeContainerName("container"));
await checkEnvironmentContainerIsHealthy(startedEnvironment, "container-1");
});

it("should support failing health check wait strategy", async () => {
await expect(
new DockerComposeEnvironment(fixtures, "docker-compose-with-healthcheck-unhealthy.yml")
.withWaitStrategy(await composeContainerName("container"), Wait.forHealthCheck())
.withWaitStrategy("container-1", Wait.forHealthCheck())
.up()
).rejects.toThrow(`Health check failed: unhealthy`);
});

it("should stop the container when the health check wait strategy times out", async () => {
await expect(
new DockerComposeEnvironment(fixtures, "docker-compose-with-healthcheck-with-start-period.yml")
.withWaitStrategy(await composeContainerName("container"), Wait.forHealthCheck())
.withWaitStrategy("container-1", Wait.forHealthCheck())
.withStartupTimeout(0)
.up()
).rejects.toThrow(`Health check not healthy after 0ms`);

expect(await getRunningContainerNames()).not.toContain("container_1");
expect(await getRunningContainerNames()).not.toContain("container-1");
});

it("should remove volumes when downing an environment", async () => {
Expand All @@ -169,7 +168,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
.up();

await Promise.all(
[await composeContainerName("container"), await composeContainerName("another_container")].map(
["container-1", "another_container-1"].map(
async (containerName) => await checkEnvironmentContainerIsHealthy(startedEnvironment, containerName)
)
);
Expand All @@ -180,7 +179,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
.withEnvironment({ ENV_VAR: "ENV_VAR_VALUE" })
.up();

await using container = startedEnvironment.getContainer(await composeContainerName("container"));
await using container = startedEnvironment.getContainer("container-1");
const response = await fetch(`http://${container.getHost()}:${container.getMappedPort(8080)}/env`);
const responseBody = (await response.json()) as { [key: string]: string };
expect(responseBody["ENV_VAR"]).toBe("ENV_VAR_VALUE");
Expand All @@ -198,11 +197,11 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
await using startedEnvironment = await new DockerComposeEnvironment(
fixtures,
"docker-compose-with-many-services.yml"
).up(["service_2"]);
).up(["service-b"]);

await checkEnvironmentContainerIsHealthy(startedEnvironment, await composeContainerName("service_2"));
expect(() => startedEnvironment.getContainer("service_1")).toThrow(
`Cannot get container "service_1" as it is not running`
await checkEnvironmentContainerIsHealthy(startedEnvironment, "service-b-1");
expect(() => startedEnvironment.getContainer("service-a")).toThrow(
`Cannot get container "service-a" as it is not running`
);
});

Expand All @@ -224,7 +223,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {

await using startedEnvironment = await new DockerComposeEnvironment(overrideFixtures, "docker-compose.yml").up();

await using container = startedEnvironment.getContainer(await composeContainerName("container"));
await using container = startedEnvironment.getContainer("container-1");
const response = await fetch(`http://${container.getHost()}:${container.getMappedPort(8080)}/env`);
const responseBody = (await response.json()) as { [key: string]: string };
expect(responseBody["ENV_VAR"]).toBe("default");
Expand All @@ -237,7 +236,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
.withEnvironmentFile(".env.override")
.up();

await using container = startedEnvironment.getContainer(await composeContainerName("container"));
await using container = startedEnvironment.getContainer("container-1");
const response = await fetch(`http://${container.getHost()}:${container.getMappedPort(8080)}/env`);
const responseBody = (await response.json()) as { [key: string]: string };
expect(responseBody["ENV_VAR"]).toBe("override");
Expand All @@ -249,7 +248,7 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => {
.up();

await Promise.all(
[await composeContainerName("container"), await composeContainerName("another_container")].map(
["container-1", "another_container-1"].map(
async (containerName) => await checkEnvironmentContainerIsHealthy(startedEnvironment, containerName)
)
);
Expand Down
4 changes: 0 additions & 4 deletions packages/testcontainers/src/utils/test-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,6 @@ export const getVolumeNames = async (): Promise<string[]> => {
return volumes.map((volume) => volume.Name);
};

export const composeContainerName = async (serviceName: string, index = 1): Promise<string> => {
return `${serviceName}-${index}`;
};

export const waitForDockerEvent = async (eventStream: Readable, eventName: string, times = 1) => {
let currentTimes = 0;
let pendingData = "";
Expand Down
Loading