186 lines
7.1 KiB
Python
186 lines
7.1 KiB
Python
"""虎牙协作礼包字典:CRUD、改名级联、积分快照边界与权限。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from tests.support.db import get_test_engine, make_test_session
|
|
from web.backend.models import AuditLog, HuyaCollabGiftCatalog, HuyaExternalOrder, User
|
|
from web.backend.permissions import ROLE_PERMISSIONS
|
|
from web.backend.routers.huya import collab as collab_api
|
|
from web.backend.schemas import HuyaCollabGiftCatalogOut
|
|
from web.backend.services import huya_collab_service as collab
|
|
|
|
|
|
class TestHuyaCollabGiftCatalog:
|
|
def setup_method(self):
|
|
self.engine = get_test_engine()
|
|
self.db = make_test_session(self.engine)
|
|
self.user = User(username="gift_op", password_hash="h", role="operation")
|
|
self.support = User(username="gift_support", password_hash="h", role="support")
|
|
self.db.add_all([self.user, self.support])
|
|
self.db.commit()
|
|
|
|
def teardown_method(self):
|
|
self.db.close()
|
|
|
|
def _gift(self, name: str, points: int = 8000, **kwargs) -> HuyaCollabGiftCatalog:
|
|
return collab.create_gift(
|
|
self.db, self.user, name=name, points=points, **kwargs
|
|
)
|
|
|
|
def _order(self, order_no: str, gift_name: str = "", **kwargs) -> HuyaExternalOrder:
|
|
return collab.create_order(
|
|
self.db,
|
|
self.user,
|
|
order_no=order_no,
|
|
gift_name=gift_name,
|
|
**kwargs,
|
|
)
|
|
|
|
def _audits(self, gift: HuyaCollabGiftCatalog) -> list[AuditLog]:
|
|
return (
|
|
self.db.query(AuditLog)
|
|
.filter(AuditLog.target == f"huya_collab_gift:{gift.id}")
|
|
.order_by(AuditLog.id.asc())
|
|
.all()
|
|
)
|
|
|
|
def test_create_list_and_serialize(self):
|
|
self._gift("乙礼包", points=900, sort_order=2)
|
|
self._gift("甲礼包", points=800, sort_order=1)
|
|
|
|
rows = collab.list_gift_records(self.db)
|
|
|
|
assert [row.name for row in rows] == ["甲礼包", "乙礼包"]
|
|
dumped = HuyaCollabGiftCatalogOut.model_validate(
|
|
collab.serialize_gift(
|
|
rows[0], users={int(self.user.id): self.user.username}
|
|
)
|
|
).model_dump()
|
|
assert dumped["name"] == "甲礼包"
|
|
assert dumped["points"] == 800
|
|
assert dumped["is_active"] is True
|
|
assert dumped["created_by_name"] == self.user.username
|
|
assert [row.action for row in self._audits(rows[0])] == [
|
|
"huya:collab:gift_create"
|
|
]
|
|
|
|
def test_create_rejects_duplicate_blank_and_invalid_points(self):
|
|
self._gift("甲礼包")
|
|
|
|
with pytest.raises(collab.CollabError) as duplicate:
|
|
self._gift(" 甲礼包 ")
|
|
assert duplicate.value.status_code == 409
|
|
assert duplicate.value.code == "gift_name_conflict"
|
|
|
|
with pytest.raises(collab.CollabError) as blank:
|
|
self._gift(" ")
|
|
assert blank.value.code == "gift_name_required"
|
|
|
|
with pytest.raises(collab.CollabError) as invalid:
|
|
self._gift("乙礼包", points="not-a-number")
|
|
assert invalid.value.code == "required_points_invalid"
|
|
|
|
def test_create_order_uses_catalog_points_when_points_are_omitted(self):
|
|
gift = self._gift("标准礼包", points=4321)
|
|
|
|
order = self._order("GIFT-POINTS-1", gift_name=gift.name)
|
|
|
|
assert order.required_points == 4321
|
|
|
|
def test_changing_order_gift_name_uses_new_catalog_points(self):
|
|
first = self._gift("礼包A", points=200)
|
|
second = self._gift("礼包B", points=300)
|
|
order = self._order("GIFT-POINTS-2", gift_name=first.name)
|
|
|
|
changes = collab.update_order(
|
|
self.db, self.user, order, {"gift_name": second.name}
|
|
)
|
|
|
|
assert changes["required_points"] == {"old": 200, "new": 300}
|
|
assert order.required_points == 300
|
|
|
|
def test_rename_cascades_but_points_change_does_not_backfill_orders(self):
|
|
gift = self._gift("旧礼包名", points=8000)
|
|
order = self._order("GIFT-RENAME-1", gift_name=gift.name)
|
|
|
|
changes = collab.update_gift(
|
|
self.db, self.user, gift, {"name": "新礼包名", "points": 9000}
|
|
)
|
|
|
|
self.db.refresh(order)
|
|
assert changes["name"] == {"old": "旧礼包名", "new": "新礼包名"}
|
|
assert changes["points"] == {"old": 8000, "new": 9000}
|
|
assert order.gift_name == "新礼包名"
|
|
assert order.required_points == 8000
|
|
audit = self._audits(gift)[-1]
|
|
assert json.loads(audit.detail)["renamed_orders"] == 1
|
|
|
|
def test_delete_is_blocked_while_orders_use_the_gift(self):
|
|
gift = self._gift("在用的礼包")
|
|
self._order("GIFT-DELETE-1", gift_name=gift.name)
|
|
|
|
with pytest.raises(collab.CollabError) as excinfo:
|
|
collab.delete_gift(self.db, self.user, gift)
|
|
|
|
assert excinfo.value.code == "gift_in_use"
|
|
assert self.db.query(HuyaCollabGiftCatalog).count() == 1
|
|
|
|
def test_unused_gift_can_be_deleted_with_audit(self):
|
|
gift = self._gift("可删礼包")
|
|
|
|
snapshot = collab.delete_gift(self.db, self.user, gift)
|
|
|
|
assert snapshot["name"] == "可删礼包"
|
|
assert self.db.query(HuyaCollabGiftCatalog).count() == 0
|
|
audit = (
|
|
self.db.query(AuditLog)
|
|
.filter(AuditLog.action == "huya:collab:gift_delete")
|
|
.one()
|
|
)
|
|
assert "可删礼包" in audit.detail
|
|
|
|
def test_inactive_gift_stays_in_catalog_for_management(self):
|
|
gift = self._gift("准备停用")
|
|
|
|
collab.update_gift(self.db, self.user, gift, {"is_active": False})
|
|
|
|
rows = collab.list_gift_records(self.db)
|
|
assert len(rows) == 1
|
|
assert rows[0].is_active is False
|
|
|
|
def test_write_permission_is_operation_only_by_default(self):
|
|
assert "huya:collab:manage" in ROLE_PERMISSIONS["operation"]
|
|
assert "huya:collab:manage" not in ROLE_PERMISSIONS["support"]
|
|
assert "huya:collab:manage" in ROLE_PERMISSIONS["super_admin"]
|
|
|
|
def test_routes_are_registered(self):
|
|
from web.backend.main import app
|
|
|
|
paths = app.openapi()["paths"]
|
|
assert "/api/huya/collab-gifts" in paths
|
|
assert "get" in paths["/api/huya/collab-gifts"]
|
|
assert "post" in paths["/api/huya/collab-gifts"]
|
|
assert "/api/huya/collab-gifts/{gift_id}" in paths
|
|
assert "put" in paths["/api/huya/collab-gifts/{gift_id}"]
|
|
assert "delete" in paths["/api/huya/collab-gifts/{gift_id}"]
|
|
|
|
def test_router_response_keeps_all_catalog_fields(self):
|
|
gift = self._gift("接口礼包", points=6600, remark="按兑换记录标准名")
|
|
|
|
payload = collab_api.create_collab_gift(
|
|
req=collab_api.HuyaCollabGiftCatalogCreate(name="另一个礼包", points=7700),
|
|
db=self.db,
|
|
current=self.user,
|
|
)
|
|
|
|
assert payload["name"] == "另一个礼包"
|
|
assert payload["points"] == 7700
|
|
assert payload["created_by_name"] == self.user.username
|
|
listed = collab_api.list_collab_gifts(db=self.db, _current=self.user)
|
|
by_name = {item["name"]: item for item in listed}
|
|
assert by_name[gift.name]["remark"] == "按兑换记录标准名"
|