feat: 服务层配置接线——email/push/rate_limit/AI凭据/行为开关/映射表/种子键
Task 9: 服务层对全局 settings 的业务引用清零,每个 DEFAULT_CONFIG 组 都有真实消费方。resolve_*_settings(email/push/ai)以空槽回退 env (平台默认层);contact 行为开关/种子白名单/国名扩表/限流上限经 manager 的 runtime.config 接线。收口: lead_push session_factory 必填、 config.py 死代码清理、PromptProvider frozen、no_contact 视图直取、 AIService wall 参数定型 CompiledWall。403 测试全绿(389+14)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -335,19 +335,24 @@ def _mk_push_log(async_db, status="pending"):
|
||||
|
||||
|
||||
def _run_push_case(async_db, monkeypatch, do_post, log_id):
|
||||
"""注入 _do_post/_sleep/async_session 后驱动 _run_push,返回退避序列。"""
|
||||
"""注入 _do_post/_sleep 后驱动 _run_push(Task 9: session_factory 直传,
|
||||
不再借模块级 async_session——已删除),返回退避序列。"""
|
||||
from app.engine.services import lead_push_service as svc
|
||||
sleeps = []
|
||||
|
||||
async def fake_sleep(s):
|
||||
sleeps.append(s)
|
||||
|
||||
monkeypatch.setattr(svc, "_do_post", do_post)
|
||||
# Task 9: _do_post 多了 config_data 参数——适配层吸收,各用例 fake 保持单参
|
||||
async def adapted_do_post(payload, config_data=None):
|
||||
return await do_post(payload)
|
||||
|
||||
monkeypatch.setattr(svc, "_do_post", adapted_do_post)
|
||||
monkeypatch.setattr(svc, "_sleep", fake_sleep)
|
||||
monkeypatch.setattr(svc, "async_session", async_db)
|
||||
|
||||
async def run():
|
||||
await svc._run_push(log_id, {"external_key": "ai-kefu-x", "event": "new"})
|
||||
await svc._run_push(
|
||||
log_id, {"external_key": "ai-kefu-x", "event": "new"}, async_db)
|
||||
asyncio.run(run())
|
||||
return sleeps
|
||||
|
||||
@@ -482,7 +487,7 @@ def test_fire_pending_creates_tasks(monkeypatch):
|
||||
from app.engine.services import lead_push_service as svc
|
||||
pushed = []
|
||||
|
||||
async def fake_run(log_id, payload, session_factory=None):
|
||||
async def fake_run(log_id, payload, session_factory=None, config_data=None):
|
||||
pushed.append((log_id, payload))
|
||||
|
||||
monkeypatch.setattr(svc, "_run_push", fake_run)
|
||||
@@ -494,7 +499,7 @@ def test_fire_pending_creates_tasks(monkeypatch):
|
||||
]
|
||||
|
||||
async def run():
|
||||
svc.fire_pending_pushes(logs)
|
||||
svc.fire_pending_pushes(logs, None)
|
||||
await asyncio.sleep(0) # 同 loop 内让 create_task 跑一轮
|
||||
asyncio.run(run())
|
||||
assert pushed == [("id-pending", {"event": "new"})]
|
||||
@@ -503,7 +508,6 @@ def test_fire_pending_creates_tasks(monkeypatch):
|
||||
def test_sweep_stale_pending(async_db, monkeypatch):
|
||||
from datetime import datetime, timezone
|
||||
from app.engine.services import lead_push_service as svc
|
||||
monkeypatch.setattr(svc, "async_session", async_db)
|
||||
_seed_push_ctx(async_db)
|
||||
|
||||
async def run():
|
||||
@@ -524,7 +528,7 @@ def test_sweep_stale_pending(async_db, monkeypatch):
|
||||
updated_at=datetime(2020, 1, 1, tzinfo=timezone.utc))
|
||||
db.add_all([stale, fresh, done])
|
||||
await db.commit()
|
||||
n = await svc.sweep_stale_pending(stale_minutes=30)
|
||||
n = await svc.sweep_stale_pending(async_db, stale_minutes=30)
|
||||
assert n == 1
|
||||
async with async_db() as db:
|
||||
logs = list((await db.execute(select(LeadPushLog))).scalars())
|
||||
|
||||
Reference in New Issue
Block a user