Files
wizarr/tests/test_invite_code_manager.py
engels74 d0df4c6d5d feat: wizard step refactor into pre/post wizard steps
Changes:
  - Pre/post invitation wizard phases
  - Phase-aware routing (/pre-wizard/*, /post-wizard/*)
  - Phase indicator badges (visual categorization)
  - Dynamic completion button behavior
  - Two-column admin layout with category drag-and-drop
  - Invite code management service
  - Enhanced wizard export/import
  - Comprehensive test coverage (17 new test files)
2025-10-16 15:28:48 +02:00

267 lines
9.8 KiB
Python

"""
Unit tests for InviteCodeManager service.
Tests cover:
- Invite code storage and retrieval
- Invite code validation (valid, expired, used)
- Pre-wizard completion flag
- Session cleanup
"""
import datetime
from datetime import timedelta
from app.extensions import db
from app.models import Invitation, MediaServer
from app.services.invite_code_manager import InviteCodeManager
class TestInviteCodeStorage:
"""Test invite code storage and retrieval."""
def test_store_and_retrieve_invite_code(self, app, client):
"""Test that invite code can be stored and retrieved from session."""
with app.app_context():
with client.session_transaction():
# Store invite code
InviteCodeManager.store_invite_code("TEST123")
with client.session_transaction():
# Retrieve invite code
code = InviteCodeManager.get_invite_code()
assert code == "TEST123"
def test_get_invite_code_when_not_stored(self, app, client):
"""Test that get_invite_code returns None when no code is stored."""
with app.app_context(), client.session_transaction():
code = InviteCodeManager.get_invite_code()
assert code is None
def test_store_overwrites_previous_code(self, app, client):
"""Test that storing a new code overwrites the previous one."""
with app.app_context():
with client.session_transaction():
InviteCodeManager.store_invite_code("FIRST123")
with client.session_transaction():
InviteCodeManager.store_invite_code("SECOND123")
with client.session_transaction():
code = InviteCodeManager.get_invite_code()
assert code == "SECOND123"
class TestInviteCodeValidation:
"""Test invite code validation logic."""
def test_validate_valid_invitation(self, app, client):
"""Test validation of a valid invitation."""
with app.app_context():
# Create a valid invitation
server = MediaServer(
name="Test Server",
server_type="jellyfin",
url="http://localhost:8096",
api_key="test-key",
)
db.session.add(server)
db.session.flush()
invitation = Invitation(
code="VALID123",
unlimited=True,
used=False,
expires=datetime.datetime.now() + timedelta(days=7),
)
invitation.servers.append(server)
db.session.add(invitation)
db.session.commit()
# Validate
is_valid, inv = InviteCodeManager.validate_invite_code("VALID123")
assert is_valid is True
assert inv is not None
assert inv.code == "VALID123"
def test_validate_case_insensitive(self, app, client):
"""Test that validation is case-insensitive."""
with app.app_context():
# Create invitation with uppercase code
invitation = Invitation(
code="UPPER123",
unlimited=True,
used=False,
)
db.session.add(invitation)
db.session.commit()
# Validate with lowercase
is_valid, inv = InviteCodeManager.validate_invite_code("upper123")
assert is_valid is True
assert inv is not None
assert inv.code == "UPPER123"
def test_validate_expired_invitation(self, app, client):
"""Test that expired invitations are rejected."""
with app.app_context():
# Create expired invitation
invitation = Invitation(
code="EXPIRED123",
unlimited=False,
used=False,
expires=datetime.datetime.now() - timedelta(hours=1),
)
db.session.add(invitation)
db.session.commit()
# Validate
is_valid, inv = InviteCodeManager.validate_invite_code("EXPIRED123")
assert is_valid is False
assert inv is None
def test_validate_used_limited_invitation(self, app, client):
"""Test that used limited invitations are rejected."""
with app.app_context():
# Create used limited invitation
invitation = Invitation(
code="USED123",
unlimited=False,
used=True,
)
db.session.add(invitation)
db.session.commit()
# Validate
is_valid, inv = InviteCodeManager.validate_invite_code("USED123")
assert is_valid is False
assert inv is None
def test_validate_used_unlimited_invitation(self, app, client):
"""Test that used unlimited invitations are still valid."""
with app.app_context():
# Create used unlimited invitation
invitation = Invitation(
code="UNLIMITED123",
unlimited=True,
used=True,
)
db.session.add(invitation)
db.session.commit()
# Validate
is_valid, inv = InviteCodeManager.validate_invite_code("UNLIMITED123")
assert is_valid is True
assert inv is not None
def test_validate_nonexistent_invitation(self, app, client):
"""Test that nonexistent invitations are rejected."""
with app.app_context():
# Validate code that doesn't exist
is_valid, inv = InviteCodeManager.validate_invite_code("NOTEXIST123")
assert is_valid is False
assert inv is None
def test_validate_empty_code(self, app, client):
"""Test that empty code is rejected."""
with app.app_context():
# Validate empty code
is_valid, inv = InviteCodeManager.validate_invite_code("")
assert is_valid is False
assert inv is None
def test_validate_none_code(self, app, client):
"""Test that None code is rejected."""
with app.app_context():
# Validate None code
is_valid, inv = InviteCodeManager.validate_invite_code(None)
assert is_valid is False
assert inv is None
class TestPreWizardCompletion:
"""Test pre-wizard completion flag management."""
def test_mark_pre_wizard_complete(self, app, client):
"""Test marking pre-wizard as complete."""
with app.app_context():
with client.session_transaction():
# Initially not complete
assert InviteCodeManager.is_pre_wizard_complete() is False
with client.session_transaction():
# Mark as complete
InviteCodeManager.mark_pre_wizard_complete()
with client.session_transaction():
# Check completion status
assert InviteCodeManager.is_pre_wizard_complete() is True
def test_is_pre_wizard_complete_default_false(self, app, client):
"""Test that pre-wizard completion defaults to False."""
with app.app_context(), client.session_transaction():
assert InviteCodeManager.is_pre_wizard_complete() is False
class TestSessionCleanup:
"""Test session data cleanup."""
def test_clear_invite_data_removes_code(self, app, client):
"""Test that clear_invite_data removes stored invite code."""
with app.app_context():
with client.session_transaction():
# Store invite code
InviteCodeManager.store_invite_code("TEST123")
with client.session_transaction():
# Clear data
InviteCodeManager.clear_invite_data()
with client.session_transaction():
# Verify code is removed
code = InviteCodeManager.get_invite_code()
assert code is None
def test_clear_invite_data_removes_completion_flag(self, app, client):
"""Test that clear_invite_data removes pre-wizard completion flag."""
with app.app_context():
with client.session_transaction():
# Mark pre-wizard as complete
InviteCodeManager.mark_pre_wizard_complete()
with client.session_transaction():
# Clear data
InviteCodeManager.clear_invite_data()
with client.session_transaction():
# Verify flag is removed
assert InviteCodeManager.is_pre_wizard_complete() is False
def test_clear_invite_data_removes_all(self, app, client):
"""Test that clear_invite_data removes all invitation-related data."""
with app.app_context():
with client.session_transaction():
# Store both code and completion flag
InviteCodeManager.store_invite_code("TEST123")
InviteCodeManager.mark_pre_wizard_complete()
with client.session_transaction():
# Clear all data
InviteCodeManager.clear_invite_data()
with client.session_transaction():
# Verify everything is removed
assert InviteCodeManager.get_invite_code() is None
assert InviteCodeManager.is_pre_wizard_complete() is False
def test_clear_invite_data_when_empty(self, app, client):
"""Test that clear_invite_data works when no data is stored."""
with app.app_context():
with client.session_transaction():
# Clear data when nothing is stored (should not raise error)
InviteCodeManager.clear_invite_data()
with client.session_transaction():
# Verify still empty
assert InviteCodeManager.get_invite_code() is None
assert InviteCodeManager.is_pre_wizard_complete() is False