muse-agent-example/tests/单元/test_预算与配置.py
zizi d909d1bd1b 后端实现与用例身份:19 包集成落地并修复收尾缺陷
实现侧:
- 上下文:任务范围拆分为 范围校验/范围授权;索引按可发现口径重建、索引新鲜度改对称差;依赖校验统一快照漂移说明。
- 知识方法:方法与材料读取口径统一;超限方法材料按可选省略,核对路径不再二次计费;删除无合同的读时重算。
- 任务运行:新增 context.usage/tool.denied 事件类型;连接池常驻并在装配生命周期内开关;调用结算与核对分列。
- 效果评测/审校修订/交付连载/作者经验/作品规划:凭据冻结、标定消费、导出补证、事实引文核对等收尾修复。
- 资源加载:能力正文不再夹带索引用的导航注记(该注记此前进入角色与技能的模型提示)。
- 元数据:受保护骨架与代码保护属性对齐;字段校验与内置结构口径同步。
- 基础设施:环境预检进入装配生命周期;数据库连接运行期字段不参与相等比较;索引指纹归一化 jsonb 浮点。
- 删除被替代实现:7 份旧提示词模板与空壳 资料来源 读取器。

用例侧:
- 用例身份与导航元信息迁移;夹具补生命周期、同库暴露与模板封存;
- 本轮定向修复:方法材料省略、事实引文、迁移回执、额度与暂停用例、慢用例超时预算等。
2026-09-18 01:15:00 +08:00

126 lines
4.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""预算时间与金额、配置引用的确定性合同。"""
from datetime import datetime, timedelta
from decimal import Decimal
from zoneinfo import ZoneInfo
import pytest
from muse.任务运行.配置版本 import 凭据引用, 提供方配置, 运行配置内容, 配置版本错误
from muse.任务运行.预算管理 import 任务预算计划, 归属窗口, 角色预算, 预算错误, 额度策略
@pytest.mark.case_id(
"TC-2852b5b9a8d0",
environment="离线纯规则",
given="给定十个整点所在时刻",
when="计算固定本地日窗口",
then=["起点日期和小时一致,末窗到次日00"],
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
)
@pytest.mark.parametrize(
"hour,expected",
[(0, 0), (4, 0), (5, 5), (9, 5), (10, 10), (14, 10), (15, 15), (19, 15), (20, 20), (23, 20)],
ids=["00", "04", "05", "09", "10", "14", "15", "19", "20", "23"],
)
def test_五小时额度窗口承接每日边界__2852b5(hour: int, expected: int) -> None:
当前 = datetime(2026, 7, 16, hour, 30, tzinfo=ZoneInfo("Asia/Shanghai"))
窗口 = 归属窗口(当前)
assert 窗口.起点.strftime("%Y-%m-%dT%H") == f"2026-07-16T{expected:02}"
assert 窗口.终点 - 窗口.起点 == timedelta(hours=4 if hour >= 20 else 5)
@pytest.mark.case_id(
"TC-7790f820deda",
environment="离线纯规则",
given="给定四个旧窗口边界时刻",
when="计算下一边界等待秒数",
then=["分别为7200、1800、10800、60秒"],
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
)
@pytest.mark.parametrize(
"hour,minute,seconds",
[(3, 0, 7200), (19, 30, 1800), (21, 0, 10800), (23, 59, 60)],
ids=["morning", "20-boundary", "midnight", "last-minute"],
)
def test_下一窗口等待秒数按原日界线计算__7790f8(hour: int, minute: int, seconds: int) -> None:
当前 = datetime(2026, 9, 9, hour, minute, tzinfo=ZoneInfo("Asia/Shanghai"))
assert (归属窗口(当前).终点 - 当前).total_seconds() == seconds
@pytest.mark.case_id(
"NC-budget-plan-reserve",
environment="离线纯规则",
given="各角色计划次数、容量和单次金额",
when="登记任务预算计划",
then=["保留计划与570最坏预留,金额不足拒绝"],
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
)
def test_预算计划保留调用计划并按单次上限预留__a60003() -> None:
角色 = (
角色预算("writer", 45, 150, Decimal("5")),
角色预算("detector", 24, 150, Decimal("5")),
角色预算("judge", 45, 150, Decimal("5")),
)
计划 = 任务预算计划(
Decimal("570"), 角色, "approval-1", datetime(2030, 1, 1, tzinfo=ZoneInfo("UTC"))
)
assert 计划.最坏预留 == Decimal("570.000000")
assert 计划.冻结()["角色"][0]["计划次数"] == 45
with pytest.raises(预算错误):
任务预算计划(Decimal("569.99"), 角色, "approval-1", 计划.截止时间)
@pytest.mark.case_id(
"NC-budget-amount-validation",
environment="离线纯规则",
given="NaN、负数与无穷金额",
when="构造额度策略",
then=["不能作为确定可用额度"],
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
)
@pytest.mark.parametrize(
"amount",
[Decimal("NaN"), Decimal("-1"), Decimal("Infinity")],
ids=["nan", "negative", "infinite"],
)
def test_预算拒绝不确定或负数金额__a60001(amount: Decimal) -> None:
with pytest.raises(预算错误):
额度策略("quota", "1", amount, 6000)
@pytest.mark.case_id(
"NC-config-controlled-credentials",
environment="离线纯规则",
given="明确凭据引用或角色参数内明文凭据",
when="冻结运行配置内容",
then=["引用保留而不支持的凭据字段拒绝"],
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
)
def test_配置凭据只保留引用且调用参数不可藏入明文__a60002() -> None:
引用 = 凭据引用("api", "环境变量", "MUSE_PROVIDER_KEY")
内容 = 运行配置内容(
"direct",
"1",
"role-policy-1",
"release-1",
"quota-1",
{"writer": {"provider": "provider", "model": "model", "thinking": "high"}},
(引用,),
(提供方配置("provider", "responses", "https://provider.invalid/v1/responses", "api"),),
"price-1",
)
assert 内容.冻结()["凭据"][0]["位置"] == "MUSE_PROVIDER_KEY"
with pytest.raises(配置版本错误):
运行配置内容(
"direct",
"1",
"policy",
"release",
"quota",
{"writer": {"api_key": "synthetic-secret"}},
(),
(),
"price-1",
)