I have recently created, after having tried to get in touch with the creator of excontainers for quite some time, a new library called testcontainers_elixir, which I hope will be merged into the testcontainers family of repositories at some point. Im looking for any type of feedback and/or contributors. There is a lot of groundwork that needs to be done in the repository, so any help someone can give is precious.
It’s currently containing a very crude example of what I believe will be the core idea of the library. A macro function to create a container, that returns {:ok, container} if container was created successfully. No setup, no nothing. Just works. And it works wonderfully except for the fact I have just whipped up some code to get it working. A demo. A PoC.
I have added a project in the repo, and I have began thinking about how to get this working from top to bottom. Added some todos.
I want to solve the primary need, to create throw away testcontainers when running single tests. Shared containers and all that, I’m neglecting consciously.
I added this thread in testcontainers slack. So have some loose backing on that side.
What do you think ? Can you contribute ? Am I on the right track ? is GenServer really the best approach here for a reaper process ?
I have successfully moved away from the silly idea of using macro function and the library is now using plain old functions to do the grunt work. I have also successfully managed to test an nginx container with the library, even to get the whole welcome from nginx index page asserted in the test.
So whats on todo now ? Wait for log statement logic. I have wait for port and wait for http. Waiting for log statement match is the next step. then everything from there is just mapping keywords in elixir to docker engine api request structs. Conceptually easy, but not trivial in practice of course
A big item on the todo list, is the “get docker base url” logic that I have currently glossed over in my library. Im just using a hard coded http+unix:// url which works on Mac and Linux, but not Windows. So if anyone want to get their hands dirty on elixir code you are welcome to join in. Code will be reviewed and we will learn something new
I didn’t even know how docker engine api worked before I start
560 lines of elixir code in the lib folder in the project now, and I can already start using it, albeit with git reference in mix. Im beginning to get confident about publishing it to Hex soon, just need to add some more tests. Any good name suggestions is appreciated, but if not I’ll just go for testcontainers_elixir. Dont need any fancy naming conventions.
There is only one macro file in the project now, and that is a ex_unit.ex macro file that contains macros for injecting exunits on_exit callback function into the Docker.Api.run method. Other than that the code is basically pretty much magic free. I haven’t yet added type specs everywhere because I really hate all the false positives. But it will come at some point.
i have just released v1.0.0 of testcontainers-elixir
Test it out.
I have on my agenda to look into better ways to define a shared Postgres up front in test_helper, for example, that can be used by all tests including doctests. But right now containers are defined inside the test modules.
Patch release v1.0.1 is out, correcting a couple of annoying issues.
You can now define a globally shared container in test helper
This basically makes it possible to circumvent the need for a locally running Postgres server when testing your Phoenix application.
Its pretty awesome
Disclaimer: I have not yet tested setting up a phoenix application and adding testcontainers in test helper, so if someone can take it for a spin I am willing to fix any hiccups you might encounter. But in general test helper sets up the test environment and there is not much different in Phoenix with regards to that.
That’s actually pretty good, thanks for putting it together. I too periodically forget to groom my DB and then get surprised by stuff that should have never happened but still takes me 20 minutes to figure out that it was old tables or data leaking.
Cool! Looking forward to hearing about how it went
btw, bug in HexDocs generation … need to escape some System.get_env stuff …
this
# in your config/test.exs, if you want to keep appending the MIX_TEST_PARTITION env variable to the database name,
# you must set the database option in postgres_container macro to the same value
config :my_app, MyApp.Repo,
username: "postgres",
password: "postgres",
hostname: "localhost",
database: "my_app_test", # set this also in postgres_container macro database option, or remove the appending
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: 10
# for example, to set the database name to the one above, in application.ex:
@impl true
def start(_type, _args) do
postgres_container(app: :my_app, database: "my_app_test"),
# .. other setup code
]
should have been this
# in your config/test.exs, if you want to keep appending the MIX_TEST_PARTITION env variable to the database name,
# you must set the database option in postgres_container macro to the same value
config :my_app, MyApp.Repo,
username: "postgres",
password: "postgres",
hostname: "localhost",
database: "my_app_test#{System.get_env("MIX_TEST_PARTITION")}", # set this also in postgres_container macro database option, or remove the appending
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: 10
# for example, to set the database name to the one above, in application.ex:
@impl true
def start(_type, _args) do
postgres_container(app: :my_app, database: "my_app_test#{System.get_env("MIX_TEST_PARTITION")}"),
# .. other setup code
]
EDIT: fixed with a patch release with no release notes
Oh and it must be wrapped in a if Mix.env() == :test do ofc if you dont want the container starting in prod I mean … or actually failing to start in prod …
I did think about enforcing it to run on only in test environment. And I might adjust the macro later to take in an optional lambda for “when to run” and defaulting it to when mix env is :test, or something like that
docker connection strategies will test the urls. This means that if you dont have docker installed you will get an error, and tests won’t start. (v1.2.5)
found a proper way to handle async tasks inside the genserver, so that clients dont block the genserver message queue. (v1.2.4) (thanks to the forum :D)
So when you run any tests now that use testcontainers, they will be faster and if you dont have docker desktop (or normal docker) or testcontainers desktop installed, test will exit early.