{"id":17966223,"url":"https://github.com/dallagi/excontainers","last_synced_at":"2025-03-17T14:15:36.964Z","repository":{"id":45255172,"uuid":"324620561","full_name":"dallagi/excontainers","owner":"dallagi","description":"Throwaway test containers for Elixir applications","archived":false,"fork":false,"pushed_at":"2024-08-20T06:44:21.000Z","size":173,"stargazers_count":61,"open_issues_count":1,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-02T13:08:02.052Z","etag":null,"topics":["docker","elixir","exunit","testing"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dallagi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-26T19:21:43.000Z","updated_at":"2025-01-27T07:08:03.000Z","dependencies_parsed_at":"2024-08-21T02:48:25.165Z","dependency_job_id":null,"html_url":"https://github.com/dallagi/excontainers","commit_stats":{"total_commits":182,"total_committers":4,"mean_commits":45.5,"dds":0.03296703296703296,"last_synced_commit":"8ba2b9a0f05ebcfee0fc1e08c494d1644b636044"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallagi%2Fexcontainers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallagi%2Fexcontainers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallagi%2Fexcontainers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallagi%2Fexcontainers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dallagi","download_url":"https://codeload.github.com/dallagi/excontainers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244047646,"owners_count":20389206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","elixir","exunit","testing"],"created_at":"2024-10-29T13:08:31.161Z","updated_at":"2025-03-17T14:15:36.936Z","avatar_url":"https://github.com/dallagi.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1 style=\"width: 100%; text-align: center\"\u003eExcontainers\u003c/h1\u003e\n  \u003cp style=\"font-size: 18px; white-space: pre-line\"\u003e \n    Throwaway test containers for Elixir/Erlang applications.\n    Heavily inspired by \u003ca href=\"https://www.testcontainers.org/\"\u003eTestcontainers\u003c/a\u003e.\n  \u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\" style=\"text-align: center;\"\u003e\n  \u003cimg alt=\"GitHub Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/dallagi/excontainers/ci.yml?branch=master\"\u003e\n  \u003cimg alt=\"Hex.pm\" src=\"https://img.shields.io/hexpm/v/excontainers\"\u003e\n\u003c/div\u003e\n\n## Project status\n\n**This package has not seen much real-world usage yet, hence it should not be considered as stable.**\nYou are encouraged to give it a try and report back problems you may experience.\n\nExcontainers was started as a personal study project to practice Elixir.\nThe core functionalities are implemented and tested, and I plan to eventually evolve it beyond the scope of providing throwaway containers for tests.\n\nHowever the development is slow, as I'm currently focused on other matters.\n\n## Installation\n\nThe package can be installed by adding `excontainers` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:excontainers, \"~\u003e 0.3.1\", only: [:dev, :test]},\n  ]\nend\n```\n\nDocumentation can be found at [https://hexdocs.pm/excontainers](https://hexdocs.pm/excontainers).\n\n## Usage\n\n#### ExUnit\n\nCreate a throwaway container (e.g., Redis) within a ExUnit test:\n\n``` elixir\ndefmodule Excontainers.RedisContainerTest do\n  use ExUnit.Case, async: true\n  import Excontainers.ExUnit\n\n  alias Excontainers.RedisContainer\n\n  container(:redis, RedisContainer.new())\n\n  test \"provides a ready-to-use redis container\", %{redis: redis} do\n    {:ok, conn} = Redix.start_link(RedisContainer.connection_url(redis))\n\n    assert Redix.command!(conn, [\"PING\"]) == \"PONG\"\n  end\nend\n```\n\nContainers declared using the `container` helper are created anew for each test.\nAlternatively, you can use `shared_container` to declare containers that are created once per each module and shared among its tests. \n\nTo create a container for a specific test only, use the `run_container` macro as follows:\n\n```elixir\ntest \"my test\" do\n  {:ok, redis} = run_container(RedisContainer.new())\n  connection_url = RedisContainer.connection_url(redis)\n  # ...\nend\n```\n\n`container`, `shared_container` and `run_container` will take care of cleaning up the containers once they are no longer needed.\n\n#### Direct usage\n\nIf you want to use Excontainers outside of your Exunit tests,\nor if you'd like to have direct control over the lifecycle of your containers,\nyou can use `Excontainers.Container`:\n\n```elixir\n{:ok, pid} = Container.start_link(@sample_container_config)\n```\n\nIt is also possible to place `Excontainers.Container` under a supervision tree:\n\n``` elixir\nchildren = [\n  {Excontainers.Container, @sample_container_config},\n]\n```\n\n### Containers\n\nThe following containers are currently provided pre-configured:\n\n* `Excontainers.MySqlContainer`\n* `Excontainers.PostgresContainer`\n* `Excontainers.RedisContainer`\n\nPlease open an issue if you'd like to see new ones.\n\n#### Custom containers\n\nExcontainers can run any container that docker can.\nCustom container configurations can be built via `Docker.Container.new`.\n\nFor example:\n\n```elixir\ncustom_container_config = Docker.Container.new(\n  \"alpine\"\n  cmd: ~w(echo hello world!),\n  labels: %{\"test-label-key\" =\u003e \"test-label-value\"},\n  privileged: false,\n  environment: %{\"SOME_KEY\" =\u003e \"SOME_VAL\"},\n  exposed_ports: [8080, \"1234/udp\": 1234], # 8080 will be mapped on a random host port\n  bind_mounts: [Docker.BindMount.new(\"host/src\", \"container/dest/\", \"ro\")],\n  wait_strategy: Docker.CommandWaitStrategy.new([\"./command/to/check/if/container/is/ready.sh\"])\n)\n```\n\nA builder-like API to customize container configuration is also provided:\n\n``` elixir\nalias Docker.Container\n\ncustom_container_config =\n  Container.new(\"alpine\", cmd: ~w(echo hello world!), privileged: false)\n  |\u003e Container.with_environment(\"SOME_KEY\", \"SOME_VAL\")\n  |\u003e Container.with_exposed_port(8080)\n  |\u003e Container.with_bind_mount(\"host/src\", \"container/dest\", \"ro\")\n```\n\n### Resources Reaping\n\nUnder normal circumstances, Excontainers removes the containers it spawned after they are no longer useful (i.e., during the teardown phase of tests).\nHowever, it may fail to do so when tests are interrupted abruptly, preventing ExUnit from running the necessary callbacks.\n\nExcontainers provides a _Resources Reaper_ that makes sure containers are removed when they are no longer useful.\nIt runs in its own docker container, so it is not affected by crashes of the BEAM or problems with the tests suite.\n\nTo enable the _Resources Reaper_, simply spawn it before you run your tests, e.g., by adding this to your `tests_helper.exs`:\n\n``` elixir\nExcontainers.ResourcesReaper.start_link()\n```\n\nContainers managed via the `container`, `shared_container` and `run_container` helpers for ExUnit are automatically registered to the _Resources Reaper_.\n\nWhen controlling the lifecycle of containers manually, containers can be registered to the _Resources Reaper_ like this:\n\n``` elixir\nExcontainers.ResourcesReaper.register({\"id\", my_container_id})\n```\n\n`{\"id\", my_container_id}` is a [filter for docker resources](https://docs.docker.com/engine/reference/commandline/ps/#filtering) that works on the id of the container.\nOther attributes (e.g., `label`s) could also be used.\n\nPlease note that using the id as filter for resources reaping may lead to (albeit unlikely) race conditions, where the BEAM crashes between the spawning of the container and the registration for resources reaping.\nA workaround for this is to use a filter that is known before spawning the container, e.g. a label that is then applied to the container.\n\n## Development\n\n### Testing\n\nTests require a machine with a docker daemon listening on the default unix socket `/var/run/docker.sock` and the cli docker client installed.\n\nRun tests with\n\n```\nmix test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdallagi%2Fexcontainers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdallagi%2Fexcontainers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdallagi%2Fexcontainers/lists"}