testcontainers / testcontainers-python

Testcontainers is a Python library that providing a friendly API to run Docker container. It is designed to create runtime environment to use during your automatic tests.
https://testcontainers-python.readthedocs.io/en/latest/
Apache License 2.0
1.53k stars 280 forks source link

docs: Add a more advance usecase documentation for ServerContainer #688

Closed Tranquility2 closed 4 weeks ago

Tranquility2 commented 4 weeks ago

Expanding the docs for using the ServerContainer with an example involving FastAPI container that is using Redis container.

Tranquility2 commented 4 weeks ago

Strange, this is working locally


Running Sphinx v7.2.6
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
writing output...
building [doctest]: targets for 1 source files that are out of date
updating environment: 0 added, 0 changed, 0 removed
reading sources...
looking for now-outdated files... none found
running tests...

Document: README
----------------
Building image from ./modules/generic/tests/samples/python_server
Built image 15d865ee1df5 with tag test-srv:latest
Pulling image testcontainers/ryuk:0.8.1
Container started: 6e48a56e9e2d
Waiting for container <Container: 6e48a56e9e2d> with image testcontainers/ryuk:0.8.1 to be ready ...
Pulling image test-srv:latest
Container started: 41f19f822e90
Waiting for container <Container: 41f19f822e90> with image test-srv:latest to be ready ...
Waiting for container <Container: 41f19f822e90> with image test-srv:latest to be ready ...
Waiting for container <Container: 41f19f822e90> with image test-srv:latest to be ready ...
Waiting for container <Container: 41f19f822e90> with image test-srv:latest to be ready ...
Removing image 15d865ee1df5
Building image from ./modules/generic/tests/samples/fastapi
Built image 1ded8da355fc with tag fastapi-test:latest
Pulling image fastapi-test:latest
Container started: 528db39b720c
Waiting for container <Container: 528db39b720c> with image fastapi-test:latest to be ready ...
Waiting for container <Container: 528db39b720c> with image fastapi-test:latest to be ready ...
Waiting for container <Container: 528db39b720c> with image fastapi-test:latest to be ready ...
Waiting for container <Container: 528db39b720c> with image fastapi-test:latest to be ready ...
Removing image 1ded8da355fc
Pulling image redis:latest
Container started: 6ca38c8fa53e
Waiting for container <Container: 6ca38c8fa53e> with image redis:latest to be ready ...
Waiting for container <Container: 6ca38c8fa53e> with image redis:latest to be ready ...
Waiting for container <Container: 6ca38c8fa53e> with image redis:latest to be ready ...
1 items passed all tests:
  13 tests in default
13 tests in 1 items.
13 passed and 0 failed.
Test passed.

Doctest summary
===============
   13 tests
    0 failures in tests
    0 failures in setup code
    0 failures in cleanup code
build succeeded.

Testing of doctests in the sources finished, look at the results in docs/_build/output.txt.```
codecov[bot] commented 4 weeks ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Please upload report for BASE (main@5216b02). Learn more about missing BASE report.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #688 +/- ## ======================================= Coverage ? 78.07% ======================================= Files ? 12 Lines ? 602 Branches ? 89 ======================================= Hits ? 470 Misses ? 106 Partials ? 26 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

Tranquility2 commented 4 weeks ago

ok, seems like redis is removed on poetry install -E generic that the CI is running. Will try adding it as a dep for generic (with relevant comment).

Tranquility2 commented 4 weeks ago

You are absolutely right, it doesn't... I lost all fait in the doctests :) (I assume its related to the way the doc tests is running but need to do some more testing) Let me try and fix it

Tranquility2 commented 4 weeks ago

ok so the fix is up and as I don't trust the doctests, I recreated a local test:

from testcontainers.redis import RedisContainer
from testcontainers.generic import ServerContainer
from testcontainers.core.image import DockerImage

with RedisContainer() as redis:
    redis_container_port = redis.port
    redis_container_ip_address = redis.get_docker_client().bridge_ip(redis._container.id)
    print(f"-> Redis avilable @ {redis_container_ip_address}:{redis_container_port}")

    with DockerImage(path="./modules/generic/tests/samples/advance_1", tag="advance-1:latest") as image:
        web_server = ServerContainer(port=80, image=image)
        web_server.with_env(key="REDIS_HOST", value=redis_container_ip_address)
        web_server.with_env(key="REDIS_PORT", value=redis_container_port)

        with web_server:
            web_server_port = web_server.get_exposed_port(web_server.internal_port)
            web_server.host = web_server.get_container_host_ip()
            print(f"--> Web server avilable @ {web_server.host}:{web_server_port}")

            web_server.get_api_url = lambda: web_server._create_connection_url()
            client = web_server.get_client()

            response = client.get("/")
            assert response.status_code == 200, "Server request failed"
            assert response.json() == {"status": "ok"}

            test_data = {"key": "test_key", "value": "test_value"}
            response = client.post("/set", params=test_data)
            assert response.status_code == 200, "Failed to set data"

            response = client.get(f"/get/{test_data['key']}")
            assert response.status_code == 200, "Failed to get data"
            assert response.json() == {test_data["key"]: test_data["value"]}

Running

poetry run pytest ./test.py -vs

Result

=================================================== test session starts ====================================================
platform linux -- Python 3.10.12, pytest-7.4.3, pluggy-1.4.0 -- /home/roy/.cache/pypoetry/virtualenvs/testcontainers-48VuS9Sz-py3.10/bin/python
cachedir: .pytest_cache
rootdir: /home/roy/projects/testcontainers-python
configfile: pyproject.toml
plugins: mock-3.14.0, anyio-4.3.0, asyncio-0.23.5, cov-4.1.0
asyncio: mode=strict
collecting ... Pulling image testcontainers/ryuk:0.8.1

--------------------------------------------------- live log collection ----------------------------------------------------
INFO     testcontainers.core.container:container.py:90 Pulling image testcontainers/ryuk:0.8.1
Container started: 851fdcaadda9
INFO     testcontainers.core.container:container.py:117 Container started: 851fdcaadda9
Waiting for container <Container: 851fdcaadda9> with image testcontainers/ryuk:0.8.1 to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: 851fdcaadda9> with image testcontainers/ryuk:0.8.1 to be ready ...
Pulling image redis:latest
INFO     testcontainers.core.container:container.py:90 Pulling image redis:latest
Container started: d938296091ad
INFO     testcontainers.core.container:container.py:117 Container started: d938296091ad
Waiting for container <Container: d938296091ad> with image redis:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: d938296091ad> with image redis:latest to be ready ...
Waiting for container <Container: d938296091ad> with image redis:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: d938296091ad> with image redis:latest to be ready ...
-> Redis avilable @ 172.17.0.3:6379
Building image from ./modules/generic/tests/samples/advance_1
INFO     testcontainers.core.image:image.py:53 Building image from ./modules/generic/tests/samples/advance_1
Built image 1b97cc837982 with tag advance-1:latest
INFO     testcontainers.core.image:image.py:58 Built image 1b97cc837982 with tag advance-1:latest
Pulling image advance-1:latest
INFO     testcontainers.core.container:container.py:90 Pulling image advance-1:latest
Container started: ed8396337ade
INFO     testcontainers.core.container:container.py:117 Container started: ed8396337ade
Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
--> Web server avilable @ localhost:33243
Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: ed8396337ade> with image advance-1:latest to be ready ...
INFO     httpx:_client.py:1026 HTTP Request: GET http://localhost:33243/ "HTTP/1.1 200 OK"
INFO     httpx:_client.py:1026 HTTP Request: POST http://localhost:33243/set?key=test_key&value=test_value "HTTP/1.1 200 OK"
INFO     httpx:_client.py:1026 HTTP Request: GET http://localhost:33243/get/test_key "HTTP/1.1 200 OK"
Removing image 1b97cc837982
INFO     testcontainers.core.image:image.py:78 Removing image 1b97cc837982
collected 0 items

================================================== no tests ran in 29.74s ==================================================
Tranquility2 commented 4 weeks ago

Now with the redis_container_ip_address = redis.get_docker_client().bridge_ip(redis._container.id) it will make more sense + we have the local script as a validation

Tranquility2 commented 4 weeks ago

Hope this will help #670

alexanderankin commented 4 weeks ago

yes i normally duplicate all doctests as regular tests for better IDE experience