mud/tests/test_login_flow.py
Jared Miller 3fe51f2552
Add login and registration flow with server integration
Adds login/registration prompts on connection, database initialization on
startup, and periodic auto-save every 5 minutes in the game loop. Player
state is now tied to authenticated accounts.
2026-02-07 21:42:12 -05:00

164 lines
4.1 KiB
Python

"""Tests for login and registration flow."""
import os
import tempfile
import pytest
from mudlib.server import handle_login
from mudlib.store import account_exists, authenticate, init_db
@pytest.fixture
def temp_db():
"""Create a temporary database for testing."""
with tempfile.NamedTemporaryFile(delete=False, suffix=".db") as f:
db_path = f.name
init_db(db_path)
yield db_path
# Cleanup
os.unlink(db_path)
@pytest.mark.asyncio
async def test_login_existing_account_correct_password(temp_db):
"""Login succeeds with correct password."""
from mudlib.store import create_account
create_account("TestUser", "correct_password")
# Mock I/O
inputs = ["correct_password"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("TestUser", mock_read, mock_write)
assert result["success"] is True
assert result["player_data"] is not None
assert result["player_data"]["x"] == 0
assert result["player_data"]["y"] == 0
@pytest.mark.asyncio
async def test_login_existing_account_wrong_password(temp_db):
"""Login fails with wrong password after max attempts."""
from mudlib.store import create_account
create_account("TestUser", "correct_password")
# Mock I/O - provide wrong password 3 times
inputs = ["wrong1", "wrong2", "wrong3"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("TestUser", mock_read, mock_write)
assert result["success"] is False
assert "Too many failed attempts" in "".join(outputs)
@pytest.mark.asyncio
async def test_login_existing_account_retry_success(temp_db):
"""Login succeeds after retrying wrong password."""
from mudlib.store import create_account
create_account("TestUser", "correct_password")
# Mock I/O - wrong password first, then correct
inputs = ["wrong_password", "correct_password"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("TestUser", mock_read, mock_write)
assert result["success"] is True
assert result["player_data"] is not None
@pytest.mark.asyncio
async def test_registration_new_account(temp_db):
"""Registration creates a new account."""
# Mock I/O - answer 'y' to create account, then provide password twice
inputs = ["y", "newpassword", "newpassword"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("NewUser", mock_read, mock_write)
assert result["success"] is True
assert account_exists("NewUser")
assert authenticate("NewUser", "newpassword")
@pytest.mark.asyncio
async def test_registration_password_mismatch(temp_db):
"""Registration fails if passwords don't match."""
# Mock I/O - answer 'y', then mismatched passwords, then cancel
inputs = ["y", "password1", "password2", "n"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("NewUser", mock_read, mock_write)
assert result["success"] is False
assert not account_exists("NewUser")
@pytest.mark.asyncio
async def test_registration_declined(temp_db):
"""User declines to create account."""
# Mock I/O - answer 'n' to create account
inputs = ["n"]
outputs = []
async def mock_write(msg: str):
outputs.append(msg)
async def mock_read():
if inputs:
return inputs.pop(0)
return None
result = await handle_login("NewUser", mock_read, mock_write)
assert result["success"] is False
assert not account_exists("NewUser")