"""回归:账号只要自己有 CK 就可见,**与任何登录记录的状态无关**。 这一条是 2026-10-04 CK 解耦的核心验收点。 解耦前:CK 存在 `login_tasks.cookie` 上,于是「记录被复用置为 pending」「重登失败」 都会让账号看起来「没有 CK」;线上出过事故(账号「远行者103」被分配后, 客服与管理员在工作台都看不到它)。 解耦后:CK 在账号上,登录记录只是一次尝试的历史 —— 删历史、批次排队、 重登失败都不可能让账号失去可见性。所以这个用例从「绕开记录状态」变成了 「根本不看记录」。 """ import pytest from tests.support.db import get_test_engine, make_test_session from web.backend.models import Account, LoginTask, User from web.backend.routers.cookies import list_cookies from web.backend.routers.douyu import list_task_account_ids, list_task_accounts from web.backend.services.account_service import cookie_account_ids_query from web.backend.services.douyu_service import ( create_douyu_planned_tasks, visible_douyu_task_accounts, ) class TestDouyuCookieVisibility: def setup_method(self): self.engine = get_test_engine() self.session = make_test_session(self.engine) self.admin = User(username="admin", password_hash="hash", role="super_admin") self.support = User(username="kf_7", password_hash="hash", role="support") self.session.add_all([self.admin, self.support]) self.session.commit() # 有 CK 的账号:即使历史记录是「重登失败」,也必须可见。 self.relogin_account = self._make_account("远行者103", self.support.id) self.relogin_account.cookie = "acf_uid=481802039" self.relogin_account.ck_check_status = "valid" self.session.add( LoginTask( batch_id="relogin-failed", account_id=self.relogin_account.id, created_by=self.support.id, status="relogin_failed", ) ) # 有 CK 的账号:即使历史记录停在 pending(批次排队中),也必须可见。 self.pending_account = self._make_account("排队中账号", self.support.id) self.pending_account.cookie = "acf_uid=2" self.session.add( LoginTask( batch_id="queued", account_id=self.pending_account.id, created_by=self.admin.id, status="pending", ) ) # 从未登录成功:没有 CK,必须继续隐藏。 self.empty_account = self._make_account("无CK账号", self.support.id) self.session.add( LoginTask( batch_id="failed", account_id=self.empty_account.id, created_by=self.admin.id, status="failed", ) ) self.session.commit() def _make_account(self, username: str, assigned_to: int) -> Account: account = Account( username=username, password="password", email=f"{username}@example.com", email_password="mail-password", assigned_to=assigned_to, ) self.session.add(account) self.session.flush() return account def teardown_method(self): self.session.close() def _task_account_names(self, current: User) -> set[str]: result = list_task_accounts( search="", tag="", ids="", account_names="", page=None, page_size=50, db=self.session, current=current, ) return {item.username for item in result} @pytest.mark.parametrize("current_attr", ["admin", "support"]) def test_workbench_lists_accounts_that_still_hold_cookie(self, current_attr): current = getattr(self, current_attr) names = self._task_account_names(current) assert {"远行者103", "排队中账号"} <= names assert "无CK账号" not in names def test_workbench_account_ids_keep_cookie_holders(self): result = list_task_account_ids( search="", tag="", account_names="", db=self.session, current=self.admin, ) assert set(result["account_ids"]) == { self.relogin_account.id, self.pending_account.id, } def test_visible_task_accounts_include_retained_cookie(self): accounts = visible_douyu_task_accounts( self.session, [self.relogin_account.id, self.empty_account.id], ) assert [account.id for account in accounts] == [self.relogin_account.id] def test_account_has_cookie_filter_matches_workbench(self): ids = { account_id for (account_id,) in cookie_account_ids_query(self.session).all() } assert ids == {self.relogin_account.id, self.pending_account.id} def test_cookie_management_page_lists_accounts_with_cookie(self): items = list_cookies( search="", tag="", account_names="", page=None, page_size=50, include_cookie=True, db=self.session, current=self.admin, ) assert {item["account_username"] for item in items} == { "远行者103", "排队中账号", } # 解耦后 id 就是账号 id(以前是「持有 CK 的登录记录 id」)。 assert {item["id"] for item in items} == { self.relogin_account.id, self.pending_account.id, } def test_retained_cookie_account_can_still_create_task(self): batch_id, created = create_douyu_planned_tasks( self.session, [self.relogin_account.id], "create_gold_qr", "elite", self.admin.id, ) assert batch_id assert created == 1 def test_deleting_login_history_does_not_touch_cookie(self): """本次改造的验收核心:删掉全部登录历史,账号的 CK 与健康状态仍在。""" self.session.query(LoginTask).delete(synchronize_session=False) self.session.commit() self.session.expire_all() fresh = ( self.session.query(Account) .filter(Account.id == self.relogin_account.id) .one() ) assert fresh.cookie == "acf_uid=481802039" assert fresh.ck_check_status == "valid" assert self._task_account_names(self.admin) == {"远行者103", "排队中账号"}