Files
openrouter-watcher/tests/unit/schemas/test_auth_schemas.py
Luca Sacchi Ricciardi 02473bc39e feat(schemas): T17 add Pydantic auth schemas
Add authentication schemas for user registration and login:
- UserRegister: email, password (with strength validation), password_confirm
- UserLogin: email, password
- UserResponse: id, email, created_at, is_active (orm_mode=True)
- TokenResponse: access_token, token_type, expires_in
- TokenData: user_id, exp

Includes field validators for password strength and password confirmation matching.

Test coverage: 19 tests for all schemas
2026-04-07 13:52:33 +02:00

263 lines
8.4 KiB
Python

"""Tests for authentication Pydantic schemas.
T17: Test Pydantic schemas for user authentication.
"""
import pytest
from pydantic import ValidationError, EmailStr
from datetime import datetime, timezone
class TestUserRegister:
"""Tests for UserRegister schema."""
def test_valid_registration(self):
"""Test valid user registration data."""
# This will fail until schema is implemented
from openrouter_monitor.schemas.auth import UserRegister
data = UserRegister(
email="test@example.com",
password="SecurePass123!",
password_confirm="SecurePass123!"
)
assert data.email == "test@example.com"
assert data.password == "SecurePass123!"
assert data.password_confirm == "SecurePass123!"
def test_invalid_email_format(self):
"""Test that invalid email format raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="email"):
UserRegister(
email="not-an-email",
password="SecurePass123!",
password_confirm="SecurePass123!"
)
def test_password_too_short(self):
"""Test that password shorter than 12 chars raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="password"):
UserRegister(
email="test@example.com",
password="Short1!",
password_confirm="Short1!"
)
def test_password_missing_uppercase(self):
"""Test that password without uppercase raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="password"):
UserRegister(
email="test@example.com",
password="lowercase123!",
password_confirm="lowercase123!"
)
def test_password_missing_lowercase(self):
"""Test that password without lowercase raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="password"):
UserRegister(
email="test@example.com",
password="UPPERCASE123!",
password_confirm="UPPERCASE123!"
)
def test_password_missing_digit(self):
"""Test that password without digit raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="password"):
UserRegister(
email="test@example.com",
password="NoDigitsHere!",
password_confirm="NoDigitsHere!"
)
def test_password_missing_special_char(self):
"""Test that password without special char raises ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="password"):
UserRegister(
email="test@example.com",
password="NoSpecialChars123",
password_confirm="NoSpecialChars123"
)
def test_passwords_do_not_match(self):
"""Test that mismatched passwords raise ValidationError."""
from openrouter_monitor.schemas.auth import UserRegister
with pytest.raises(ValidationError, match="match"):
UserRegister(
email="test@example.com",
password="SecurePass123!",
password_confirm="DifferentPass123!"
)
def test_password_strength_validator_called(self):
"""Test that validate_password_strength is called."""
from openrouter_monitor.schemas.auth import UserRegister
# Valid password should pass
data = UserRegister(
email="test@example.com",
password="ValidPass123!@#",
password_confirm="ValidPass123!@#"
)
assert data.password == "ValidPass123!@#"
class TestUserLogin:
"""Tests for UserLogin schema."""
def test_valid_login(self):
"""Test valid login credentials."""
from openrouter_monitor.schemas.auth import UserLogin
data = UserLogin(
email="test@example.com",
password="anypassword"
)
assert data.email == "test@example.com"
assert data.password == "anypassword"
def test_invalid_email_format(self):
"""Test that invalid email format raises ValidationError."""
from openrouter_monitor.schemas.auth import UserLogin
with pytest.raises(ValidationError, match="email"):
UserLogin(
email="not-an-email",
password="password"
)
def test_empty_password(self):
"""Test that empty password is allowed (validation happens elsewhere)."""
from openrouter_monitor.schemas.auth import UserLogin
data = UserLogin(
email="test@example.com",
password=""
)
assert data.password == ""
class TestUserResponse:
"""Tests for UserResponse schema."""
def test_valid_response(self):
"""Test valid user response."""
from openrouter_monitor.schemas.auth import UserResponse
from datetime import datetime
created_at = datetime(2024, 1, 1, 12, 0, 0)
data = UserResponse(
id=1,
email="test@example.com",
created_at=created_at,
is_active=True
)
assert data.id == 1
assert data.email == "test@example.com"
assert data.created_at == created_at
assert data.is_active is True
def test_from_orm(self):
"""Test that UserResponse can be created from ORM model."""
from openrouter_monitor.schemas.auth import UserResponse
from datetime import datetime
# Mock ORM object
class MockUser:
id = 1
email = "test@example.com"
created_at = datetime(2024, 1, 1, 12, 0, 0)
is_active = True
user = UserResponse.model_validate(MockUser())
assert user.id == 1
assert user.email == "test@example.com"
class TestTokenResponse:
"""Tests for TokenResponse schema."""
def test_valid_token_response(self):
"""Test valid token response."""
from openrouter_monitor.schemas.auth import TokenResponse
data = TokenResponse(
access_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
token_type="bearer",
expires_in=3600
)
assert data.access_token == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
assert data.token_type == "bearer"
assert data.expires_in == 3600
def test_default_token_type(self):
"""Test that default token_type is 'bearer'."""
from openrouter_monitor.schemas.auth import TokenResponse
data = TokenResponse(
access_token="some_token",
expires_in=3600
)
assert data.token_type == "bearer"
class TestTokenData:
"""Tests for TokenData schema."""
def test_valid_token_data(self):
"""Test valid token data."""
from openrouter_monitor.schemas.auth import TokenData
exp = datetime.now(timezone.utc)
data = TokenData(
user_id="123",
exp=exp
)
assert data.user_id == "123"
assert data.exp == exp
def test_user_id_from_sub(self):
"""Test that user_id can be extracted from sub claim."""
from openrouter_monitor.schemas.auth import TokenData
exp = datetime.now(timezone.utc)
# TokenData might be created from JWT payload with 'sub' field
data = TokenData(user_id="456", exp=exp)
assert data.user_id == "456"
def test_user_id_integer_conversion(self):
"""Test that user_id handles integer IDs."""
from openrouter_monitor.schemas.auth import TokenData
exp = datetime.now(timezone.utc)
data = TokenData(
user_id=123, # Integer ID
exp=exp
)
assert data.user_id == 123