"""Shared pytest fixtures. The integration tests need a running Informix server on ``localhost:9088`` with the default Developer Edition credentials (``informix`` / ``in4mix`` on the ``sysmaster`` database). Run:: docker compose -f tests/docker-compose.yml up -d before the integration suite. See ``docs/DECISION_LOG.md`` for the pinned image digest and credential rationale. Connection parameters are overridable via env vars (``IFX_HOST`` / ``IFX_PORT`` / ``IFX_USER`` / ``IFX_PASSWORD`` / ``IFX_DATABASE`` / ``IFX_SERVER``) so the same suite runs against a non-default instance if you have one. """ from __future__ import annotations import os import socket from collections.abc import Iterator from typing import NamedTuple import pytest class ConnParams(NamedTuple): host: str port: int user: str password: str database: str server: str @pytest.fixture(scope="session") def conn_params() -> ConnParams: """Connection parameters for the test Informix instance.""" return ConnParams( host=os.environ.get("IFX_HOST", "127.0.0.1"), port=int(os.environ.get("IFX_PORT", "9088")), user=os.environ.get("IFX_USER", "informix"), password=os.environ.get("IFX_PASSWORD", "in4mix"), database=os.environ.get("IFX_DATABASE", "sysmaster"), server=os.environ.get("IFX_SERVER", "informix"), ) @pytest.fixture(scope="session", autouse=True) def _check_integration_server(request: pytest.FixtureRequest, conn_params: ConnParams) -> None: """Skip integration tests cleanly when the server isn't up. Avoids a sea of ``ConnectionRefusedError`` failures masking real bugs when the user runs the full suite without ``docker compose up``. """ if "integration" not in request.config.getoption("-m", default=""): return try: with socket.create_connection((conn_params.host, conn_params.port), timeout=2.0): return except OSError as e: pytest.skip( f"Informix server not reachable at {conn_params.host}:{conn_params.port} ({e}). " f"Start it with: docker compose -f tests/docker-compose.yml up -d" ) @pytest.fixture def ifx_connection(conn_params: ConnParams) -> Iterator[object]: """Open a fresh Informix connection for one test, then close it.""" import informix_db conn = informix_db.connect( host=conn_params.host, port=conn_params.port, user=conn_params.user, password=conn_params.password, database=conn_params.database, server=conn_params.server, connect_timeout=10.0, read_timeout=10.0, ) try: yield conn finally: conn.close()