Files
MoviePilot/tests/test_auth_ticket.py
T

87 lines
2.8 KiB
Python

"""插件认证一次性票据的生命周期测试。"""
from concurrent.futures import ThreadPoolExecutor
import pytest
from app.application.security import auth
from app.application.security.auth import AuthTicketStore
@pytest.fixture(autouse=True)
def clear_auth_tickets():
"""隔离单例票据缓存,避免测试间共享认证事实。"""
store = AuthTicketStore()
with store._lock:
store._tickets.clear()
yield
with store._lock:
store._tickets.clear()
def test_auth_ticket_can_only_be_consumed_once():
"""成功领取后立即删除票据,后续兑换不得重复获得认证事实。"""
store = AuthTicketStore()
ticket = store.create(user_id=1, provider_id="plugin:test")
assert store.consume(ticket)["user_id"] == 1
assert store.consume(ticket) is None
def test_auth_ticket_concurrent_consumers_have_single_winner():
"""多个并发兑换请求只能有一个成功领取同一票据。"""
store = AuthTicketStore()
ticket = store.create(user_id=1, provider_id="plugin:test")
with ThreadPoolExecutor(max_workers=8) as executor:
results = list(executor.map(lambda _: store.consume(ticket), range(8)))
assert sum(result is not None for result in results) == 1
def test_auth_ticket_ttl_boundary_and_expiration(monkeypatch):
"""票据在 TTL 边界内有效,超过边界后即使首次领取也必须失败。"""
now = [1_000.0]
monkeypatch.setattr(auth.time, "time", lambda: now[0])
store = AuthTicketStore()
boundary_ticket = store.create(user_id=1, provider_id="plugin:test")
now[0] += store._ttl_seconds
assert store.consume(boundary_ticket) is not None
expired_ticket = store.create(user_id=1, provider_id="plugin:test")
now[0] += store._ttl_seconds + 0.001
assert store.consume(expired_ticket) is None
assert store.consume(expired_ticket) is None
def test_auth_ticket_metadata_is_detached_from_callers():
"""签发和领取两侧都不能通过可变对象改写缓存中的认证元数据。"""
store = AuthTicketStore()
metadata = {"groups": ["users"]}
ticket = store.create(
user_id=1,
provider_id="plugin:test",
metadata=metadata,
)
metadata["groups"].append("admins")
consumed = store.consume(ticket)
assert consumed["metadata"] == {"groups": ["users"]}
def test_auth_ticket_capacity_is_a_hard_limit(monkeypatch):
"""连续签发也不得让票据表永久超过容量上限。"""
monkeypatch.setattr(AuthTicketStore, "_max_items", 4)
store = AuthTicketStore()
tickets = [
store.create(user_id=index, provider_id="plugin:test")
for index in range(6)
]
assert len(store._tickets) == 4
assert store.consume(tickets[0]) is None
assert store.consume(tickets[-1]) is not None