diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e5e0f18..233d137 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,30 +1,29 @@ -name: Run tests +name: Run parallel tests -on: ["push", "pull_request"] +on: [push, pull_request] jobs: - test: - + name: Tests / Python ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v3 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install hatch - - - name: Run tests - run: | - hatch run ci - + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get -y install podman + podman --version + systemctl --user enable podman + systemctl --user start podman + python -m pip install --upgrade pip + pip install hatch + - name: Run tests + run: | + hatch run ci diff --git a/README.rst b/README.rst index b6c6e9b..ea05e55 100644 --- a/README.rst +++ b/README.rst @@ -92,6 +92,16 @@ PG containers. You will need to do up to two extra things: can set the DBTESTTOOLS_PG_IP_ADDR environment variable. +If you want to use Podman instead of Docker engine you will need to follow +these steps: + + 1. Enable and start podman on your host + ```bash + systemctl --user enable podman + systemctl --user start podman + ``` + 2. `export DBTESTTOOLS_USE_PODMAN=1` variable. + This code has been in use daily on a large project at Cisco for a few years now, and is very stable. diff --git a/dbtesttools/engines/postgres.py b/dbtesttools/engines/postgres.py index 44614f2..f3e54a5 100644 --- a/dbtesttools/engines/postgres.py +++ b/dbtesttools/engines/postgres.py @@ -90,6 +90,26 @@ def has_savepoint(self): def setUp(self): """Do all the work to bring up a working Postgres fixture.""" super().setUp() + # Podman integration: optionally override Docker socket + if os.getenv("DBTESTTOOLS_USE_PODMAN") == "1": + if sys.platform == "darwin": + # MacOS Podman socket + podman_socket = ( + f"unix://{os.getenv('HOME')}" + f"/.local/share/containers/podman/machine/podman.sock" + ) + else: + # Linux Podman socket + podman_socket = ( + f"unix:///run/user/{os.getuid()}/podman/podman.sock" + ) + if os.path.exists(podman_socket.replace("unix://", "")): + os.environ["DOCKER_HOST"] = podman_socket + else: + raise FileNotFoundError( + f"Podman socket not found at {podman_socket}" + ) + self.client = docker.from_env() self.pull_image() self.find_free_port() @@ -156,7 +176,7 @@ def set_up_test_database(self): cur.close() c.close() - @retry(psycopg2.OperationalError, tries=30, delay=1) + @retry(psycopg2.OperationalError, tries=60, delay=1) def wait_for_pg_start(self): c = psycopg2.connect( "user='postgres' host='{ip}' port='{port}'" diff --git a/dbtesttools/tests/test_pgfixture.py b/dbtesttools/tests/test_pgfixture.py new file mode 100644 index 0000000..1c1b1b6 --- /dev/null +++ b/dbtesttools/tests/test_pgfixture.py @@ -0,0 +1,66 @@ +import os +import unittest +import warnings + +import testscenarios +import testtools +from sqlalchemy import text + +from dbtesttools.engines.postgres import PostgresContainerFixture + +warnings.filterwarnings("ignore", category=UserWarning, module="urllib3") + + +class TestPostgresContainer( + testscenarios.TestWithScenarios, testtools.TestCase +): + """Test that we can bring up a Postgres container.""" + + scenarios = [ + ("docker", {"podman": False}), + ("podman", {"podman": True}), + ] + + def setUp(self): + self.pg_fixture = None + super().setUp() + if self.podman: + os.environ["DBTESTTOOLS_USE_PODMAN"] = "1" + else: + os.environ.pop("DBTESTTOOLS_USE_PODMAN", None) + try: + fixture = PostgresContainerFixture(future=True) + fixture.setUp() + self.pg_fixture = fixture + except Exception as e: + print(f'[ERROR] Failed to start Postgres fixture: {e}') + + def tearDown(self): + if self.pg_fixture is not None: + if hasattr(self.pg_fixture, "engine"): + try: + self.pg_fixture.engine.dispose() + except Exception as e: + print(f"Warning: failed to dispose engine: {e}") + if hasattr(self.pg_fixture, "container"): + try: + self.pg_fixture.container.kill() + except Exception as e: + print(f"Warning: failed to kill container: {e}") + super().tearDown() + + def test_connection(self): + if self.pg_fixture is None: + self.fail("Postgres fixture was not initialized") + # Actually test that the database is reachable + conn = self.pg_fixture.connect() + try: + result = conn.execute(text("SELECT 1;")) + value = result.scalar() + self.assertEqual(value, 1) + finally: + conn.close() + + +if __name__ == "__main__": + unittest.main()