From ae294fe2326af9b6c3b51ae0a38f96e3c8b86f6b Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Tue, 17 Feb 2026 16:17:56 +0000 Subject: [PATCH] Simplify Compose naming to v2-only conventions --- docs/features/compose.md | 2 +- .../docker-compose-with-many-services.yml | 4 +- .../parse-compose-container-name.test.ts | 8 ++-- .../compose/parse-compose-container-name.ts | 4 +- .../docker-compose-environment.test.ts | 47 +++++++++---------- .../testcontainers/src/utils/test-helper.ts | 4 -- 6 files changed, 32 insertions(+), 37 deletions(-) diff --git a/docs/features/compose.md b/docs/features/compose.md index 2f22ddef7..325ab38cd 100644 --- a/docs/features/compose.md +++ b/docs/features/compose.md @@ -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 `-` format. ```js const container = environment.getContainer("alpine-1"); diff --git a/packages/testcontainers/fixtures/docker-compose/docker-compose-with-many-services.yml b/packages/testcontainers/fixtures/docker-compose/docker-compose-with-many-services.yml index 8a27089d6..73fe04c21 100644 --- a/packages/testcontainers/fixtures/docker-compose/docker-compose-with-many-services.yml +++ b/packages/testcontainers/fixtures/docker-compose/docker-compose-with-many-services.yml @@ -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 diff --git a/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.test.ts b/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.test.ts index 703a3e05b..9f2391c20 100644 --- a/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.test.ts +++ b/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.test.ts @@ -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); }); @@ -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"` ); }); }); diff --git a/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.ts b/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.ts index 6000d999a..fc195acc0 100644 --- a/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.ts +++ b/packages/testcontainers/src/container-runtime/clients/compose/parse-compose-container-name.ts @@ -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 { diff --git a/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts b/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts index 9a077642b..1c6d76134 100644 --- a/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts +++ b/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts @@ -4,7 +4,6 @@ import { randomUuid } from "../common/uuid"; import { PullPolicy } from "../utils/pull-policy"; import { checkEnvironmentContainerIsHealthy, - composeContainerName, getDockerEventStream, getRunningContainerNames, getVolumeNames, @@ -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) ) ); @@ -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"); }); } @@ -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; } }); @@ -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`); @@ -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) ) ); @@ -125,16 +124,16 @@ 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`); }); @@ -142,12 +141,12 @@ describe("DockerComposeEnvironment", { timeout: 180_000 }, () => { 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 () => { @@ -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) ) ); @@ -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"); @@ -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` ); }); @@ -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"); @@ -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"); @@ -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) ) ); diff --git a/packages/testcontainers/src/utils/test-helper.ts b/packages/testcontainers/src/utils/test-helper.ts index 70e4e8fbe..70a9a2d09 100644 --- a/packages/testcontainers/src/utils/test-helper.ts +++ b/packages/testcontainers/src/utils/test-helper.ts @@ -119,10 +119,6 @@ export const getVolumeNames = async (): Promise => { return volumes.map((volume) => volume.Name); }; -export const composeContainerName = async (serviceName: string, index = 1): Promise => { - return `${serviceName}-${index}`; -}; - export const waitForDockerEvent = async (eventStream: Readable, eventName: string, times = 1) => { let currentTimes = 0; let pendingData = "";