Improve abnormal account cleanup
This commit is contained in:
@@ -239,50 +239,44 @@ def test_cleanup_invalid_preview_and_execute(db_session, monkeypatch):
|
||||
assert item_k1.test_status == "failed"
|
||||
|
||||
item_k2 = next(i for i in items if i.account_id == "acc-k2")
|
||||
assert item_k2.cleanup_allowed is False
|
||||
assert item_k2.cleanup_allowed is True
|
||||
assert item_k2.test_status == "test_passed"
|
||||
assert item_k2.cleanup_action == "delete_remote_and_clear_marker"
|
||||
|
||||
item_orphan = next(i for i in items if i.account_id == "acc-orphan-remote")
|
||||
assert item_orphan.cleanup_allowed is True
|
||||
assert item_orphan.test_status == "failed"
|
||||
assert item_orphan.upstream_key_id == 9999
|
||||
assert item_orphan.cleanup_action == "delete_remote_account"
|
||||
|
||||
# 确认没有调用过删除
|
||||
assert len(deleted_accounts) == 0
|
||||
|
||||
# ── 2. 测试执行 ──
|
||||
# 重置调用计数
|
||||
test_calls.clear()
|
||||
execute_res = execute_cleanup_invalid_accounts(wid=w.id, db=db_session)
|
||||
assert execute_res.success is True
|
||||
assert "成功清理 2 个" in execute_res.message
|
||||
assert "跳过 1 个" in execute_res.message
|
||||
assert "成功清理 3 个" in execute_res.message
|
||||
|
||||
# 验证是否重新跑了测试
|
||||
assert "acc-k1" in test_calls
|
||||
assert "acc-k2" in test_calls
|
||||
assert "acc-orphan-remote" in test_calls
|
||||
|
||||
# 验证被删除的账号 (只有测试失败/可清理的才删:acc-k1 和 acc-orphan-remote)
|
||||
assert len(deleted_accounts) == 2
|
||||
# 验证被删除的账号(所有候选都按 cleanup_action 执行删除)
|
||||
assert len(deleted_accounts) == 3
|
||||
assert "acc-k1" in deleted_accounts
|
||||
assert "acc-k2" in deleted_accounts
|
||||
assert "acc-orphan-remote" in deleted_accounts
|
||||
assert "acc-k2" not in deleted_accounts
|
||||
|
||||
# 验证本地数据库的 DB key 清空逻辑:
|
||||
db_session.refresh(k1)
|
||||
db_session.refresh(k2)
|
||||
db_session.refresh(k3)
|
||||
|
||||
# k1 应该被清空 imported 字段,但保留 status='orphaned' 及原始 error
|
||||
# k1 应该被清空 imported 字段(delete_remote_and_clear_marker),但保留 status='orphaned' 及原始 error
|
||||
assert k1.imported_website_id is None
|
||||
assert k1.imported_account_id is None
|
||||
assert k1.status == "orphaned"
|
||||
assert k1.error == "original-error-k1"
|
||||
|
||||
# k2 由于测试成功跳过删除,DB 不变
|
||||
assert k2.imported_website_id == w.id
|
||||
assert k2.imported_account_id == "acc-k2"
|
||||
# k2 也是 delete_remote_and_clear_marker,删除成功后清空导入标记
|
||||
assert k2.imported_website_id is None
|
||||
assert k2.imported_account_id is None
|
||||
assert k2.status == "orphaned"
|
||||
|
||||
|
||||
@@ -317,3 +311,93 @@ def test_cleanup_list_accounts_failure(db_session, monkeypatch):
|
||||
assert execute_res.success is False
|
||||
assert "拉取远端账号列表失败" in execute_res.message
|
||||
assert len(execute_res.items) == 0
|
||||
|
||||
|
||||
def test_cleanup_missing_remote_account_clear_local_marker(db_session, monkeypatch):
|
||||
"""status=imported 且本地有 imported_account_id,但远端账号列表已不存在该账号
|
||||
→ 走 clear_local_marker,不调用 delete_account,只清 SmartUp 本地导入标记。
|
||||
"""
|
||||
w = Website(
|
||||
name="W-clear",
|
||||
site_type="sub2api",
|
||||
base_url="http://w-clear",
|
||||
enabled=True,
|
||||
auth_config_json="{}",
|
||||
timeout_seconds=30
|
||||
)
|
||||
u = Upstream(name="U-clear", base_url="http://u-clear")
|
||||
db_session.add_all([w, u])
|
||||
db_session.commit()
|
||||
db_session.refresh(w)
|
||||
db_session.refresh(u)
|
||||
|
||||
# 正常 imported 的 Key,关联到远端账号 acc-gone
|
||||
k = UpstreamGeneratedKey(
|
||||
upstream_id=u.id,
|
||||
group_id="G-clear",
|
||||
group_name="G-Clear-Name",
|
||||
key_name="Key-Clear",
|
||||
key_value="sk-clear",
|
||||
status="imported",
|
||||
imported_website_id=w.id,
|
||||
imported_account_id="acc-gone",
|
||||
imported_target_group_id="tg-1",
|
||||
imported_target_group_name="Target Group 1",
|
||||
)
|
||||
db_session.add(k)
|
||||
db_session.commit()
|
||||
|
||||
deleted_accounts: list[str] = []
|
||||
|
||||
class MockClient:
|
||||
def __init__(self, **kwargs): pass
|
||||
def __enter__(self): return self
|
||||
def __exit__(self, *a): pass
|
||||
|
||||
def list_accounts(self):
|
||||
# 远端列表中不包含 acc-gone
|
||||
return [
|
||||
{"id": "acc-other", "name": "Other-Acc", "notes": ""},
|
||||
]
|
||||
|
||||
def extract_id(self, val):
|
||||
return val.get("id") if isinstance(val, dict) else str(val)
|
||||
|
||||
def delete_account(self, account_id: str):
|
||||
deleted_accounts.append(account_id)
|
||||
return {"status": "deleted", "message": "deleted"}
|
||||
|
||||
def test_account(self, account_id: str):
|
||||
return {"status": "404", "cleanup_allowed": True, "message": "not found"}
|
||||
|
||||
monkeypatch.setattr("app.routers.websites._client", lambda row: MockClient())
|
||||
|
||||
# ── Preview ──
|
||||
preview_res = preview_cleanup_invalid_accounts(wid=w.id, db=db_session)
|
||||
assert preview_res.success is True
|
||||
assert len(preview_res.items) == 1
|
||||
|
||||
item = preview_res.items[0]
|
||||
assert item.account_id == "acc-gone"
|
||||
assert item.cleanup_action == "clear_local_marker"
|
||||
assert item.cleanup_allowed is True
|
||||
assert item.test_status == "not_needed"
|
||||
assert item.reason == "目标账号已被手动删除"
|
||||
|
||||
# ── Execute ──
|
||||
execute_res = execute_cleanup_invalid_accounts(wid=w.id, db=db_session)
|
||||
assert execute_res.success is True
|
||||
assert "清除本地标记 1 个" in execute_res.message
|
||||
|
||||
# 不应调用删除
|
||||
assert len(deleted_accounts) == 0
|
||||
|
||||
# 本地导入标记应被清空
|
||||
db_session.refresh(k)
|
||||
assert k.imported_website_id is None
|
||||
assert k.imported_account_id is None
|
||||
assert k.imported_at is None
|
||||
assert k.imported_target_group_id is None
|
||||
assert k.imported_target_group_name is None
|
||||
# status 不受影响
|
||||
assert k.status == "imported"
|
||||
|
||||
Reference in New Issue
Block a user