"""Unit tests for user service Tests for the users table and upsert operations used in report generation. """ import pytest from datetime import datetime, timedelta from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from app.core.database import Base from app.modules.auth.models import User from app.modules.auth.services.user_service import upsert_user, get_user_by_id, get_display_name # Create in-memory SQLite database for testing @pytest.fixture def db_session(): """Create a fresh database session for each test""" engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(bind=engine) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = SessionLocal() try: yield session finally: session.close() class TestUpsertUser: """Tests for upsert_user function""" def test_create_new_user(self, db_session): """Test creating a new user record""" user = upsert_user( db=db_session, user_id="test@example.com", display_name="Test User 測試用戶", office_location="Taipei", job_title="Engineer", ) assert user.user_id == "test@example.com" assert user.display_name == "Test User 測試用戶" assert user.office_location == "Taipei" assert user.job_title == "Engineer" assert user.last_login_at is not None assert user.created_at is not None def test_update_existing_user(self, db_session): """Test updating an existing user record""" # Create initial user user1 = upsert_user( db=db_session, user_id="test@example.com", display_name="Original Name", office_location="Taipei", job_title="Junior Engineer", ) original_created_at = user1.created_at original_last_login = user1.last_login_at # Wait a tiny bit to ensure timestamp difference import time time.sleep(0.01) # Update same user user2 = upsert_user( db=db_session, user_id="test@example.com", display_name="Updated Name 更新名稱", office_location="Kaohsiung", job_title="Senior Engineer", ) # Verify update assert user2.user_id == "test@example.com" assert user2.display_name == "Updated Name 更新名稱" assert user2.office_location == "Kaohsiung" assert user2.job_title == "Senior Engineer" # created_at should be preserved assert user2.created_at == original_created_at # last_login_at should be updated assert user2.last_login_at >= original_last_login def test_upsert_with_null_optional_fields(self, db_session): """Test upsert with null office_location and job_title""" user = upsert_user( db=db_session, user_id="test@example.com", display_name="Test User", office_location=None, job_title=None, ) assert user.office_location is None assert user.job_title is None def test_update_clears_optional_fields(self, db_session): """Test that updating with None clears optional fields""" # Create with values upsert_user( db=db_session, user_id="test@example.com", display_name="Test User", office_location="Taipei", job_title="Engineer", ) # Update with None user = upsert_user( db=db_session, user_id="test@example.com", display_name="Test User", office_location=None, job_title=None, ) assert user.office_location is None assert user.job_title is None class TestGetUserById: """Tests for get_user_by_id function""" def test_get_existing_user(self, db_session): """Test getting an existing user""" upsert_user( db=db_session, user_id="test@example.com", display_name="Test User", ) user = get_user_by_id(db_session, "test@example.com") assert user is not None assert user.display_name == "Test User" def test_get_nonexistent_user(self, db_session): """Test getting a user that doesn't exist""" user = get_user_by_id(db_session, "nonexistent@example.com") assert user is None class TestGetDisplayName: """Tests for get_display_name function""" def test_get_display_name_existing_user(self, db_session): """Test getting display name for existing user""" upsert_user( db=db_session, user_id="test@example.com", display_name="Test User 測試用戶", ) name = get_display_name(db_session, "test@example.com") assert name == "Test User 測試用戶" def test_get_display_name_nonexistent_user(self, db_session): """Test fallback to email for nonexistent user""" name = get_display_name(db_session, "unknown@example.com") # Should return email as fallback assert name == "unknown@example.com"