Files
live-hub-py/tests/test_douyu_workbench_scopes.py
T
yml2213 3ce1c7a51b test: pytest 工程化落地 — 本地门禁、容器测试镜像、迁移链冒烟测试
- 门禁: 本地 pre-push 钩子(.git/hooks,推送前强制跑全量 pytest)
- Docker: 新增 test 镜像阶段(含 dev 依赖与 tests),compose 提供
  --profile test run --rm test 入口;dev.sh 支持 ./dev.sh test
- 测试基建: 根目录 conftest.py 统一 DATABASE_URL/APP_ENCRYPTION_KEY,
  移除 9 个测试文件内的重复 setdefault(含多余 import os)
- 迁移冒烟: tests/test_migrations.py 校验链线性、脚本可编译、空库整链
  upgrade head 后与 Base.metadata 表/列/索引对齐
- 修复冒烟测试发现的漂移: YybRechargeTask.task_id 冗余 index=True
  (唯一索引已覆盖,迁移链未建普通索引,模型与真实 schema 对齐)
- alembic.ini: path_separator=os 消除弃用告警;README 补测试章节
2026-08-30 18:54:00 +08:00

129 lines
5.5 KiB
Python

import unittest
from types import SimpleNamespace
from sqlalchemy import create_engine, event
from sqlalchemy.orm import sessionmaker
from web.backend.database import Base
from web.backend.models import Account, DouyuTask, DouyuWorkbench, DouyuWorkbenchAccount, LoginTask, User
from web.backend.routers.accounts import delete_account
from web.backend.routers.douyu import list_tasks, list_workbench_accounts, update_workbench_accounts
from web.backend.schemas import DouyuWorkbenchAccountsUpdate
from web.backend.services.douyu_service import create_douyu_planned_tasks
class DouyuWorkbenchScopeTests(unittest.TestCase):
def setUp(self):
self.engine = create_engine("sqlite://")
@event.listens_for(self.engine, "connect")
def enable_foreign_keys(connection, _):
connection.execute("PRAGMA foreign_keys=ON")
Base.metadata.create_all(self.engine)
self.session = sessionmaker(bind=self.engine)()
self.user = User(username="operator", password_hash="hash", role="super_admin")
self.session.add(self.user)
self.session.commit()
self.account = Account(username="douyu-user", password="password", email="mail@example.com", email_password="mail-password")
self.session.add(self.account)
self.session.commit()
self.session.add(LoginTask(batch_id="login", account_id=self.account.id, created_by=self.user.id, status="success", cookie="acf_uid=1"))
self.session.commit()
self.current = SimpleNamespace(id=self.user.id, username=self.user.username, role=self.user.role, custom_permissions=None)
def tearDown(self):
self.session.close()
Base.metadata.drop_all(self.engine)
self.engine.dispose()
def test_workbench_accounts_are_per_user_and_scope(self):
update_workbench_accounts(
DouyuWorkbenchAccountsUpdate(handbook_scope="elite", account_ids=[self.account.id]),
db=self.session,
current=self.current,
)
elite = list_workbench_accounts("elite", db=self.session, current=self.current)
esports = list_workbench_accounts("esports", db=self.session, current=self.current)
self.assertEqual(elite["account_ids"], [self.account.id])
self.assertEqual(esports["account_ids"], [])
self.assertTrue(elite["configured"])
self.assertFalse(esports["configured"])
self.assertEqual(self.session.query(DouyuWorkbenchAccount).count(), 1)
update_workbench_accounts(
DouyuWorkbenchAccountsUpdate(handbook_scope="elite", account_ids=[]),
db=self.session,
current=self.current,
)
empty_elite = list_workbench_accounts("elite", db=self.session, current=self.current)
self.assertEqual(empty_elite["account_ids"], [])
self.assertTrue(empty_elite["configured"])
self.assertEqual(self.session.query(DouyuWorkbench).count(), 1)
def test_task_scope_is_persisted_and_filters_shared_task_types(self):
elite_batch, _ = create_douyu_planned_tasks(
self.session, [self.account.id], "create_gold_qr", "elite", self.user.id,
)
esports_batch, _ = create_douyu_planned_tasks(
self.session, [self.account.id], "create_gold_qr", "esports", self.user.id,
)
elite = list_tasks(
batch_id=None, handbook_scope="elite", include_detail=False, page=None, page_size=100,
db=self.session, current=self.current,
)
esports = list_tasks(
batch_id=None, handbook_scope="esports", include_detail=False, page=None, page_size=100,
db=self.session, current=self.current,
)
self.assertEqual({item.batch_id for item in elite}, {elite_batch})
self.assertEqual({item.batch_id for item in esports}, {esports_batch})
self.assertEqual({task.handbook_scope for task in self.session.query(DouyuTask).all()}, {"elite", "esports"})
def test_rejects_task_from_wrong_workbench(self):
with self.assertRaisesRegex(ValueError, "不属于当前工作台"):
create_douyu_planned_tasks(
self.session, [self.account.id], "get_xpd_bind_qr", "elite", self.user.id,
)
def test_elite_workbench_accepts_lock_goods_task(self):
batch_id, count = create_douyu_planned_tasks(
self.session,
[self.account.id],
"lock_goods",
"elite",
self.user.id,
{"commodity_id": "goods-1"},
)
task = self.session.query(DouyuTask).filter(DouyuTask.batch_id == batch_id).one()
self.assertEqual(count, 1)
self.assertEqual(task.task_type, "lock_goods")
self.assertEqual(task.result, {"payload": {"commodity_id": "goods-1"}})
_, pay_count = create_douyu_planned_tasks(
self.session,
[self.account.id],
"pay_locked_order",
"elite",
self.user.id,
{"order_id": "5874", "commodity_id": "goods-1"},
)
self.assertEqual(pay_count, 1)
def test_account_deletion_removes_workbench_membership(self):
self.session.add(DouyuWorkbenchAccount(
user_id=self.user.id,
handbook_scope="elite",
account_id=self.account.id,
))
self.session.commit()
delete_account(self.account.id, db=self.session, current=self.current)
self.assertEqual(self.session.query(DouyuWorkbenchAccount).count(), 0)
if __name__ == "__main__":
unittest.main()