144 lines
3.7 KiB
Python
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
|