from __future__ import annotations import json from datetime import UTC, datetime, timedelta from decimal import Decimal import pytest from commercial_runtime_testkit import seed_meter from sqlalchemy import create_engine, select from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.pool import StaticPool import app.models # noqa: F401 - 注册完整 metadata from app.db.base_class import Base from app.models.commercial import CommercialCostEvent, UsageMeterEvent from app.models.commercial_runtime import CommercialRuntimeReservation from app.services.commercial_direct_operation import ( CommercialDirectOperationBridge, DirectOperationIdentity, ) @pytest.fixture() def factory() -> sessionmaker[Session]: engine = create_engine( "sqlite+pysqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) result = sessionmaker(bind=engine, expire_on_commit=False) try: yield result finally: Base.metadata.drop_all(engine) engine.dispose() def _identity(now: datetime, suffix: str = "a") -> DirectOperationIdentity: return DirectOperationIdentity( tenant_id="tenant-a", operation_key=f"SENSITIVE-OPERATION-{suffix}", run_key=f"SENSITIVE-RUN-{suffix}", tool_type="llm", tool_name="chat.completions", provider="OpenAI", model_name="gpt-test", started_at=now, ) def test_unconfigured_direct_operation_is_compatible_and_writes_no_fact( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) bridge = CommercialDirectOperationBridge(factory) permit = bridge.permit(_identity(now)) assert permit.enforced is False assert permit.allowed is True assert permit.reason_code == "runtime_meter_not_configured" with factory() as db: assert db.query(CommercialRuntimeReservation).count() == 0 assert db.query(UsageMeterEvent).count() == 0 def test_authoritative_tokens_settle_once_with_redacted_identity_and_cost( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter( db, "tenant-a", now, basis="total_tokens", preflight_quantity=Decimal("20"), internal_cost={ "enabled": True, "cost_category": "ai_inference", "unit": "token", "unit_cost": "0.002", "original_currency": "CNY", "reporting_currency": "CNY", "fx_rate": "1", "provider": "OpenAI", "model_name": "gpt-test", }, ) db.commit() identity = _identity(now, "tokens") bridge = CommercialDirectOperationBridge(factory) permit = bridge.permit(identity) result = bridge.complete( identity, outcome="succeeded", authoritative_quantities={ "input_tokens": 3, "output_tokens": 2, "total_tokens": 5, }, completed_at=now + timedelta(seconds=1), usage_source="openai_usage", usage_availability="available", ) replay = bridge.complete( identity, outcome="succeeded", authoritative_quantities={ "input_tokens": 3, "output_tokens": 2, "total_tokens": 5, }, completed_at=now + timedelta(seconds=1), usage_source="openai_usage", usage_availability="available", ) assert permit.allowed is True and permit.reservation_id assert permit.reserved_quantity == Decimal("20") assert result.status == "created" assert result.quantity == Decimal("5") assert replay.status == "replayed" with factory() as db: reservation = db.scalars(select(CommercialRuntimeReservation)).one() usage = db.scalars(select(UsageMeterEvent)).one() cost = db.scalars(select(CommercialCostEvent)).one() assert reservation.status == "committed" assert Decimal(reservation.actual_quantity or 0) == Decimal("5") assert Decimal(usage.quantity) == Decimal("5") assert Decimal(cost.cost_amount) == Decimal("0.0100") assert usage.billing_period_id == reservation.billing_period_id assert cost.billing_period_id == reservation.billing_period_id serialized = json.dumps(usage.metadata_json, ensure_ascii=False) assert "SENSITIVE-OPERATION" not in serialized assert "SENSITIVE-RUN" not in serialized assert db.query(UsageMeterEvent).count() == 1 assert db.query(CommercialCostEvent).count() == 1 @pytest.mark.parametrize( ("basis", "tool_type", "tool_name"), [ ("bytes", "storage", "attachment.upload"), ("pages", "ocr", "receipt.extract"), ("objects", "storage", "attachment.persist"), ("events", "connector", "financial.ingest"), ], ) def test_authoritative_resource_quantities_settle_without_estimation( factory: sessionmaker[Session], basis: str, tool_type: str, tool_name: str, ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter( db, "tenant-a", now, basis=basis, tool_type=tool_type, tool_name=tool_name, preflight_quantity=Decimal("100"), ) db.commit() identity = DirectOperationIdentity( tenant_id="tenant-a", operation_key=f"resource-operation:{basis}", run_key=f"resource-run:{basis}", tool_type=tool_type, tool_name=tool_name, started_at=now, ) bridge = CommercialDirectOperationBridge(factory) permit = bridge.permit(identity, requested_quantity=7) assert permit.allowed is True assert permit.reserved_quantity == Decimal("7") result = bridge.complete( identity, outcome="succeeded", authoritative_quantities={basis: 7}, completed_at=now + timedelta(seconds=1), usage_source=f"authoritative_{basis}", usage_availability="available", ) assert result.status == "created" assert result.quantity_basis == basis assert result.quantity == Decimal("7") with factory() as db: usage = db.scalars(select(UsageMeterEvent)).one() assert Decimal(usage.quantity) == Decimal("7") assert usage.metadata_json["usage_source"] == f"authoritative_{basis}" @pytest.mark.parametrize( ("outcome", "quantities", "reason_code", "actual"), [ ("outcome_unknown", {}, "authoritative_usage_unavailable", None), ( "provider_rejected", {"total_tokens": 25}, "actual_exceeds_preflight_reservation", Decimal("25"), ), ], ) def test_uncertain_or_over_reservation_call_enters_durable_reconciliation( factory: sessionmaker[Session], outcome: str, quantities: dict[str, int], reason_code: str, actual: Decimal | None, ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter( db, "tenant-a", now, basis="total_tokens", preflight_quantity=Decimal("20"), ) db.commit() identity = _identity(now, outcome) bridge = CommercialDirectOperationBridge(factory) assert bridge.permit(identity).allowed is True result = bridge.complete( identity, outcome=outcome, # type: ignore[arg-type] authoritative_quantities=quantities, completed_at=now + timedelta(seconds=1), usage_source="unavailable" if not quantities else "openai_usage", usage_availability="unavailable" if not quantities else "available", ) assert result.status == "reconciliation_required" assert result.reason_code == reason_code with factory() as db: reservation = db.scalars(select(CommercialRuntimeReservation)).one() assert reservation.status == "reconciliation_required" assert ( Decimal(reservation.actual_quantity) if reservation.actual_quantity is not None else None ) == actual assert db.query(UsageMeterEvent).count() == 0 assert db.query(CommercialCostEvent).count() == 0 def test_not_sent_releases_reservation_and_never_meters( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter(db, "tenant-a", now, basis="call") db.commit() identity = _identity(now, "not-sent") bridge = CommercialDirectOperationBridge(factory) assert bridge.permit(identity).allowed is True result = bridge.complete( identity, outcome="not_sent", authoritative_quantities={}, completed_at=now + timedelta(milliseconds=10), usage_source="unavailable", usage_availability="unavailable", ) assert result.status == "released" with factory() as db: reservation = db.scalars(select(CommercialRuntimeReservation)).one() assert reservation.status == "released" assert db.query(UsageMeterEvent).count() == 0 def test_released_operation_can_be_preflighted_again_after_business_rollback( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter(db, "tenant-a", now, basis="call") db.commit() identity = _identity(now, "released-retry") bridge = CommercialDirectOperationBridge(factory) assert bridge.permit(identity).allowed is True bridge.complete( identity, outcome="not_sent", authoritative_quantities={}, completed_at=now + timedelta(milliseconds=10), usage_source="business_transaction_rolled_back", usage_availability="unavailable", ) retry = bridge.permit(identity) result = bridge.complete( identity, outcome="succeeded", authoritative_quantities={"call": 1}, completed_at=now + timedelta(milliseconds=20), usage_source="accepted_retry", usage_availability="available", ) assert retry.allowed is True assert result.status == "created" with factory() as db: reservation = db.scalars(select(CommercialRuntimeReservation)).one() assert reservation.status == "committed" assert db.query(UsageMeterEvent).count() == 1 def test_variable_meter_without_explicit_hard_preflight_is_denied( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter(db, "tenant-a", now, basis="total_tokens") db.commit() permit = CommercialDirectOperationBridge(factory).permit(_identity(now, "no-max")) assert permit.enforced is True assert permit.allowed is False assert "preflight_quantity" in permit.reason with factory() as db: assert db.query(CommercialRuntimeReservation).count() == 0 def test_known_resource_quantity_above_configured_maximum_is_denied_before_call( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter( db, "tenant-a", now, basis="pages", tool_type="ocr", tool_name="receipt.extract", preflight_quantity=Decimal("10"), ) db.commit() identity = DirectOperationIdentity( tenant_id="tenant-a", operation_key="resource-operation:too-many-pages", run_key="resource-run:too-many-pages", tool_type="ocr", tool_name="receipt.extract", started_at=now, ) permit = CommercialDirectOperationBridge(factory).permit( identity, requested_quantity=11, ) assert permit.allowed is False assert "硬上限" in permit.reason with factory() as db: assert db.query(CommercialRuntimeReservation).count() == 0 def test_call_without_observed_permit_creates_reconciliation_backlog( factory: sessionmaker[Session], ) -> None: now = datetime.now(UTC) with factory() as db: seed_meter(db, "tenant-a", now, basis="call") db.commit() identity = _identity(now, "missing-permit") result = CommercialDirectOperationBridge(factory).complete( identity, outcome="provider_rejected", authoritative_quantities={}, completed_at=now + timedelta(milliseconds=50), usage_source="unavailable", usage_availability="unavailable", ) assert result.status == "reconciliation_required" assert result.reason_code == "missing_pre_execution_reservation" assert result.quantity == Decimal("1") with factory() as db: reservation = db.scalars(select(CommercialRuntimeReservation)).one() assert reservation.status == "reconciliation_required" assert reservation.resolution_code == "missing_pre_execution_reservation"