test_interrupted_model_budget.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import asyncio
  2. from uuid import uuid4
  3. import pytest
  4. from test_after_sales import scenario # noqa: F401
  5. from test_money_budget import PRICE, PROVIDER, approve, budget, setup
  6. from test_token_budget import sample
  7. from zhifu.modules.agent_runtime.budget import change_entry, mark_pending_unknown, reserve
  8. from zhifu.modules.agent_runtime.models import TokenAccount, TokenEntry
  9. from zhifu.modules.billing.models import MoneyEntry
  10. from zhifu.modules.identity.auth import now
  11. @pytest.mark.parametrize("kind", ["agent", "memory"])
  12. async def test_interrupted_budget_preserves_scope_and_late_settlement(scenario, kind): # noqa: F811
  13. sessions, tenant = scenario["app"].state.sessions, scenario["tenant"].bytes
  14. await setup(scenario)
  15. await budget(scenario, 1000000)
  16. await approve(scenario, PRICE)
  17. observed = sample()
  18. reference, other_reference = uuid4().bytes, uuid4().bytes
  19. pending, completed, other = [uuid4().bytes for _ in range(3)]
  20. for identifier, target in (
  21. (pending, reference), (completed, reference), (other, other_reference)
  22. ):
  23. await reserve(sessions, tenant, identifier, kind, target,
  24. PRICE["model"], 6000, provider=PROVIDER)
  25. await change_entry(sessions, tenant, completed, usage=observed["usage"])
  26. # 真实事务创建待计量记录;错误租户和调用类型不能改变其他业务的预算状态。
  27. await mark_pending_unknown(sessions, uuid4().bytes, kind, reference)
  28. await mark_pending_unknown(
  29. sessions, tenant, "memory" if kind == "agent" else "agent", reference)
  30. async with sessions() as session:
  31. assert (await session.get(TokenEntry, pending)).status == "PENDING"
  32. await asyncio.gather(*(
  33. mark_pending_unknown(sessions, tenant, kind, reference) for _ in range(3)))
  34. async with sessions() as session:
  35. assert (await session.get(TokenEntry, pending)).status == "UNKNOWN"
  36. assert (await session.get(MoneyEntry, pending)).status == "UNKNOWN"
  37. assert (await session.get(TokenEntry, pending)).version == 2
  38. assert (await session.get(TokenEntry, completed)).status == "SETTLED"
  39. assert (await session.get(TokenEntry, other)).status == "PENDING"
  40. account = await session.get(TokenAccount, (tenant, now().date()))
  41. assert account.reserved == 12000
  42. assert account.consumed == observed["usage"]["total_tokens"]
  43. # 使用已有供应商真实usage验证迟到结算与清理竞争,不生成模型响应。
  44. await asyncio.gather(
  45. change_entry(sessions, tenant, pending, usage=observed["usage"]),
  46. mark_pending_unknown(sessions, tenant, kind, reference),
  47. )
  48. async with sessions() as session:
  49. assert (await session.get(TokenEntry, pending)).status == "SETTLED"
  50. assert (await session.get(MoneyEntry, pending)).status == "SETTLED"
  51. account = await session.get(TokenAccount, (tenant, now().date()))
  52. assert account.reserved == 6000
  53. assert account.consumed == 2 * observed["usage"]["total_tokens"]