Looking for feedback and/or contributors for testcontainers_elixir

Hi!

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 ?

Thanks!

2 Likes

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 :wink:

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 :wink:

I didn’t even know how docker engine api worked before I start :wink:

1 Like

Update:

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.

1 Like

Update!!

Published two packages to Hex today:

  1. ex_docker_engine_api | Hex (there is excontainers and docker_engine_api but both of these are useless as I need something stable to depend on)
  2. testcontainers | Hex

The latter being the interesting one :wink:

Im crossing fingers that some might find it useful! I have committed to this project, and I’m ready for all the weird corner cases.

Maybe you want to join in on the fun and improve on it? You are welcome! :slight_smile:

2 Likes

Update!

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.

1 Like

Update!

Patch release v1.0.1 is out, correcting a couple of annoying issues.

You can now define a globally shared container in test helper :raised_hands:

This basically makes it possible to circumvent the need for a locally running Postgres server when testing your Phoenix application.

Its pretty awesome :raised_hands:

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.

1 Like

Update!

Feature release v1.1.0 is out, correcting a minor bug and adding a huge feature.

You can now use the Testcontainers.Ecto macro in application.ex like this:

  import Testcontainers.Ecto

  @impl true
  def start(_type, _args) do
    postgres_container(app: my_app)
    
    # .. other code
  end

Thats mostly whats needed. You also need to remove the default test alias in aliases function in mix.exs, but you can all read more in the rep readme here GitHub - jarlah/testcontainers-elixir: Testcontainers is an Elixir library that supports ExUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. or in the api docs API Reference — testcontainers v1.1.0

Have fun with it :slight_smile: Personally I love it. I no longer have to manage the Postgres instance manually any more.

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.

Will definitely try your library.

1 Like

Cool! Looking forward to hearing about how it went :slight_smile:

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 :wink: 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

I fixed a bug where the new macro didnt work in github actions, and published a new patch release 1.1.2.

Update

Just released a new feature

You can now use testcontainers with MySql adapter for ecto too :partying_face:

The plan is to increase the number of supported databases for use with ecto.

Right now the plan is to add more containers, among them mongodb, including ecto support for it. And other commonly used databases with Phoenix.

2 Likes

(Big?) Update

v1.2.3 is released.

It fixes a glaring issue about container cleanup, that caused parallell test runs to fail each other in random ways.

I needed to do some huge refactor of the library, internally, which didn’t added breaking changes in the api, luckily.

But for ExUnit and disposable containers inside the tests, you must now add

Testcontainers.start_link()

in test/test-helper.exs

This is not needed if using the Testcontainers.Ecto module, which can be dropped into application.ex as shown in the readme.

I considered making a minor version change, but this only fixes bugs and discrepancies.

2 Likes

Update!

v1.2.4 and v1.2.5 is released

  • 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.

1 Like

Repository has now moved into Testcontainers org :raised_hands:

Closed on request of the OP