# Backend API Test Plan

This document outlines comprehensive test cases for all backend API endpoints in PunimTag.

## Test Structure Overview

The test suite uses:
- **pytest** - Testing framework
- **httpx/TestClient** - For making test requests to FastAPI
- **pytest-fixtures** - For database setup/teardown
- **Test database** - Separate PostgreSQL database for testing

## Test Files Organization

### 1. Authentication API Tests (`test_api_auth.py`)

#### Login Endpoints
- `test_login_success_with_valid_credentials` - Verify successful login with valid username/password
- `test_login_failure_with_invalid_credentials` - Verify 401 with invalid credentials
- `test_login_with_inactive_user` - Verify 401 when user account is inactive
- `test_login_without_password_hash` - Verify error when password_hash is missing
- `test_login_fallback_to_hardcoded_admin` - Verify fallback to admin/admin works
- `test_login_updates_last_login` - Verify last_login timestamp is updated

#### Token Refresh Endpoints
- `test_refresh_token_success` - Verify successful token refresh
- `test_refresh_token_with_invalid_token` - Verify 401 with invalid refresh token
- `test_refresh_token_with_access_token` - Verify 401 when using access token instead of refresh token
- `test_refresh_token_expired` - Verify 401 with expired refresh token

#### Current User Endpoints
- `test_get_current_user_info_authenticated` - Verify user info retrieval with valid token
- `test_get_current_user_info_unauthenticated` - Verify 401 without token
- `test_get_current_user_info_bootstrap_admin` - Verify admin bootstrap when no admins exist
- `test_get_current_user_info_role_permissions` - Verify role and permissions are returned

#### Password Change Endpoints
- `test_change_password_success` - Verify successful password change
- `test_change_password_with_wrong_current_password` - Verify 401 with incorrect current password
- `test_change_password_clears_password_change_required_flag` - Verify flag is cleared after change
- `test_change_password_user_not_found` - Verify 404 when user doesn't exist

#### Authentication Middleware
- `test_get_current_user_without_token` - Verify 401 without Authorization header
- `test_get_current_user_with_expired_token` - Verify 401 with expired JWT
- `test_get_current_user_with_invalid_token_format` - Verify 401 with malformed token
- `test_get_current_user_with_id_creates_user` - Verify user creation in bootstrap scenario

---

### 2. Photos API Tests (`test_api_photos.py`)

#### Photo Search Endpoints
- `test_search_photos_by_name_success` - Verify search by person name works
- `test_search_photos_by_name_without_person_name` - Verify 400 when person_name missing
- `test_search_photos_by_name_with_pagination` - Verify pagination works correctly
- `test_search_photos_by_date_success` - Verify date range search
- `test_search_photos_by_date_without_dates` - Verify 400 when both dates missing
- `test_search_photos_by_date_from_only` - Verify search with only date_from
- `test_search_photos_by_date_to_only` - Verify search with only date_to
- `test_search_photos_by_tags_success` - Verify tag search works
- `test_search_photos_by_tags_match_all` - Verify match_all parameter
- `test_search_photos_by_tags_match_any` - Verify match_any behavior
- `test_search_photos_by_tags_without_tags` - Verify 400 when tag_names missing
- `test_search_photos_no_faces` - Verify photos without faces search
- `test_search_photos_no_tags` - Verify photos without tags search
- `test_search_photos_processed` - Verify processed photos search
- `test_search_photos_unprocessed` - Verify unprocessed photos search
- `test_search_photos_favorites_authenticated` - Verify favorites search with auth
- `test_search_photos_favorites_unauthenticated` - Verify 401 without auth
- `test_search_photos_with_pagination` - Verify page and page_size parameters
- `test_search_photos_with_invalid_search_type` - Verify 400 with invalid search_type
- `test_search_photos_with_media_type_filter` - Verify image/video filtering
- `test_search_photos_with_folder_path_filter` - Verify folder path filtering
- `test_search_photos_with_date_filters_as_additional_filters` - Verify date filters in non-date searches
- `test_search_photos_returns_favorite_status` - Verify is_favorite field in results

#### Photo Import Endpoints
- `test_import_photos_success` - Verify photo import job is queued
- `test_import_photos_with_invalid_folder_path` - Verify 400 with invalid path
- `test_import_photos_with_nonexistent_folder` - Verify 400 when folder doesn't exist
- `test_import_photos_recursive` - Verify recursive import option
- `test_import_photos_returns_job_id` - Verify job_id is returned
- `test_import_photos_returns_estimated_count` - Verify estimated_photos count

#### Photo Upload Endpoints
- `test_upload_photos_success` - Verify single file upload
- `test_upload_photos_multiple_files` - Verify multiple file upload
- `test_upload_photos_duplicate_handling` - Verify duplicate detection
- `test_upload_photos_invalid_file_type` - Verify error handling for invalid files
- `test_upload_photos_returns_added_existing_counts` - Verify response counts

#### Photo Retrieval Endpoints
- `test_get_photo_by_id_success` - Verify photo retrieval by ID
- `test_get_photo_by_id_not_found` - Verify 404 for non-existent photo
- `test_get_photo_image_success` - Verify image file serving
- `test_get_photo_image_not_found` - Verify 404 when photo doesn't exist
- `test_get_photo_image_file_missing` - Verify 404 when file is missing
- `test_get_photo_image_content_type` - Verify correct Content-Type header
- `test_get_photo_image_cache_headers` - Verify cache headers are set

#### Photo Favorites Endpoints
- `test_toggle_favorite_add` - Verify adding favorite
- `test_toggle_favorite_remove` - Verify removing favorite
- `test_toggle_favorite_unauthenticated` - Verify 401 without auth
- `test_toggle_favorite_photo_not_found` - Verify 404 for non-existent photo
- `test_check_favorite_true` - Verify check returns true for favorited photo
- `test_check_favorite_false` - Verify check returns false for non-favorited photo
- `test_bulk_add_favorites_success` - Verify bulk add operation
- `test_bulk_add_favorites_already_favorites` - Verify handling of already-favorited photos
- `test_bulk_add_favorites_with_missing_photos` - Verify 404 with missing photo IDs
- `test_bulk_remove_favorites_success` - Verify bulk remove operation
- `test_bulk_remove_favorites_not_favorites` - Verify handling of non-favorited photos

#### Photo Deletion Endpoints
- `test_bulk_delete_photos_success` - Verify bulk delete (admin only)
- `test_bulk_delete_photos_non_admin` - Verify 403 for non-admin users
- `test_bulk_delete_photos_with_missing_ids` - Verify handling of missing IDs
- `test_bulk_delete_photos_cascades_to_faces_tags` - Verify cascade deletion
- `test_bulk_delete_photos_empty_list` - Verify 400 with empty photo_ids

#### Photo Folder Operations
- `test_browse_folder_success` - Verify folder picker works (if tkinter available)
- `test_browse_folder_no_display` - Verify graceful failure without display
- `test_browse_folder_cancelled` - Verify handling when user cancels
- `test_open_photo_folder_success` - Verify folder opening works
- `test_open_photo_folder_photo_not_found` - Verify 404 for non-existent photo
- `test_open_photo_folder_file_missing` - Verify 404 when file is missing

---

### 3. People API Tests (`test_api_people.py`)

#### People Listing Endpoints
- `test_list_people_success` - Verify people list retrieval
- `test_list_people_with_last_name_filter` - Verify last name filtering
- `test_list_people_case_insensitive_filter` - Verify case-insensitive search
- `test_list_people_with_faces_success` - Verify people with face counts
- `test_list_people_with_faces_includes_zero_counts` - Verify zero counts included
- `test_list_people_with_faces_last_name_filter` - Verify filtering with faces
- `test_list_people_with_faces_maiden_name_filter` - Verify maiden name filtering
- `test_list_people_sorted_by_name` - Verify sorting by last_name, first_name

#### People CRUD Endpoints
- `test_create_person_success` - Verify person creation
- `test_create_person_with_middle_name` - Verify optional middle_name
- `test_create_person_with_maiden_name` - Verify optional maiden_name
- `test_create_person_with_date_of_birth` - Verify date_of_birth handling
- `test_create_person_strips_whitespace` - Verify name trimming
- `test_get_person_by_id_success` - Verify person retrieval
- `test_get_person_by_id_not_found` - Verify 404 for non-existent person
- `test_update_person_success` - Verify person update
- `test_update_person_not_found` - Verify 404 when updating non-existent person
- `test_update_person_strips_whitespace` - Verify whitespace handling
- `test_delete_person_success` - Verify person deletion
- `test_delete_person_cascades_to_faces_and_encodings` - Verify cascade behavior
- `test_delete_person_cascades_to_video_linkages` - Verify video linkage cleanup
- `test_delete_person_not_found` - Verify 404 for non-existent person

#### People Faces Endpoints
- `test_get_person_faces_success` - Verify faces retrieval for person
- `test_get_person_faces_no_faces` - Verify empty list when no faces
- `test_get_person_faces_person_not_found` - Verify 404 for non-existent person
- `test_get_person_faces_sorted_by_filename` - Verify sorting
- `test_get_person_videos_success` - Verify videos linked to person
- `test_get_person_videos_no_videos` - Verify empty list when no videos
- `test_get_person_videos_person_not_found` - Verify 404 handling

#### People Match Acceptance Endpoints
- `test_accept_matches_success` - Verify accepting auto-match matches
- `test_accept_matches_tracks_user_id` - Verify user tracking
- `test_accept_matches_person_not_found` - Verify 404 for non-existent person
- `test_accept_matches_face_not_found` - Verify handling of missing faces
- `test_accept_matches_creates_person_encodings` - Verify encoding creation
- `test_accept_matches_updates_existing_encodings` - Verify encoding updates

---

### 4. Faces API Tests (`test_api_faces.py`)

#### Face Processing Endpoints
- `test_process_faces_success` - Verify face processing job queued
- `test_process_faces_redis_unavailable` - Verify 503 when Redis unavailable
- `test_process_faces_with_custom_detector` - Verify custom detector_backend
- `test_process_faces_with_custom_model` - Verify custom model_name
- `test_process_faces_with_batch_size` - Verify batch_size parameter
- `test_process_faces_returns_job_id` - Verify job_id in response

#### Unidentified Faces Endpoints
- `test_get_unidentified_faces_success` - Verify unidentified faces list
- `test_get_unidentified_faces_with_pagination` - Verify pagination
- `test_get_unidentified_faces_with_quality_filter` - Verify min_quality filter
- `test_get_unidentified_faces_with_date_filters` - Verify date filtering
- `test_get_unidentified_faces_with_tag_filters` - Verify tag filtering
- `test_get_unidentified_faces_with_photo_id_filter` - Verify photo ID filtering
- `test_get_unidentified_faces_include_excluded` - Verify include_excluded parameter
- `test_get_unidentified_faces_sort_by_quality` - Verify sorting by quality
- `test_get_unidentified_faces_sort_by_date` - Verify sorting by date
- `test_get_unidentified_faces_invalid_date_format` - Verify date validation
- `test_get_unidentified_faces_match_all_tags` - Verify match_all parameter

#### Similar Faces Endpoints
- `test_get_similar_faces_success` - Verify similar faces retrieval
- `test_get_similar_faces_include_excluded` - Verify include_excluded parameter
- `test_get_similar_faces_face_not_found` - Verify 404 for non-existent face
- `test_get_similar_faces_returns_similarity_scores` - Verify similarity in response
- `test_batch_similarity_success` - Verify batch similarity calculation
- `test_batch_similarity_with_min_confidence` - Verify min_confidence filter
- `test_batch_similarity_empty_list` - Verify handling of empty face_ids
- `test_batch_similarity_invalid_face_ids` - Verify error handling

#### Face Identification Endpoints
- `test_identify_face_with_existing_person` - Verify identification with existing person
- `test_identify_face_create_new_person` - Verify person creation during identification
- `test_identify_face_with_additional_faces` - Verify batch identification
- `test_identify_face_face_not_found` - Verify 404 for non-existent face
- `test_identify_face_person_not_found` - Verify 400 when person_id invalid
- `test_identify_face_tracks_user_id` - Verify user tracking
- `test_identify_face_creates_person_encodings` - Verify encoding creation
- `test_identify_face_requires_name_for_new_person` - Verify validation

#### Face Crop Endpoint
- `test_get_face_crop_success` - Verify face crop image generation
- `test_get_face_crop_face_not_found` - Verify 404 for non-existent face
- `test_get_face_crop_photo_file_missing` - Verify 404 when file missing
- `test_get_face_crop_invalid_location` - Verify 422 for invalid location
- `test_get_face_crop_exif_orientation_handling` - Verify EXIF correction
- `test_get_face_crop_resizes_small_faces` - Verify resizing for small faces
- `test_get_face_crop_content_type` - Verify correct Content-Type

#### Face Exclusion Endpoints
- `test_toggle_face_excluded_true` - Verify excluding face
- `test_toggle_face_excluded_false` - Verify including face
- `test_toggle_face_excluded_face_not_found` - Verify 404 handling

#### Face Unmatch Endpoints
- `test_unmatch_face_success` - Verify face unmatching
- `test_unmatch_face_already_unmatched` - Verify 400 when already unmatched
- `test_unmatch_face_deletes_person_encodings` - Verify encoding cleanup
- `test_batch_unmatch_faces_success` - Verify batch unmatch
- `test_batch_unmatch_faces_none_matched` - Verify 400 when none matched
- `test_batch_unmatch_faces_some_missing` - Verify 404 with missing faces

#### Auto-Match Endpoints
- `test_auto_match_faces_success` - Verify auto-match process
- `test_auto_match_faces_with_tolerance` - Verify tolerance parameter
- `test_auto_match_faces_auto_accept_enabled` - Verify auto-accept functionality
- `test_auto_match_faces_auto_accept_with_threshold` - Verify threshold filtering
- `test_auto_match_faces_auto_accept_filters_by_quality` - Verify quality filtering
- `test_auto_match_faces_auto_accept_filters_by_pose` - Verify pose filtering
- `test_get_auto_match_people_success` - Verify people list for auto-match
- `test_get_auto_match_people_filter_frontal_only` - Verify frontal filter
- `test_get_auto_match_person_matches_success` - Verify person matches retrieval
- `test_get_auto_match_person_matches_person_not_found` - Verify 404 handling

#### Face Maintenance Endpoints
- `test_list_all_faces_success` - Verify all faces listing
- `test_list_all_faces_with_filters` - Verify filtering options
- `test_list_all_faces_pagination` - Verify pagination
- `test_list_all_faces_excluded_filter` - Verify excluded status filter
- `test_list_all_faces_identified_filter` - Verify identified status filter
- `test_delete_faces_success` - Verify face deletion
- `test_delete_faces_with_missing_ids` - Verify 404 with missing IDs
- `test_delete_faces_deletes_person_encodings` - Verify encoding cleanup
- `test_delete_faces_empty_list` - Verify 400 with empty list

---

### 5. Tags API Tests (`test_api_tags.py`)

#### Tag Listing Endpoints
- `test_get_tags_success` - Verify tags list retrieval
- `test_get_tags_empty_list` - Verify empty list when no tags
- `test_get_tags_sorted` - Verify sorting behavior

#### Tag CRUD Endpoints
- `test_create_tag_success` - Verify tag creation
- `test_create_tag_duplicate` - Verify returns existing tag if duplicate
- `test_create_tag_strips_whitespace` - Verify whitespace handling
- `test_update_tag_success` - Verify tag update
- `test_update_tag_not_found` - Verify 404 for non-existent tag
- `test_delete_tag_success` - Verify tag deletion
- `test_delete_tag_with_photos` - Verify cascade or error handling
- `test_delete_tag_not_found` - Verify 404 handling

#### Photo-Tag Operations
- `test_add_tags_to_photos_success` - Verify adding tags to photos
- `test_add_tags_to_photos_empty_photo_ids` - Verify 400 with empty photo_ids
- `test_add_tags_to_photos_empty_tag_names` - Verify 400 with empty tag_names
- `test_add_tags_to_photos_creates_missing_tags` - Verify auto-creation
- `test_remove_tags_from_photos_success` - Verify tag removal
- `test_get_photo_tags_success` - Verify photo tags retrieval
- `test_get_photo_tags_empty` - Verify empty list for untagged photo
- `test_get_photos_with_tags_success` - Verify photos with tags query
- `test_get_photos_with_tags_multiple_tags` - Verify multiple tag filtering
- `test_get_photos_with_tags_match_all` - Verify match_all behavior

---

### 6. Users API Tests (`test_api_users.py`)

#### User Listing Endpoints
- `test_list_users_success` - Verify users list (admin only)
- `test_list_users_non_admin` - Verify 403 for non-admin users
- `test_list_users_with_pagination` - Verify pagination
- `test_list_users_with_search_filter` - Verify search functionality
- `test_list_users_includes_role_info` - Verify role information

#### User CRUD Endpoints
- `test_create_user_success` - Verify user creation (admin only)
- `test_create_user_duplicate_email` - Verify 400 with duplicate email
- `test_create_user_duplicate_username` - Verify 400 with duplicate username
- `test_create_user_with_role` - Verify role assignment
- `test_create_user_creates_auth_user` - Verify auth database sync
- `test_create_user_password_validation` - Verify password requirements
- `test_get_user_by_id_success` - Verify user retrieval
- `test_get_user_by_id_not_found` - Verify 404 for non-existent user
- `test_update_user_success` - Verify user update
- `test_update_user_role_change` - Verify role updates
- `test_update_user_email_conflict` - Verify email uniqueness
- `test_delete_user_success` - Verify user deletion
- `test_delete_user_with_linked_data` - Verify graceful handling
- `test_delete_user_cascades_to_auth_database` - Verify auth DB cleanup
- `test_delete_user_non_admin` - Verify 403 for non-admin

#### User Activation Endpoints
- `test_activate_user_success` - Verify user activation
- `test_deactivate_user_success` - Verify user deactivation
- `test_activate_user_not_found` - Verify 404 handling

---

### 7. Jobs API Tests (`test_api_jobs.py`)

#### Job Status Endpoints
- `test_get_job_status_queued` - Verify queued job status
- `test_get_job_status_started` - Verify started job status
- `test_get_job_status_progress` - Verify progress status with metadata
- `test_get_job_status_success` - Verify completed job status
- `test_get_job_status_failed` - Verify failed job status
- `test_get_job_status_cancelled` - Verify cancelled job status
- `test_get_job_status_not_found` - Verify 404 for non-existent job
- `test_get_job_status_includes_timestamps` - Verify timestamp fields

#### Job Streaming Endpoints
- `test_stream_job_progress_success` - Verify SSE stream works
- `test_stream_job_progress_updates` - Verify progress updates in stream
- `test_stream_job_progress_completion` - Verify completion event
- `test_stream_job_progress_not_found` - Verify 404 handling
- `test_stream_job_progress_sse_format` - Verify SSE format compliance

---

### 8. Health & Version API Tests (`test_api_health.py`)

#### Health Check Endpoints
- `test_health_check_success` - Verify health endpoint returns 200
- `test_health_check_database_connection` - Verify DB connection check
- `test_version_endpoint_success` - Verify version information
- `test_version_endpoint_includes_app_version` - Verify version format
- `test_metrics_endpoint_success` - Verify metrics endpoint (if applicable)

---

### 9. Integration Tests (`test_api_integration.py`)

#### End-to-End Workflows
- `test_photo_import_to_face_processing_to_identification_workflow` - Full photo import workflow
- `test_create_person_identify_faces_auto_match_workflow` - Person creation to auto-match
- `test_tag_photos_search_by_tags_workflow` - Tagging and search workflow
- `test_favorite_photos_search_favorites_workflow` - Favorites workflow
- `test_user_creation_login_role_permissions_workflow` - User management workflow
- `test_bulk_operations_workflow` - Multiple bulk operations in sequence
- `test_concurrent_requests_workflow` - Verify concurrent request handling

---

### 10. Error Handling & Edge Cases (`test_api_errors.py`)

#### Error Response Tests
- `test_404_not_found_responses` - Verify 404 responses across endpoints
- `test_400_bad_request_validation` - Verify validation error responses
- `test_401_unauthorized_responses` - Verify authentication errors
- `test_403_forbidden_responses` - Verify authorization errors
- `test_422_unprocessable_entity` - Verify unprocessable entity errors
- `test_500_internal_server_error_handling` - Verify error handling
- `test_database_connection_failure_handling` - Verify DB failure handling
- `test_redis_connection_failure_handling` - Verify Redis failure handling
- `test_file_operation_errors` - Verify file operation error handling
- `test_concurrent_request_handling` - Verify concurrent operations
- `test_large_payload_handling` - Verify handling of large requests
- `test_sql_injection_attempts` - Verify SQL injection protection
- `test_xss_attempts` - Verify XSS protection
- `test_path_traversal_attempts` - Verify path traversal protection

---

## Test Infrastructure Setup

### Test Configuration (`conftest.py`)

The test suite requires a `conftest.py` file with the following fixtures:

```python
# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from backend.app import create_app
from backend.db.base import Base
from backend.db.session import get_db

# Test database URL (use separate test database)
TEST_DATABASE_URL = "postgresql+psycopg2://postgres:postgres@localhost:5432/punimtag_test"

@pytest.fixture(scope="session")
def test_db_engine():
    """Create test database engine."""
    engine = create_engine(TEST_DATABASE_URL)
    Base.metadata.create_all(bind=engine)
    yield engine
    Base.metadata.drop_all(bind=engine)

@pytest.fixture(scope="function")
def test_db_session(test_db_engine):
    """Create a test database session with transaction rollback."""
    connection = test_db_engine.connect()
    transaction = connection.begin()
    session = sessionmaker(bind=connection)()
    
    yield session
    
    session.close()
    transaction.rollback()
    connection.close()

@pytest.fixture(scope="function")
def test_client(test_db_session):
    """Create a test client with test database."""
    app = create_app()
    
    def override_get_db():
        yield test_db_session
    
    app.dependency_overrides[get_db] = override_get_db
    
    with TestClient(app) as client:
        yield client
    
    app.dependency_overrides.clear()

@pytest.fixture
def auth_token(test_client):
    """Get authentication token for test user."""
    response = test_client.post(
        "/api/v1/auth/login",
        json={"username": "admin", "password": "admin"}
    )
    return response.json()["access_token"]

@pytest.fixture
def auth_headers(auth_token):
    """Get authentication headers."""
    return {"Authorization": f"Bearer {auth_token}"}

@pytest.fixture
def admin_user(test_db_session):
    """Create an admin user for testing."""
    from backend.db.models import User
    from backend.utils.password import hash_password
    
    user = User(
        username="testadmin",
        email="testadmin@example.com",
        password_hash=hash_password("testpass"),
        is_admin=True,
        is_active=True,
    )
    test_db_session.add(user)
    test_db_session.commit()
    return user

@pytest.fixture
def regular_user(test_db_session):
    """Create a regular user for testing."""
    from backend.db.models import User
    from backend.utils.password import hash_password
    
    user = User(
        username="testuser",
        email="testuser@example.com",
        password_hash=hash_password("testpass"),
        is_admin=False,
        is_active=True,
    )
    test_db_session.add(user)
    test_db_session.commit()
    return user
```

### Test Database Setup

1. Create a separate test database:
   ```sql
   CREATE DATABASE punimtag_test;
   ```

2. Set test database URL in environment or test config:
   ```bash
   export DATABASE_URL="postgresql+psycopg2://postgres:postgres@localhost:5432/punimtag_test"
   ```

3. Ensure Redis is available for job-related tests (or mock it)

---

## Priority Recommendations

### High Priority (Core Functionality)
1. **Authentication** - Login, token refresh, password change
2. **Photo Search** - All search types and filters
3. **Face Identification** - Core face matching and identification
4. **User Management** - Admin operations and role management

### Medium Priority (Important Features)
1. **Tag Operations** - CRUD and photo-tag relationships
2. **People CRUD** - Person management
3. **Job Status Tracking** - Background job monitoring
4. **Bulk Operations** - Bulk favorites, deletions, etc.

### Lower Priority (Nice to Have)
1. **File Operations** - Browse folder, open folder (OS-dependent)
2. **Maintenance Endpoints** - Advanced maintenance features
3. **Edge Cases** - Comprehensive error handling tests

---

## Testing Best Practices

1. **Use Fixtures** - Leverage pytest fixtures for common setup (database, auth tokens)
2. **Test Both Paths** - Always test both success and failure scenarios
3. **Test Authorization** - Verify admin vs regular user permissions
4. **Test Pagination** - Verify pagination works for all list endpoints
5. **Test Validation** - Test input validation (empty strings, invalid IDs, etc.)
6. **Test Transactions** - Verify database transactions and rollbacks
7. **Use Test Database** - Always use a separate test database
8. **Clean Up** - Ensure test data is cleaned up after each test
9. **Test Concurrency** - Test concurrent operations where relevant
10. **Mock External Dependencies** - Mock Redis, file system when needed
11. **Test Error Messages** - Verify error messages are helpful
12. **Test Response Formats** - Verify response schemas match expectations
13. **Test Edge Cases** - Test boundary conditions and edge cases
14. **Test Performance** - Consider performance tests for critical endpoints
15. **Test Security** - Test authentication, authorization, and input sanitization

---

## Running Tests

### Run All Tests
```bash
npm run test:backend
# or
pytest tests/ -v
```

### Run Specific Test File
```bash
pytest tests/test_api_auth.py -v
```

### Run Specific Test
```bash
pytest tests/test_api_auth.py::test_login_success_with_valid_credentials -v
```

### Run with Coverage
```bash
pytest tests/ --cov=backend --cov-report=html
```

### Run in CI
The CI workflow (`.gitea/workflows/ci.yml`) already includes a `test-backend` job that runs:
```bash
python -m pytest tests/ -v
```

---

## Test Coverage Goals

- **Minimum Coverage**: 80% (as per project rules)
- **Critical Endpoints**: 100% coverage (auth, photo search, face identification)
- **All Endpoints**: At least basic success/failure tests

---

## Notes

- Tests should be independent and not rely on execution order
- Use transaction rollback to ensure test isolation
- Mock external services (Redis, file system) when appropriate
- Use factories or fixtures for test data creation
- Keep tests fast - avoid unnecessary I/O operations
- Document complex test scenarios with comments

