Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential macOS networking issue? #59

Open
paul-snively opened this issue Jan 9, 2025 · 1 comment
Open

Potential macOS networking issue? #59

paul-snively opened this issue Jan 9, 2025 · 1 comment

Comments

@paul-snively
Copy link

Hi everyone,

I'm trying to use testcontainers-hs on a project, having had great success with testcontainers-scala for years. My test currently looks like the following, a lightly-edited copy of the example from the home page:

import Control.Monad.Logger
import Data.Text.Encoding as T
import Database.Persist.Postgresql (ConnectionString, runMigration, withPostgresqlConn)
import Test.Tasty qualified as Tasty
import Test.Tasty.HUnit qualified as Tasty
import TestContainers.Tasty qualified as TC

data Endpoints = Endpoints
  { pgHost :: Text,
    pgPort :: Int
  }

-- | Sets up and runs the containers required for this test suite.
setupContainers :: (TC.MonadDocker m) => m Endpoints
setupContainers = do
  -- Launch the container based on the postgres 14 image.
  pgContainer <-
    TC.run $ TC.containerRequest (TC.fromTag "postgres:14-alpine")
      -- Expose the port 5432 from within the container. The respective port
      -- on the host machine can be looked up using `containerPort` (see below).
      TC.& TC.setExpose [5432]
      -- PostgreSQL requires POSTGRES_PASSWORD to be set.
      TC.& TC.setEnv [("POSTGRES_PASSWORD", "password")]
      -- Wait until the container is ready to accept requests. `run` blocks until
      -- readiness can be established.
      TC.& TC.setWaitingFor (TC.waitUntilMappedPortReachable 5432)

  let host = TC.containerIp pgContainer
      -- Look up the corresponding port on the host machine for the exposed
      -- port 5432.
      port = TC.containerPort pgContainer 5432
      connString :: ConnectionString = T.encodeUtf8 $ "host=" <> host <> " port=" <> show port <> " user=postgres dbname=postgres password=password sslmode=disable"
  runStdoutLoggingT $ withPostgresqlConn connString $ \backend ->
    liftIO $ runReaderT (runMigration migrateAll) backend

  pure
    $ Endpoints
      { pgHost = host,
        pgPort = port
      }

main :: IO ()
main =
  Tasty.defaultMain
    $
    -- Use `withContainers` to make the containers available in the closed over
    -- tests. Due to how Tasty handles resources `withContainers` passes down
    -- an IO action `start` to actually start up the containers. `start` can be
    -- invoked multiple times, Tasty makes sure to only start up the containrs
    -- once.
    --
    -- `withContainers` ensures the started containers are shut down correctly
    -- once execution leaves its scope.
    TC.withContainers setupContainers
    $ \start ->
      Tasty.testGroup
        "Teams service tests"
        [ Tasty.testCase "PostgreSQL test" $ do
            -- Actually start the containers!!
            Endpoints {..} <- start
            -- ... assert some properties
            pure (),
          Tasty.testCase "Another PostgreSQL test" $ do
            -- Invoking `start` twice gives the same Endpoints!
            Endpoints {..} <- start
            -- ... assert some properties
            pure ()
        ]

However, running the test gives me:

Teams service tests
  PostgreSQL test:         FAIL
    Exception: libpq: failed (connection to server at "172.17.0.3", port 57694 failed: could not receive data from server: Operation timed out
    could not send startup packet: Operation timed out
    )
    Use -p '/Teams service tests.PostgreSQL test/' to rerun this test only.
  Another PostgreSQL test: FAIL
    Exception: libpq: failed (connection to server at "172.17.0.3", port 57694 failed: could not receive data from server: Operation timed out
    could not send startup packet: Operation timed out
    )
    Use -p '/Another PostgreSQL test/' to rerun this test only.

2 out of 2 tests failed (84.90s)

And no variations of container IP or port work.

I suspect this has to do with the fact that Docker on macOS, of necessity, runs in its own virtual machine, so there's some magic I need to perform to get a working IP address to that VM. But that magic would still need to work in Linux as well, and I also believe it's something that, if necessary, the library should abstract away from.

Regardless of that, thanks for the Haskell port. It's nice to be able to refer to it on the basis of experience with the library in other languages, and I'm hoping this is just a minor hiccup on that path.

@alexbiehl
Copy link
Collaborator

Hey @paul-snively, thanks for the report.

I believe we need to look at the corresponding ruby or javascript ports of the library and figure out how they determine the container ip. I don't have much time but would love to explore that area.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants