mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-01 05:27:02 +08:00
87 lines
2.8 KiB
Python
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
|