testcontainers / testcontainers-node

Testcontainers is a NodeJS library that supports tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
https://testcontainers.com
MIT License
1.89k stars 184 forks source link

HostPortWaitStrategy strategy does not work for localhost bound ports #686

Open jalaziz opened 10 months ago

jalaziz commented 10 months ago

Expected Behaviour

When launching a container with a port bound to localhost, the wait strategy should work.

Actual Behaviour

The HostPortWaitStrategy fails to recognize the open port and eventually times out. This issue seems to only occur on Linux machines. MacOS works fine.

Testcontainer Logs

Error: Port 4566 not bound after 60000ms

   at globalSetup.ts:38

  36 |   console.log(`Starting docker compose environment...`);
  37 |   const composeFilePath = path.resolve(__dirname, '../');
> 38 |   const environment = await new DockerComposeEnvironment(
     |                       ^
  39 |     composeFilePath,
  [40](https://github.com/bastionplatforms/monorepo/actions/runs/7124569757/job/19400552961?pr=553#step:12:41) |     'docker-compose.yml',
  [41](https://github.com/bastionplatforms/monorepo/actions/runs/7124569757/job/19400552961?pr=553#step:12:42) |   )

    at /home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/wait-strategies/host-port-wait-strategy.ts:52:15
    at IntervalRetry.retryUntil (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/common/retry.ts:49:16)
    at HostPortWaitStrategy.waitForPort (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/wait-strategies/host-port-wait-strategy.ts:[46](https://github.com/bastionplatforms/monorepo/actions/runs/7124569757/job/19400552961?pr=553#step:12:47):5)
    at HostPortWaitStrategy.waitForHostPorts (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/wait-strategies/host-port-wait-strategy.ts:27:7)
    at HostPortWaitStrategy.waitUntilReady (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/wait-strategies/host-port-wait-strategy.ts:14:5)
    at waitForContainer (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/wait-strategies/wait-for-container.ts:17:5)
    at /home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/docker-compose-environment/docker-compose-environment.ts:1[50](https://github.com/bastionplatforms/monorepo/actions/runs/7124569757/job/19400552961?pr=553#step:12:51):13
    at DockerComposeEnvironment.up (/home/runner/work/monorepo/monorepo/node_modules/testcontainers/src/docker-compose-environment/docker-compose-environment.ts:128:7)
    at globalSetup (/home/runner/work/monorepo/monorepo/e2e-tests/globalSetup.ts:38:23)

Steps to Reproduce

  1. Setup a GitHub Actions workflow to launch a compose project through testcontainers.
  2. The compose file:
    services:
      localstack:
        image: localstack/localstack
        ports:
          - "127.0.0.1:4566:4566"            # LocalStack Gateway
        environment:
          - DEBUG=${DEBUG-}
          - DOCKER_HOST=unix:///var/run/docker.sock
          - DYNAMODB_SHARE_DB=1
          - DYNAMODB_IN_MEMORY=1
        healthcheck:
          test: "curl --silent --fail localstack:4566/_localstack/health"
          interval: 1s
          retries: 5
          start_period: 20s
          timeout: 10s
        volumes:
          - "./.localstack/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh"  # ready hook
          - "./.localstack-volume:/var/lib/localstack"
          - "/var/run/docker.sock:/var/run/docker.sock"
  3. Run 'await new DockerComposeEnvironment(composeFilePath, 'docker-compose.yml').up();`
  4. See error...

Environment Information

sneko commented 7 months ago

@jalaziz @cristianrgreco any solution for this?

I was in a previous project using:

  const environment = await new DockerComposeEnvironment(composeFilePath, composeFile)
    .withEnvironment({
      ...
    })
    .withWaitStrategy(serviceName, Wait.forHealthCheck())
    .up([serviceName]);

But now for a new project with lot of dependencies updated (ESM modules, different Node version...), it times out saying Port 52670 not bound after 60000ms (it seems to come from https://github.com/testcontainers/testcontainers-node/blob/9805f226ed259e451c46f15d3988bdff992c46d8/packages/testcontainers/src/wait-strategies/host-port-wait-strategy.ts#L45-L57).

Note I tried to use testcontainers with the latest version and also v9.6.0 that is on the other project.

Thank you,

EDIT: I'm on a MacOS Intel

EDIT2: I did other attempts to run the test without ESM settings into my Jest setup, but it's the same error. It's so weird...

EDIT3: On my side I'm using the strategy Wait.forHealthCheck() for both the working and failing projects

sneko commented 7 months ago

After spending some time on it, it seems my old way of bindings ports to make them random on the list:

    ports:
      - '127.0.0.1::5432'

is not working for any reason on the new project.

Switching to:

    ports:
      - '5432'

Don't tell why... the old way is working in a project with direct dependencies versions aligned (also I don't remember why I had to use the 127.0.0.1 at that time). Hope it helps 👍

jalaziz commented 7 months ago

@jalaziz @cristianrgreco any solution for this?

Unfortunately no solution. I've switched to Wait.forHealthCheck() with custom healtchecks for the time being.

t3hmrman commented 1 month ago

I think I just ran into this -- except I can't actually get the custom health check to pass either, even with test: ["CMD-SHELL", "exit 0"] it just fails for however long.

It would be nice if there wasn't a default healthcheck (or it could be disbaled) that tried to use the ports -- it's helpful but a way to disable that logic would be nice