feat(priority): group priority changed notifications by target group and fetch remote account details
This commit is contained in:
@@ -533,3 +533,148 @@ def test_reorder_priority_endpoint_scopes_to_current_website(db_session, monkeyp
|
||||
updated = {account_id: payload["priority"] for account_id, payload in update_calls}
|
||||
assert response.success is True
|
||||
assert updated == {"W1A1": 1, "W1A2": 11}
|
||||
|
||||
|
||||
def test_priority_sync_notification_grouped_by_target_group():
|
||||
"""测试 DingTalk Markdown 通知按目标分组正确聚合。"""
|
||||
from app.utils.dingtalk import format_dingtalk_priority_changed
|
||||
|
||||
updates = [
|
||||
{
|
||||
"target_group_id": "TG1",
|
||||
"target_group_name": "PRO智能分组",
|
||||
"account_id": "A123",
|
||||
"account_name": "SmartUp-PRO-xxx",
|
||||
"source_group_id": "sg1",
|
||||
"source_group_name": "28",
|
||||
"source_rate": 0.8,
|
||||
"old_priority": 11,
|
||||
"new_priority": 1,
|
||||
"status": "success",
|
||||
"message": "success",
|
||||
},
|
||||
{
|
||||
"target_group_id": "TG1",
|
||||
"target_group_name": "PRO智能分组",
|
||||
"account_id": "A456",
|
||||
"account_name": "SmartUp-Claude-xxx",
|
||||
"source_group_id": "sg2",
|
||||
"source_group_name": "claude max渠道",
|
||||
"source_rate": 1.2,
|
||||
"old_priority": 21,
|
||||
"new_priority": 11,
|
||||
"status": "failed",
|
||||
"message": "xxx",
|
||||
},
|
||||
{
|
||||
"target_group_id": "TG2",
|
||||
"target_group_name": "Basic智能分组",
|
||||
"account_id": "A789",
|
||||
"account_name": "SmartUp-Basic-xxx",
|
||||
"source_group_id": "sg3",
|
||||
"source_group_name": "basic渠道",
|
||||
"source_rate": 2.0,
|
||||
"old_priority": "未知",
|
||||
"new_priority": 31,
|
||||
"status": "success",
|
||||
"message": "success",
|
||||
}
|
||||
]
|
||||
|
||||
msg = format_dingtalk_priority_changed("SmartSite", "Upstream1", "2026-07-01 09:00:00", updates)
|
||||
text = msg["markdown"]["text"]
|
||||
|
||||
# 验证分组标题
|
||||
assert "目标分组:PRO智能分组" in text
|
||||
assert "目标分组:Basic智能分组" in text
|
||||
|
||||
# 验证账号明细
|
||||
assert "- ✅ SmartUp-PRO-xxx(账号ID A123):old=11 → new=1,来源分组=28,倍率=0.8" in text
|
||||
assert "- ❌ SmartUp-Claude-xxx(账号ID A456):old=21 → new=11,来源分组=claude max渠道,倍率=1.2,原因=xxx" in text
|
||||
assert "- ✅ SmartUp-Basic-xxx(账号ID A789):old=未知 → new=31,来源分组=basic渠道,倍率=2.0" in text
|
||||
|
||||
|
||||
def test_priority_sync_fetches_remote_accounts_and_backfills_info(db_session, monkeypatch):
|
||||
"""验证优先级同步能获取并回填远端账号的名称和旧优先级。"""
|
||||
w = Website(name="W1", base_url="http://w1", enabled=True,
|
||||
auth_config_json="{}", timeout_seconds=30)
|
||||
u = Upstream(name="U1", base_url="http://u1")
|
||||
db_session.add_all([w, u])
|
||||
db_session.commit()
|
||||
db_session.refresh(w); db_session.refresh(u)
|
||||
|
||||
_make_snapshot(db_session, u.id, {"G1": 1.0, "G2": 2.0})
|
||||
|
||||
_make_key(db_session, u.id, "G1", "K1", "V1", w.id, "A1", imported_target_group_id="TG1")
|
||||
_make_key(db_session, u.id, "G2", "K2", "V2", w.id, "A2", imported_target_group_id="TG1")
|
||||
|
||||
update_calls = []
|
||||
|
||||
class CustomMockClient:
|
||||
def __init__(self, **kwargs): pass
|
||||
def __enter__(self): return self
|
||||
def __exit__(self, *a): pass
|
||||
def list_accounts(self):
|
||||
return [
|
||||
{"id": "A1", "name": "SmartUp-A1-Name", "priority": 15},
|
||||
{"id": "A2", "name": "SmartUp-A2-Name", "priority": 25},
|
||||
]
|
||||
def update_account(self, account_id, data):
|
||||
update_calls.append((account_id, data))
|
||||
|
||||
monkeypatch.setattr("app.services.website_sync.Sub2ApiWebsiteClient", CustomMockClient)
|
||||
|
||||
results = sync_account_priorities_for_upstream(db_session, u.id, website_id=w.id)
|
||||
assert len(results) == 2
|
||||
|
||||
# 校验 site_results 中的丰富信息是否填充
|
||||
res_a1 = next(r for r in results if r["account_id"] == "A1")
|
||||
assert res_a1["account_name"] == "SmartUp-A1-Name"
|
||||
assert res_a1["old_priority"] == 15
|
||||
assert res_a1["new_priority"] == 1
|
||||
assert res_a1["source_rate"] == 1.0
|
||||
assert res_a1["target_group_id"] == "TG1"
|
||||
assert res_a1["target_group_name"] == "TG1" # fallback to tg_id since target_group_name is not set
|
||||
|
||||
res_a2 = next(r for r in results if r["account_id"] == "A2")
|
||||
assert res_a2["account_name"] == "SmartUp-A2-Name"
|
||||
assert res_a2["old_priority"] == 25
|
||||
assert res_a2["new_priority"] == 11
|
||||
assert res_a2["source_rate"] == 2.0
|
||||
|
||||
|
||||
def test_priority_sync_graceful_on_remote_list_failure(db_session, monkeypatch):
|
||||
"""验证 list_accounts 抛异常时,优先级同步依然成功更新,且各项降级为账号 ID 和未知。"""
|
||||
w = Website(name="W1", base_url="http://w1", enabled=True,
|
||||
auth_config_json="{}", timeout_seconds=30)
|
||||
u = Upstream(name="U1", base_url="http://u1")
|
||||
db_session.add_all([w, u])
|
||||
db_session.commit()
|
||||
db_session.refresh(w); db_session.refresh(u)
|
||||
|
||||
_make_snapshot(db_session, u.id, {"G1": 1.0, "G2": 2.0})
|
||||
|
||||
_make_key(db_session, u.id, "G1", "K1", "V1", w.id, "A1", imported_target_group_id="TG1")
|
||||
_make_key(db_session, u.id, "G2", "K2", "V2", w.id, "A2", imported_target_group_id="TG1")
|
||||
|
||||
class CustomMockClient:
|
||||
def __init__(self, **kwargs): pass
|
||||
def __enter__(self): return self
|
||||
def __exit__(self, *a): pass
|
||||
def list_accounts(self):
|
||||
raise Exception("Remote server error 500")
|
||||
def update_account(self, account_id, data):
|
||||
pass
|
||||
|
||||
monkeypatch.setattr("app.services.website_sync.Sub2ApiWebsiteClient", CustomMockClient)
|
||||
|
||||
results = sync_account_priorities_for_upstream(db_session, u.id, website_id=w.id)
|
||||
assert len(results) == 2
|
||||
|
||||
# 校验降级逻辑
|
||||
res_a1 = next(r for r in results if r["account_id"] == "A1")
|
||||
assert res_a1["account_name"] == "A1"
|
||||
assert res_a1["old_priority"] is None
|
||||
assert res_a1["new_priority"] == 1
|
||||
assert res_a1["status"] == "success"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user