"""Benchmark fixtures — long-lived connections + populated test tables. The end-to-end benchmark suite needs: * A persistent connection (creating one per benchmark inflates the cost by the login handshake, ~5-15ms — distorts micro-second measurements). * A pre-populated test table so SELECT/UPDATE benchmarks have rows to iterate. Both fixtures are session-scoped so the table is created exactly once even when the same benchmark is iterated over many rounds. """ from __future__ import annotations import contextlib from collections.abc import Iterator import pytest import informix_db from tests.conftest import ConnParams BENCH_TABLE_ROWS = 1000 # rows in the populated benchmark table @pytest.fixture(scope="session") def bench_conn(conn_params: ConnParams) -> Iterator[informix_db.Connection]: """One long-lived autocommit connection for the entire bench session.""" 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, autocommit=True, ) try: yield conn finally: conn.close() @pytest.fixture(scope="session") def bench_table(bench_conn: informix_db.Connection) -> Iterator[str]: """Create + populate a 1k-row table for SELECT/UPDATE benchmarks. Yields the table name. The table is dropped at session teardown. Schema covers the common type mix: INT id, VARCHAR name, INT (counter), FLOAT (value), DATE (created). """ table = "p21_bench" cur = bench_conn.cursor() with contextlib.suppress(informix_db.Error): cur.execute(f"DROP TABLE {table}") cur.execute( f"CREATE TABLE {table} (" " id INT, name VARCHAR(64), counter INT," " value FLOAT, created DATE)" ) # Populate via executemany so setup is fast. rows = [ ( i, f"row_{i:04d}", i * 7, float(i) * 1.5, None, # DATE NULL — keeps fixture small ) for i in range(BENCH_TABLE_ROWS) ] cur.executemany( f"INSERT INTO {table} VALUES (?, ?, ?, ?, ?)", rows, ) try: yield table finally: with contextlib.suppress(informix_db.Error): cur.execute(f"DROP TABLE {table}")