-
Notifications
You must be signed in to change notification settings - Fork 22
Description
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.