ForcePilot/backend/test/unit/channels/test_twitch_pairing.py

200 lines
6.2 KiB
Python
Raw Normal View History

from __future__ import annotations
import time
import pytest
from yuxi.channels.adapters.twitch.pairing import (
PairingStore,
check_pairing_policy,
format_pairing_notification,
strip_pairing_prefix,
)
class TestStripPairingPrefix:
def test_strips_twitch_prefix(self):
assert strip_pairing_prefix("twitch:user123") == "user123"
def test_strips_user_prefix(self):
assert strip_pairing_prefix("user:user123") == "user123"
def test_preserves_without_prefix(self):
assert strip_pairing_prefix("user123") == "user123"
def test_strips_case_insensitive(self):
assert strip_pairing_prefix("TWITCH:user123") == "user123"
assert strip_pairing_prefix("User:user123") == "user123"
def test_empty_string(self):
assert strip_pairing_prefix("") == ""
class TestPairingStore:
def test_initial_state(self):
store = PairingStore()
assert len(store) == 0
assert store.pending_count == 0
def test_is_approved_false_initially(self):
store = PairingStore()
assert store.is_approved("user1") is False
def test_add_pending_and_approve(self):
store = PairingStore()
store.add_pending("user1", "UserOne", "#chan")
assert store.pending_count == 1
result = store.approve("user1")
assert result is True
assert store.is_approved("user1") is True
assert store.pending_count == 0
def test_approve_triggers_callback(self):
callback_data = {"called": False}
def cb(user_name, channel):
callback_data["called"] = True
callback_data["user_name"] = user_name
callback_data["channel"] = channel
store = PairingStore()
store.set_on_approve(cb, "#main_channel")
store.add_pending("user1", "UserOne", "#chan")
store.approve("user1", "UserOne")
assert callback_data["called"] is True
assert callback_data["user_name"] == "UserOne"
assert callback_data["channel"] == "#main_channel"
def test_approve_callback_exception_suppressed(self):
def cb(user_name, channel):
raise RuntimeError("test error")
store = PairingStore()
store.set_on_approve(cb)
store.add_pending("user1", "UserOne", "#chan")
result = store.approve("user1")
assert result is True
def test_approve_without_pending(self):
store = PairingStore()
result = store.approve("user1")
assert result is True
assert store.is_approved("user1") is True
def test_reject_removes_pending(self):
store = PairingStore()
store.add_pending("user1", "UserOne", "#chan")
result = store.reject("user1")
assert result is True
assert store.pending_count == 0
def test_reject_nonexistent(self):
store = PairingStore()
result = store.reject("nonexistent")
assert result is False
def test_remove_approval(self):
store = PairingStore()
store.approve("user1")
assert store.is_approved("user1") is True
result = store.remove_approval("user1")
assert result is True
assert store.is_approved("user1") is False
def test_remove_approval_nonexistent(self):
store = PairingStore()
result = store.remove_approval("nonexistent")
assert result is False
def test_get_approved_users(self):
store = PairingStore()
store.approve("user1")
store.approve("user2")
approved = store.get_approved_users()
assert "user1" in approved
assert "user2" in approved
def test_get_pending_users(self):
store = PairingStore()
store.add_pending("user1", "U1", "#ch")
store.add_pending("user2", "U2", "#ch")
pending = store.get_pending_users()
assert "user1" in pending
assert "user2" in pending
def test_is_pending(self):
store = PairingStore()
store.add_pending("user1", "U1", "#ch")
assert store.is_pending("user1") is True
assert store.is_pending("user2") is False
def test_approved_expiry(self):
store = PairingStore()
store.APPROVED_TTL = 0.1
store.approve("user1")
assert store.is_approved("user1") is True
time.sleep(0.15)
assert store.is_approved("user1") is False
def test_length_after_expiry(self):
store = PairingStore()
store.APPROVED_TTL = 0.05
store.approve("user1")
assert len(store) == 1
time.sleep(0.1)
_ = store.is_approved("user1")
assert len(store) == 0
def test_normalize_with_prefix(self):
store = PairingStore()
store.approve("twitch:user1")
assert store.is_approved("user1") is True
assert store.is_approved("twitch:user1") is True
def test_max_approved_eviction(self):
store = PairingStore()
store.MAX_APPROVED = 3
for i in range(5):
store.approve(f"user{i}")
assert len(store) <= 3
def test_pending_expiry(self):
store = PairingStore()
store.PENDING_TTL = 0.05
store.add_pending("user1", "U1", "#ch")
assert store.pending_count == 1
time.sleep(0.1)
store.get_pending_users()
assert store.pending_count == 0
def test_approved_move_to_end(self):
store = PairingStore()
store.MAX_APPROVED = 2
store.approve("user1")
time.sleep(0.01)
store.approve("user2")
time.sleep(0.01)
assert store.is_approved("user1") is True
store.approve("user3")
approved = store.get_approved_users()
assert "user1" in approved
assert "user2" not in approved
class TestCheckPairingPolicy:
def test_approved_user(self):
store = PairingStore()
store.approve("user1")
assert check_pairing_policy(store, "user1") is True
def test_unapproved_user(self):
store = PairingStore()
assert check_pairing_policy(store, "user1") is False
class TestFormatPairingNotification:
def test_formats_message(self):
msg = format_pairing_notification("TestUser", "ABC123")
assert "TestUser" in msg
assert "ABC123" in msg
assert "!approve" in msg