fischer-agentkit/tests/unit/bitable/conftest.py

144 lines
3.7 KiB
Python

"""Shared fixtures for bitable unit tests.
Provides:
- ``bitable_db``: initialized BitableDB (skips if PG unavailable)
- ``bitable_service``: BitableService backed by bitable_db
- Factory functions: make_table, make_field, make_record, make_formula_field
"""
from __future__ import annotations
import os
import pytest
from agentkit.bitable.models import FieldOwner, FieldType
def _pg_available() -> bool:
"""Check if PostgreSQL is reachable via DATABASE_URL env var."""
url = os.environ.get("DATABASE_URL") or os.environ.get("AGENTKIT_DATABASE_URL")
return bool(url)
@pytest.fixture
async def bitable_db():
"""Initialize a fresh bitable DB for each test (skips if PG unavailable)."""
if not _pg_available():
pytest.skip("PostgreSQL not available (set DATABASE_URL)")
from agentkit.bitable.db import BitableDB
db = BitableDB()
try:
await db.init()
# Clean slate: drop and recreate bitable schema
from sqlalchemy import text
async with db.engine.begin() as conn:
await conn.execute(text("DROP SCHEMA IF EXISTS bitable CASCADE"))
await db.init() # re-create fresh
yield db
finally:
# Cleanup
from sqlalchemy import text
if db.engine is not None:
async with db.engine.begin() as conn:
await conn.execute(text("DROP SCHEMA IF EXISTS bitable CASCADE"))
await db.close()
@pytest.fixture
async def bitable_service(bitable_db):
"""BitableService backed by the test bitable_db."""
from agentkit.bitable.service import BitableService
yield BitableService(bitable_db)
# ── Factory fixtures ───────────────────────────────────────
@pytest.fixture
def make_table(bitable_service):
"""Factory: create a table and return it."""
counter = [0]
async def _make(
name: str | None = None,
description: str = "",
primary_key_field_id: str | None = None,
):
counter[0] += 1
return await bitable_service.create_table(
name=name or f"test_table_{counter[0]}",
description=description,
primary_key_field_id=primary_key_field_id,
)
return _make
@pytest.fixture
def make_field(bitable_service):
"""Factory: create a field and return it."""
counter = [0]
async def _make(
table_id: str,
name: str | None = None,
field_type: FieldType = FieldType.text,
config: dict | None = None,
owner: FieldOwner = FieldOwner.agent,
):
counter[0] += 1
return await bitable_service.create_field(
table_id=table_id,
name=name or f"field_{counter[0]}",
field_type=field_type,
config=config or {},
owner=owner,
)
return _make
@pytest.fixture
def make_record(bitable_service):
"""Factory: create a record and return it."""
counter = [0]
async def _make(table_id: str, values: dict | None = None):
counter[0] += 1
return await bitable_service.create_record(
table_id=table_id,
values=values or {},
)
return _make
@pytest.fixture
def make_formula_field(bitable_service):
"""Factory: create a formula field and return it."""
counter = [0]
async def _make(
table_id: str,
name: str | None = None,
formula_expr: str = "=1+1",
):
counter[0] += 1
return await bitable_service.create_field(
table_id=table_id,
name=name or f"calc_{counter[0]}",
field_type=FieldType.formula,
config={"formula_expr": formula_expr},
owner=FieldOwner.user,
)
return _make