mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-09 23:44:20 +08:00
93 lines
2.3 KiB
Python
93 lines
2.3 KiB
Python
from concurrent.futures import ThreadPoolExecutor
|
|
|
|
from app.core.cache import TTLCache
|
|
from app.helper.passkey import PasskeyChallengeStore
|
|
|
|
|
|
def setup_function():
|
|
PasskeyChallengeStore._cache.clear()
|
|
|
|
|
|
def test_challenge_can_only_be_consumed_once():
|
|
token = PasskeyChallengeStore.issue(
|
|
challenge="server-challenge",
|
|
purpose="authentication",
|
|
user_id=1,
|
|
)
|
|
|
|
challenge = PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="authentication",
|
|
)
|
|
|
|
assert challenge is not None
|
|
assert challenge.challenge == "server-challenge"
|
|
assert challenge.user_id == 1
|
|
assert (
|
|
PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="authentication",
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_wrong_purpose_invalidates_transaction():
|
|
token = PasskeyChallengeStore.issue(
|
|
challenge="server-challenge",
|
|
purpose="registration",
|
|
user_id=1,
|
|
)
|
|
|
|
assert (
|
|
PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="authentication",
|
|
)
|
|
is None
|
|
)
|
|
assert (
|
|
PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="registration",
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_expired_challenge_cannot_be_consumed(monkeypatch):
|
|
expired_cache = TTLCache(region="expired_passkey_challenge", maxsize=1, ttl=0)
|
|
monkeypatch.setattr(PasskeyChallengeStore, "_cache", expired_cache)
|
|
token = PasskeyChallengeStore.issue(
|
|
challenge="server-challenge",
|
|
purpose="authentication",
|
|
user_id=None,
|
|
)
|
|
|
|
assert (
|
|
PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="authentication",
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_concurrent_consumers_have_single_winner():
|
|
token = PasskeyChallengeStore.issue(
|
|
challenge="server-challenge",
|
|
purpose="authentication",
|
|
user_id=None,
|
|
)
|
|
|
|
def consume():
|
|
return PasskeyChallengeStore.consume(
|
|
transaction_token=token,
|
|
purpose="authentication",
|
|
)
|
|
|
|
with ThreadPoolExecutor(max_workers=8) as executor:
|
|
results = list(executor.map(lambda _: consume(), range(8)))
|
|
|
|
assert sum(result is not None for result in results) == 1
|