From e1e3d13b47923dd7124196e6b743799bd87b6885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Bartha?= <39852431+totallyzen@users.noreply.github.com> Date: Sat, 3 Aug 2024 06:20:58 +0200 Subject: [PATCH] feat(compose): ability to retain volumes when using context manager (#659) # changes On fiddling with a local project of mine, I realised we default to removing volumes when using compose. This is neat, but the context manager should also allow control over the volumes kept. This change adds the `keep_volumes` flag and hooks into `self.stop()` that already had the option. I added a test to cover the new functionality : --- core/testcontainers/compose/compose.py | 3 ++- .../basic_volume/docker-compose.yaml | 17 ++++++++++++++ core/tests/test_compose.py | 22 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 core/tests/compose_fixtures/basic_volume/docker-compose.yaml diff --git a/core/testcontainers/compose/compose.py b/core/testcontainers/compose/compose.py index 08dd313a..c5349b52 100644 --- a/core/testcontainers/compose/compose.py +++ b/core/testcontainers/compose/compose.py @@ -165,6 +165,7 @@ class DockerCompose: pull: bool = False build: bool = False wait: bool = True + keep_volumes: bool = False env_file: Optional[str] = None services: Optional[list[str]] = None docker_command_path: Optional[str] = None @@ -178,7 +179,7 @@ def __enter__(self) -> "DockerCompose": return self def __exit__(self, exc_type, exc_val, exc_tb) -> None: - self.stop() + self.stop(not self.keep_volumes) def docker_compose_command(self) -> list[str]: """ diff --git a/core/tests/compose_fixtures/basic_volume/docker-compose.yaml b/core/tests/compose_fixtures/basic_volume/docker-compose.yaml new file mode 100644 index 00000000..371ab9d3 --- /dev/null +++ b/core/tests/compose_fixtures/basic_volume/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + alpine: + image: alpine:latest + init: true + command: + - sh + - -c + - 'while true; do sleep 0.1 ; date -Ins; done' + read_only: true + volumes: + - type: volume + source: my-data + target: /var/lib/example/data + read_only: false + +volumes: + my-data: {} diff --git a/core/tests/test_compose.py b/core/tests/test_compose.py index e1a42655..72bfaefa 100644 --- a/core/tests/test_compose.py +++ b/core/tests/test_compose.py @@ -1,3 +1,4 @@ +import subprocess from pathlib import Path from re import split from time import sleep @@ -147,6 +148,27 @@ def test_compose_logs(): assert not line or container.Service in next(iter(line.split("|")), None) +def test_compose_volumes(): + _file_in_volume = "/var/lib/example/data/hello" + volumes = DockerCompose(context=FIXTURES / "basic_volume", keep_volumes=True) + with volumes: + stdout, stderr, exitcode = volumes.exec_in_container( + ["/bin/sh", "-c", f"echo hello > {_file_in_volume}"], "alpine" + ) + assert exitcode == 0 + + # execute another time to confirm the file is still there, but we're not keeping the volumes this time + volumes.keep_volumes = False + with volumes: + stdout, stderr, exitcode = volumes.exec_in_container(["cat", _file_in_volume], "alpine") + assert exitcode == 0 + assert "hello" in stdout + + # third time we expect the file to be missing + with volumes, pytest.raises(subprocess.CalledProcessError): + volumes.exec_in_container(["cat", _file_in_volume], "alpine") + + # noinspection HttpUrlsUsage def test_compose_ports(): # fairly straight forward - can we get the right port to request it