Files
KohakuHub/tests/test_auth.py

214 lines
8.0 KiB
Python

"""Authentication API tests.
Tests user registration, login, logout, token management, and whoami endpoints.
Uses actual Pydantic models from the source code.
"""
import uuid
import pytest
from tests.base import HTTPClient
from tests.config import config
class TestAuthentication:
"""Test authentication endpoints."""
def test_version_check(self, http_client):
"""Test API version endpoint."""
resp = http_client.get("/api/version")
assert resp.status_code == 200
data = resp.json()
assert "api" in data
assert data["api"] == "kohakuhub"
assert "version" in data
def test_register_login_logout_flow(self, http_client):
"""Test complete user registration, login, and logout flow."""
# Import actual Pydantic models
from kohakuhub.auth.routes import RegisterRequest, LoginRequest
# Use unique username for this test
unique_id = uuid.uuid4().hex[:6]
test_username = f"user-{unique_id}" # Matches ^[a-z0-9][a-z0-9-]{2,62}$
test_email = f"test-{unique_id}@example.com"
test_password = "testpass123"
# 1. Register new user using actual model
payload = RegisterRequest(
username=test_username, email=test_email, password=test_password
)
resp = http_client.post("/api/auth/register", json=payload.model_dump())
assert resp.status_code == 200, f"Registration failed: {resp.text}"
data = resp.json()
assert data["success"] == True
# 2. Login using actual model
login_payload = LoginRequest(username=test_username, password=test_password)
resp = http_client.post("/api/auth/login", json=login_payload.model_dump())
assert resp.status_code == 200, f"Login failed: {resp.text}"
data = resp.json()
assert "username" in data
assert data["username"] == test_username
# Save session
session_cookies = resp.cookies
# 3. Get current user (with session)
client_with_session = HTTPClient()
client_with_session.session.cookies.update(session_cookies)
resp = client_with_session.get("/api/auth/me")
assert resp.status_code == 200, f"Get user failed: {resp.text}"
data = resp.json()
assert data["username"] == test_username
# 4. Logout
resp = client_with_session.post("/api/auth/logout")
assert resp.status_code == 200
# 5. Verify session is cleared
resp = client_with_session.get("/api/auth/me")
assert resp.status_code == 401, "Session should be cleared after logout"
def test_token_creation_and_usage(self, authenticated_http_client):
"""Test API token creation and usage."""
from kohakuhub.auth.routes import CreateTokenRequest
# 1. Create token using actual model
unique_id = uuid.uuid4().hex[:6]
token_payload = CreateTokenRequest(name=f"token-{unique_id}")
resp = authenticated_http_client.post(
"/api/auth/tokens/create", json=token_payload.model_dump()
)
assert resp.status_code == 200, f"Token creation failed: {resp.text}"
data = resp.json()
assert "token" in data
assert "token_id" in data
token = data["token"]
token_id = data["token_id"]
# 2. Use token for authentication
client_with_token = HTTPClient(token=token)
resp = client_with_token.get("/api/auth/me")
assert resp.status_code == 200, f"Token auth failed: {resp.text}"
user_data = resp.json()
assert user_data["username"] == config.username
# 3. List tokens
resp = authenticated_http_client.get("/api/auth/tokens")
assert resp.status_code == 200
tokens_response = resp.json()
assert "tokens" in tokens_response
tokens = tokens_response["tokens"]
assert isinstance(tokens, list)
# Our token should be in the list
token_names = [t["name"] for t in tokens]
assert token_payload.name in token_names
# 4. Revoke token
resp = authenticated_http_client.delete(f"/api/auth/tokens/{token_id}")
assert resp.status_code == 200
# 5. Verify token is revoked
resp = client_with_token.get("/api/auth/me")
assert resp.status_code == 401, "Token should be revoked"
def test_whoami_endpoint(self, authenticated_http_client):
"""Test whoami-v2 endpoint for detailed user info."""
resp = authenticated_http_client.get("/api/whoami-v2")
assert resp.status_code == 200, f"whoami-v2 failed: {resp.text}"
data = resp.json()
# Validate response structure (based on actual implementation in misc.py)
assert "type" in data
assert data["type"] == "user"
assert "name" in data
assert data["name"] == config.username
assert "email" in data
assert "orgs" in data
assert isinstance(data["orgs"], list)
assert "emailVerified" in data
assert "auth" in data
def test_invalid_credentials(self, http_client):
"""Test login with invalid credentials."""
from kohakuhub.auth.routes import LoginRequest
payload = LoginRequest(username="nonexistent", password="wrongpass")
resp = http_client.post("/api/auth/login", json=payload.model_dump())
assert resp.status_code == 401, "Should reject invalid credentials"
def test_unauthenticated_access(self, http_client):
"""Test accessing protected endpoints without authentication."""
# Try to access protected endpoint
resp = http_client.get("/api/auth/me")
assert resp.status_code == 401, "Should require authentication"
# Try to create repo without auth
from kohakuhub.api.repo.routers.crud import CreateRepoPayload
payload = CreateRepoPayload(type="model", name="test-repo")
resp = http_client.post("/api/repos/create", json=payload.model_dump())
assert resp.status_code in [401, 403], "Should require authentication"
def test_duplicate_registration(self, http_client):
"""Test that duplicate usernames are rejected."""
from kohakuhub.auth.routes import RegisterRequest
unique_id = uuid.uuid4().hex[:6]
test_username = f"dup-{unique_id}"
test_email = f"dup-{unique_id}@example.com"
payload = RegisterRequest(
username=test_username, email=test_email, password="testpass123"
)
# First registration
resp = http_client.post("/api/auth/register", json=payload.model_dump())
assert resp.status_code == 200
# Second registration with same username (different email)
payload2 = RegisterRequest(
username=test_username,
email=f"different_{unique_id}@example.com",
password="testpass123",
)
resp = http_client.post("/api/auth/register", json=payload2.model_dump())
assert resp.status_code == 400
assert "username" in resp.text.lower() or "exist" in resp.text.lower()
def test_duplicate_email_registration(self, http_client):
"""Test that duplicate emails are rejected."""
from kohakuhub.auth.routes import RegisterRequest
unique_id = uuid.uuid4().hex[:6]
test_username = f"email-{unique_id}"
test_email = f"email-{unique_id}@example.com"
payload = RegisterRequest(
username=test_username, email=test_email, password="testpass123"
)
# First registration
resp = http_client.post("/api/auth/register", json=payload.model_dump())
assert resp.status_code == 200
# Second registration with same email (different username)
payload2 = RegisterRequest(
username=f"different_{unique_id}",
email=test_email,
password="testpass123",
)
resp = http_client.post("/api/auth/register", json=payload2.model_dump())
assert resp.status_code == 400
assert "email" in resp.text.lower() or "exist" in resp.text.lower()