"""Phase 2 Task 10(清理单 #1/#2/#3): config_views 单入口 + 限流 0 语义统一。 - #3 单入口: 六个配置消费视图(email/push/ai/contact_flags/context_seed_map/ name_to_region_extras)同住 app.platform.config_views 且可调用——服务层与 Phase 3 编辑器/试金石都从这里拿,散在各服务模块的定义已删(单一定义点); - #2 0 语义: ws_conn_limit 与 rate_limit_per_hour 行为统一——0 或负 = 回退出厂默认(非全拒)。config_validation 已拒 0/负,这里是直写快照/ 旧库数据的纵深防御层; - #1 FakeAI 收敛(conftest 单一定义点,四份拷贝删)的证明 = 既有测试 全绿,无新增断言。 """ from app.engine.routes.chat_rest import _resolve_rate_limit from app.engine.services.conn_limiter import ConnectionLimiter from app.engine.services.rate_limit import DEFAULT_MAX from app.platform import config_views def test_config_views_single_entry(): """一次 import 拿全六个 resolver——单一定义点,散装定义已收拢。""" names = ("resolve_email_settings", "resolve_push_settings", "resolve_ai_settings", "resolve_contact_flags", "context_seed_map", "name_to_region_extras") for name in names: assert callable(getattr(config_views, name)), ( f"config_views 缺消费视图 resolver: {name}") def test_name_to_region_extras_view_keeps_inline_semantics(): """ConversationManager.__init__ 内联取值的等价迁移: misc 组缺省/空 dict → None(``or None`` 语义原样保留);有扩表 → 原样返回。""" assert config_views.name_to_region_extras(None) is None assert config_views.name_to_region_extras({}) is None assert config_views.name_to_region_extras( {"misc": {"name_to_region_extras": {}}}) is None assert config_views.name_to_region_extras( {"misc": {"name_to_region_extras": {"德意志": "DE"}}}) == {"德意志": "DE"} def test_conn_limiter_zero_or_negative_limit_falls_back(): """ws_conn_limit=0/负 → 构造默认(原语义 0=全拒;统一后与姊妹键 rate_limit_per_hour 一致)。""" lim = ConnectionLimiter(limit=2) assert lim.try_acquire("t", "1.1.1.1", limit=0) is True # 0 ≠ 全拒 assert lim.try_acquire("t", "1.1.1.1", limit=0) is True assert lim.try_acquire("t", "1.1.1.1", limit=0) is False # 默认 2 满 assert lim.try_acquire("t", "2.2.2.2", limit=-3) is True # 负数同回退 def test_chat_rest_rate_limit_zero_or_negative_falls_back(): """rate_limit_per_hour=0/负 → DEFAULT_MAX(chat_rest 取值处与 ws_conn_limit 同款)。""" assert _resolve_rate_limit( {"engine": {"rate_limit_per_hour": 0}}) == DEFAULT_MAX assert _resolve_rate_limit( {"engine": {"rate_limit_per_hour": -5}}) == DEFAULT_MAX assert _resolve_rate_limit({}) == DEFAULT_MAX assert _resolve_rate_limit(None) == DEFAULT_MAX assert _resolve_rate_limit( {"engine": {"rate_limit_per_hour": 7}}) == 7