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.51k stars 281 forks source link

Bug: Postgres Port not working #569

Closed Biscgit closed 3 months ago

Biscgit commented 3 months ago

Describe the bug

Creating a PostgresContainer gets stuck on creating when port= is defined and raises a Runtime error after 1-2 minutes except when setting to the default Postgres port 5432. Not defining it leads to random port mapping (as intended), but reading it with PostgresContainer.port returns the default Postgres port instead of the randomly selected one. It gets correctly mapped in the connection url though.

To Reproduce

import asyncpg
import pytest
from testcontainers.postgres import PostgresContainer

pytest_plugins = ('pytest_asyncio',)

# Gets stuck in creating container process and eventually raises a RuntimeException
@pytest.mark.asyncio
async def test_postgres_start():
    port = 3182
    with PostgresContainer("postgres:16-alpine", port=port) as pg:
        pass

# Reading port via .port returns the default port and not the actual one
@pytest.mark.asyncio
async def test_postgres_port():
    # Gets stuck in creating process:
    with PostgresContainer("postgres:16-alpine") as pg:
        port = pg.get_connection_url().split(":")[-1].split('/')[0]
        assert int(port) == pg.port

You can check the port with nmap as-well to be certain that the variable fails. Setting driver=None leads to the same results.

Runtime environment

Versions and specs (at time of creating latest stable versions):

alexanderankin commented 3 months ago

I think you are setting the port inside the container not outside. There is a separate API for what you are trying to do.

On Fri, May 10, 2024, 3:47 PM David Horvát @.***> wrote:

Describe the bug

Creating a PostgresContainer gets stuck on creating when port= is defined and raises a Runtime error after 1-2 minutes except when setting to the default Postgres port 5432. Not defining it leads to random port mapping (as intended), but reading it with PostgresContainer.port returns the default Postgres port instead of the randomly selected one. It gets correctly mapped in the connection url though.

To Reproduce

import ... pytest_plugins = ('pytest_asyncio',)

Gets stuck in creating container process and raises a RuntimeException @.*** def test_postgres_start(monkeypatch):

port = 3182
with PostgresContainer(
        "postgres:16-alpine",
        port=port,
) as pg:
    ...

Reading port via .port returns the default port and not the actual @.*** def test_postgres_port(monkeypatch):

# Gets stuck in creating process:
with PostgresContainer(
        "postgres:16-alpine"
) as pg:
    port = pg.get_connection_url().split(":")[-1].split('/')[0]
    assert port != pg.port

You can check the port with nmap as-well to be certain that the variable fails. Setting driver=None leads to the same results.

Runtime environment

Versions and specs (at time of creating latest stable versions):

  • Machine: EndeavourOS Linux 6.8.9-arch1-2 x86_64 GNU/Linux
  • Docker: v26.1.2
  • Python: v3.12.3
    • pip: v24.0
    • pytest: v8.2.0
    • pytest-asyncio: v0.23.6
    • asyncpg: v0.29.0
    • testcontainers: v4.4.0

— Reply to this email directly, view it on GitHub https://github.com/testcontainers/testcontainers-python/issues/569, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACECGJFH7DB4VBFIA4F3JXLZBUP6NAVCNFSM6AAAAABHRFCYL6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGI4TAMZRG4YDINQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

Biscgit commented 3 months ago

Hello! Would it be possible to maybe expand the documentation on what exactly port= does? Because neither in the Python documentation nor in Postgres-Tests was I able to find any hints. Or implementing a simple function for getting the containers port directly.

alexanderankin commented 3 months ago

you can get the exposed port using this function: https://github.com/testcontainers/testcontainers-python/blob/main/core/testcontainers/core/container.py#L140

https://github.com/testcontainers/testcontainers-python/blob/690b9b4526dcdf930c0733c227009af208f47cda/core/testcontainers/core/container.py#L139-L148

e.g. by:

mkdir tcp-postgres-port-demo
cd tcp-postgres-port-demo
python -m venv .venv
test -d .venv/bin && . .venv/bin/activate
test -d .venv/Scripts && . .venv/Scripts/activate
pip install testcontainers pytest
cat > example.py <<EOF
from testcontainers.postgres import PostgresContainer
def test():
    with PostgresContainer("postgres:16-alpine") as pg:
        print(pg.get_exposed_port(5432))
EOF
pytest -s example.py
alexanderankin commented 3 months ago

documentation can be improved a lot, you are right about that

Biscgit commented 3 months ago

okay, that works too, thanks :+1: