Source code for pytest_databases.docker.gizmosql

from __future__ import annotations

import dataclasses
from typing import TYPE_CHECKING

import pytest
from adbc_driver_flightsql import DatabaseOptions
from adbc_driver_flightsql import dbapi as flightsql

from pytest_databases.helpers import get_xdist_worker_num
from pytest_databases.types import ServiceContainer, XdistIsolationLevel

if TYPE_CHECKING:
    from collections.abc import Generator

    from pytest_databases._service import DockerService


[docs] @dataclasses.dataclass class GizmoSQLService(ServiceContainer): """Service container for GizmoSQL database. GizmoSQL is a high-performance SQL server built on Apache Arrow Flight SQL with DuckDB/SQLite backends. The server always runs with TLS enabled using auto-generated self-signed certificates. """ username: str password: str @property def uri(self) -> str: """Return the gRPC+TLS URI for connecting to the service. GizmoSQL always runs with TLS enabled. """ return f"grpc+tls://{self.host}:{self.port}"
def _make_connection_kwargs( username: str, password: str, ) -> dict[str, str]: """Build the db_kwargs dictionary for ADBC Flight SQL connection. Always includes TLS_SKIP_VERIFY since GizmoSQL uses self-signed certificates. """ return { "username": username, "password": password, DatabaseOptions.TLS_SKIP_VERIFY.value: "true", }
[docs] @pytest.fixture(scope="session") def xdist_gizmosql_isolation_level() -> XdistIsolationLevel: """Xdist isolation level for GizmoSQL. Note: For xdist parallel testing, only 'server' isolation is recommended because DuckDB/SQLite backends don't support multiple databases per instance. Override this fixture to return 'server' when using pytest-xdist. """ return "database"
[docs] @pytest.fixture(scope="session") def gizmosql_image() -> str: """Docker image for GizmoSQL.""" return "gizmodata/gizmosql:latest"
[docs] @pytest.fixture(scope="session") def gizmosql_username() -> str: """Default username for GizmoSQL.""" return "gizmosql_username"
[docs] @pytest.fixture(scope="session") def gizmosql_password() -> str: """Default password for GizmoSQL.""" return "gizmosql_password"
[docs] @pytest.fixture(autouse=False, scope="session") def gizmosql_service( docker_service: DockerService, xdist_gizmosql_isolation_level: XdistIsolationLevel, gizmosql_image: str, gizmosql_username: str, gizmosql_password: str, ) -> Generator[GizmoSQLService, None, None]: def check(_service: ServiceContainer) -> bool: """Health check using ADBC Flight SQL connection.""" try: uri = f"grpc+tls://{_service.host}:{_service.port}" db_kwargs = _make_connection_kwargs(gizmosql_username, gizmosql_password) with flightsql.connect(uri=uri, db_kwargs=db_kwargs, autocommit=True) as conn, conn.cursor() as cur: cur.execute("SELECT 1") result = cur.fetchone() return result is not None and result[0] == 1 except Exception: # noqa: BLE001 return False worker_num = get_xdist_worker_num() name = "gizmosql" if worker_num is not None: # Only server isolation is supported for GizmoSQL (DuckDB doesn't support multiple DBs) name += f"_{worker_num}" env: dict[str, str] = { "GIZMOSQL_PASSWORD": gizmosql_password, "GIZMOSQL_USERNAME": gizmosql_username, } with docker_service.run( image=gizmosql_image, check=check, container_port=31337, name=name, env=env, timeout=90, pause=1.0, transient=xdist_gizmosql_isolation_level == "server", ) as service: yield GizmoSQLService( host=service.host, port=service.port, username=gizmosql_username, password=gizmosql_password, )
[docs] @pytest.fixture(autouse=False, scope="session") def gizmosql_connection( gizmosql_service: GizmoSQLService, ) -> Generator[flightsql.Connection, None, None]: db_kwargs = _make_connection_kwargs( gizmosql_service.username, gizmosql_service.password, ) with flightsql.connect( uri=gizmosql_service.uri, db_kwargs=db_kwargs, autocommit=True, ) as conn: yield conn