Jc2k/pytest-docker-tools

Change container environment variables between tests

KostasKgr opened this issue · 1 comments

Hello, thanks for the amazing library! I am quite new to pytest and trying to figure out the following.

I am creating an application that reads and writes to kafka and I don't want to have messages spilling out from one test to the next. Also starting up kafka and zookeeper takes around 10 seconds.

So my thoughts where to have kafka in session scope, but change which topics my application reads/writes to between tests, and in this way avoid data spilling over, and keep test time low.

My container looks something like this:

myapp = container(
    image='{myapp_image.id}',
    network='{integration_test_network.name}',
    scope="module",
    ports={
        '5000/tcp': None,
    },
    environment={
        "CONSUMER_AUTO_OFFSET_RESET": "earliest"
    }
)

This way the application always reads and writes to the same topic

After looking at the readme I was considering to set per module the value of the whole environment key so that I could do something like this on each module

@pytest.fixture(scope="module")
def myapp_environment():
    return {
        "CONSUMER_AUTO_OFFSET_RESET": "earliest",
        "CONSUMER_TOPIC": "consume.test_a",
        "PRODUCER_TOPIC": "produce.test_a",
    }

However this doesn't work in either of those two cases of rewriting myapp fixture:

environment='{myapp_environment}'

Causes the following error:

    environment = "{'CONSUMER_AUTO_OFFSET_RESET': 'earliest', 'CONSUMER_TOPIC': 'consume.test_a', 'PRODUCER_TOPIC': 'produce.test_a'}"

       def inject_proxy_environment(self, environment):
       >       return proxy_env + environment
       E       TypeError: can only concatenate list (not "str") to list
.direnv\lib\site-packages\docker\api\container.py:419: in create_container
environment=myapp_environment

Causes the following error:
    Fixture "myapp_environment" called directly. Fixtures are not meant to be called directly,
    but are created automatically when test functions request them as parameters.
    See https://docs.pytest.org/en/latest/fixture.html for more information about fixtures, and
    https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly about how to update your code.

Is what I am thinking possible? How would you go about achieving it in pytest and this library

Jc2k commented

I'm so sorry for not noticing this ticket, it looks like it got lost in a sea of notification from another project :-/

If this is still something you are interested in, i wanted to check you were doing something like this:

@pytest.fixture(scope="module")
def myapp_environment():
    return {
        "CONSUMER_AUTO_OFFSET_RESET": "earliest",
        "CONSUMER_TOPIC": "consume.test_a",
        "PRODUCER_TOPIC": "produce.test_a",
    }

myapp = container(
    image='{myapp_image.id}',
    network='{integration_test_network.name}',
    scope="module",
    ports={
        '5000/tcp': None,
    },
    environment='{myapp_environment}',
)

So the string fixture dependency magic here only works for strings. It works enough to pull in a dependency on myapp_environment, but the "{foo}" is ultimately a python string operation. It pulls in your dict and turns it into a string, which then causes a type error inside the docker library.

A workaround is to reference each key seperately. It's a bit more typing but you can do:

@pytest.fixture(scope="module")
def myapp_environment():
    return {
        "CONSUMER_AUTO_OFFSET_RESET": "earliest",
        "CONSUMER_TOPIC": "consume.test_a",
        "PRODUCER_TOPIC": "produce.test_a",
    }

myapp = container(
    image='{myapp_image.id}',
    network='{integration_test_network.name}',
    scope="module",
    ports={
        '5000/tcp': None,
    },
    environment={
        "CONSUMER_AUTO_OFFSET_RESET":  "{myapp_environment['CONSUMER_AUTO_OFFSET_RESET']}",
        "CONSUMER_TOPIC": "{myapp_environment['CONSUMER_TOPIC']}",
        "PRODUCER_TOPIC": "{myapp_environment['PRODUCER_TOPIC']}",
    }
)

Not 100% that will work, it's been a while since I worked on this, but it's worth a shot.

The error you are getting about calling fixtures directly might well be an indication that we were unknowingly relying on an undocumented behaviour of pytest which has now been restricted. If the above works but you are still getting the warning let me know and i'll try and find some time to figure out a fix for it.