feat(platform): close AI expense value loop
Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
This commit is contained in:
397
server/tests/test_commercial_direct_operation.py
Normal file
397
server/tests/test_commercial_direct_operation.py
Normal file
@@ -0,0 +1,397 @@
|
||||
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"
|
||||
Reference in New Issue
Block a user