"""Phase 1 integration smoke tests — connect, auth-fail, network-fail. Marked ``integration`` so the default ``pytest`` invocation skips them. Run with ``pytest -m integration`` after ``docker compose up`` (or with the container already running). """ from __future__ import annotations import pytest import informix_db from tests.conftest import ConnParams pytestmark = pytest.mark.integration def test_connect_and_close(conn_params: ConnParams) -> None: """The happy path: connect with valid creds, then close cleanly.""" 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, ) assert conn.closed is False conn.close() assert conn.closed is True def test_close_is_idempotent(conn_params: ConnParams) -> None: """``close()`` must be safely callable multiple times.""" 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, ) conn.close() conn.close() # must not raise assert conn.closed is True def test_context_manager(conn_params: ConnParams) -> None: """``with`` block closes on exit.""" with 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, ) as conn: assert conn.closed is False assert conn.closed is True def test_bad_password_raises_operational_error(conn_params: ConnParams) -> None: """Auth failure must be ``OperationalError``, not a generic socket error.""" with pytest.raises(informix_db.OperationalError): informix_db.connect( host=conn_params.host, port=conn_params.port, user=conn_params.user, password="definitely-the-wrong-password", database=conn_params.database, server=conn_params.server, connect_timeout=5.0, read_timeout=5.0, ) def test_bad_host_raises_operational_error(conn_params: ConnParams) -> None: """Network-level failure must also be ``OperationalError``.""" # Pick an unused port on loopback. with pytest.raises(informix_db.OperationalError, match="cannot connect"): informix_db.connect( host="127.0.0.1", port=1, # IANA-reserved, nothing listens user="x", password="x", database="x", server="x", connect_timeout=2.0, ) def test_cursor_not_yet_implemented(conn_params: ConnParams) -> None: """Phase 1 declares ``cursor()`` as NotImplementedError; Phase 2 lands it.""" with 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, ) as conn, pytest.raises(NotImplementedError, match="Phase 2"): conn.cursor()