pytest-docker icon indicating copy to clipboard operation
pytest-docker copied to clipboard

Option to keep containers running or use manually started ones

Open languitar opened this issue 4 years ago • 5 comments

I have a setup where spinning up the containers for tests is quite expensive. It would be nice if there was an option to either leave contains running after the first execution or to use a project started manually beforehand. That way, the expensive boot up of the containers can be avoided for subsequent tests.

languitar avatar Jun 04 '20 13:06 languitar

Hello,

I've run into this issue in the past myself. I solved it by temporarily removing the docker_services fixture from my tests. But that is not an elegant solution.

Do you have an idea of how this option could be implemented? What comes to mind is either some kind of environment variable or maybe looking at the names of containers running on the system.

I would prefer the first option because it would be less likely to cause strange issues.

Luminaar avatar Jun 09 '20 19:06 Luminaar

Pytest has command line options and this is what, for instance, pytest-kind uses for this purpose. I think the easiest thing would be to switch to a predictable project name and to provide a command line switch that disables the docker-compose down call.

https://codeberg.org/hjacobs/pytest-kind#user-content-pytest-options

languitar avatar Jun 09 '20 19:06 languitar

https://github.com/lovelysystems/lovely-pytest-docker/blob/master/src/lovely/pytest/docker/compose.py#L219 implements this

languitar avatar Oct 15 '20 14:10 languitar

It’s quite easy to implement a “keep alive” mode by defining/overriding a few pytest-docker fixtures.

By adding the following code, you’ll be able to run pytest with a new --keepalive option that won’t stop Docker containers. In order to avoid recreating containers in the next pytest run, this requires to have a predictable name for Dockers, which was done by overriding the docker_compose_project_name fixture.

def pytest_addoption(parser):
    """Add custom options to pytest.
    Add the --keepalive option for pytest.
    """

    parser.addoption("--keepalive", "-K", action="store_true", default=False, help="Keep Docker containers alive")


@pytest.fixture(scope="session")
def keepalive(request):
    """Check if user asked to keep Docker running after the test."""

    return request.config.option.keepalive


@pytest.fixture(scope="session")
def docker_compose_project_name(keepalive, docker_compose_project_name):
    """Override `docker_compose_project_name` to make sure that we have a
    unique project name if user asked to keep containers alive. This way
    we won’t create Docker container every time we will start pytest."""

    if keepalive:
        return "pytest-myproject"

    return docker_compose_project_name


@pytest.fixture(scope="session")
def docker_cleanup(keepalive, docker_cleanup):
    """If user asked to keep Docker alive, make `pytest-docker` execute
    the `docker-compose version` command. This way, Docker container won’t
    be shut down."""

    if keepalive:
        return "version"

    return docker_cleanup

otetard avatar Jul 27 '21 10:07 otetard

I do this for development work. I start my local cluster manually, and manage it myself. When running automated testing, I want pytest-docker to manage the cluster.

The simplest solution was to add a flag so that pytest-docker only runs when we set --env=docker like so:

# Add optional flags to the commandline
def pytest_addoption(parser):
    parser.addoption("--env", action="store", default="default")
    parser.addoption("--compose", action="store", default="v2")

    # add optional marker flags
    for marker, info in default_skip_markers.items():
        parser.addoption(
            f"--{marker}",
            action="store_true",
            default=False,
            help=info["help"],
        )

@fixture(scope="session")
def my_service(request):
    if request.config.getoption("--env") == "docker":
        request.getfixturevalue("my_container")
        
@fixture(scope="session")
def my_container(docker_ip, docker_services):
    """Ensure that HTTP service is up and responsive."""
    ...

lundybernard avatar Sep 28 '23 16:09 lundybernard