mirror of
https://github.com/pydantic/pydantic-ai.git
synced 2026-10-12 02:21:31 +00:00
86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
"""A real Absurd schema on PostgreSQL, and task contexts entered the way an Absurd worker enters them.
|
|
|
|
Every test runs against Absurd's own SQL, so step naming, encounter-order disambiguation and
|
|
checkpoint storage are Absurd's, not a stand-in's. The database is named by `ABSURD_TEST_DATABASE_URL`:
|
|
|
|
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:16
|
|
export ABSURD_TEST_DATABASE_URL=postgresql://postgres:[email protected]:5432/postgres
|
|
|
|
Without it the tests skip. With it but no reachable server they also skip, unless
|
|
`ABSURD_REQUIRE_LIVE` is set (CI does), where they fail instead.
|
|
|
|
`fixtures/absurd.sql` is Absurd's `sql/absurd.sql` (https://github.com/earendil-works/absurd,
|
|
Apache-2.0). Refresh it from the Absurd release matching the `absurd-sdk` floor in
|
|
`pydantic-ai-harness[absurd]`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from collections.abc import AsyncGenerator
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from ...conftest import try_import
|
|
|
|
with try_import() as imports_successful:
|
|
from absurd_sdk import AsyncAbsurd
|
|
from psycopg import AsyncConnection
|
|
from psycopg.rows import TupleRow
|
|
|
|
if TYPE_CHECKING:
|
|
AsyncConn = AsyncConnection[TupleRow]
|
|
|
|
ABSURD_SQL = Path(__file__).parent / 'fixtures' / 'absurd.sql'
|
|
|
|
|
|
@pytest.fixture(scope='session')
|
|
def db_dsn() -> str:
|
|
"""Install Absurd's schema, once, in the database named by `ABSURD_TEST_DATABASE_URL`."""
|
|
import psycopg
|
|
|
|
dsn = os.environ.get('ABSURD_TEST_DATABASE_URL')
|
|
if not dsn:
|
|
pytest.skip('ABSURD_TEST_DATABASE_URL is not set')
|
|
try:
|
|
with psycopg.connect(dsn, autocommit=True, connect_timeout=5) as conn:
|
|
# xdist workers share the database, and the schema script is not re-runnable.
|
|
conn.execute('SELECT pg_advisory_lock(8126)')
|
|
if conn.execute("SELECT to_regnamespace('absurd') IS NULL").fetchone() == (True,):
|
|
conn.execute(ABSURD_SQL.read_bytes())
|
|
conn.execute('SELECT pg_advisory_unlock(8126)')
|
|
# Only when the configured server is unreachable, which CI never is.
|
|
except psycopg.OperationalError as exc: # pragma: no cover
|
|
message = f'PostgreSQL is unreachable at ABSURD_TEST_DATABASE_URL: {exc}'
|
|
if os.environ.get('ABSURD_REQUIRE_LIVE', '').lower() in {'1', 'true', 'yes'}:
|
|
pytest.fail(message)
|
|
pytest.skip(message)
|
|
return dsn
|
|
|
|
|
|
@pytest.fixture
|
|
async def async_conn(db_dsn: str) -> AsyncGenerator[AsyncConn]:
|
|
"""An autocommit connection to the test database."""
|
|
async with await AsyncConnection.connect(db_dsn, autocommit=True) as conn:
|
|
yield conn
|
|
|
|
|
|
@pytest.fixture
|
|
def queue_name() -> str:
|
|
"""A queue name unique to the test, so runs on a kept database cannot collide."""
|
|
return f'test_{uuid4().hex[:8]}'
|
|
|
|
|
|
@pytest.fixture
|
|
async def absurd(async_conn: AsyncConn, queue_name: str) -> AsyncGenerator[AsyncAbsurd]:
|
|
"""An Absurd client on a queue of its own, dropped after the test."""
|
|
client = AsyncAbsurd(async_conn, queue_name=queue_name)
|
|
await client.create_queue()
|
|
try:
|
|
yield client
|
|
finally:
|
|
await client.drop_queue()
|