247 lines
7.3 KiB
Markdown
247 lines
7.3 KiB
Markdown
# API Endpoint Tests
|
|
|
|
This directory contains comprehensive integration tests for all FastAPI REST API endpoints in the Aniworld web application.
|
|
|
|
## Test Files
|
|
|
|
### 1. test_auth_endpoints.py
|
|
|
|
Tests for authentication API endpoints (`/api/auth/*`):
|
|
|
|
- ✅ Master password setup flow
|
|
- ✅ Login with valid/invalid credentials
|
|
- ✅ Authentication status checking
|
|
- ✅ Token-based authentication
|
|
- ✅ Logout functionality
|
|
- ⚠️ Rate limiting behavior (some race conditions with trio backend)
|
|
|
|
**Status**: 1/2 tests passing (asyncio: ✅, trio: ⚠️ rate limiting)
|
|
|
|
### 2. test_anime_endpoints.py
|
|
|
|
Tests for anime management API endpoints (`/api/v1/anime/*`):
|
|
|
|
- ✅ List anime series with missing episodes
|
|
- ✅ Get anime series details
|
|
- ✅ Trigger rescan of local anime library
|
|
- ✅ Search for anime series
|
|
- ✅ Unauthorized access handling
|
|
- ✅ Direct function call tests
|
|
- ✅ HTTP endpoint integration tests
|
|
|
|
**Status**: 11/11 tests passing ✅
|
|
|
|
### 3. test_config_endpoints.py
|
|
|
|
Tests for configuration API endpoints (`/api/config/*`):
|
|
|
|
- ⚠️ Get current configuration
|
|
- ⚠️ Validate configuration
|
|
- ⚠️ Update configuration (authenticated)
|
|
- ⚠️ List configuration backups
|
|
- ⚠️ Create configuration backup
|
|
- ⚠️ Restore from backup
|
|
- ⚠️ Delete backup
|
|
- ⚠️ Configuration persistence
|
|
|
|
**Status**: 0/18 tests passing - needs authentication fixes
|
|
|
|
**Issues**:
|
|
|
|
- Config endpoints require authentication but tests need proper auth client fixture
|
|
- Mock config service may need better integration
|
|
|
|
### 4. test_download_endpoints.py
|
|
|
|
Tests for download queue API endpoints (`/api/queue/*`):
|
|
|
|
- ⚠️ Get queue status and statistics
|
|
- ⚠️ Add episodes to download queue
|
|
- ⚠️ Remove items from queue (single/multiple)
|
|
- ⚠️ Start/stop/pause/resume queue
|
|
- ⚠️ Reorder queue items
|
|
- ⚠️ Clear completed downloads
|
|
- ⚠️ Retry failed downloads
|
|
- ✅ Unauthorized access handling (2/2 tests passing)
|
|
|
|
**Status**: 2/36 tests passing - fixture dependency issues
|
|
|
|
**Issues**:
|
|
|
|
- `authenticated_client` fixture dependency on `mock_download_service` causing setup errors
|
|
- Authentication rate limiting across test runs
|
|
- Need proper mocking of download service dependencies
|
|
|
|
## Test Infrastructure
|
|
|
|
### Fixtures
|
|
|
|
#### Common Fixtures
|
|
|
|
- `reset_auth_state`: Auto-use fixture that clears rate limiting state between tests
|
|
- `authenticated_client`: Creates async client with valid JWT token
|
|
- `client`: Creates unauthenticated async client
|
|
|
|
#### Service-Specific Fixtures
|
|
|
|
- `mock_download_service`: Mocks DownloadService for testing download endpoints
|
|
- `mock_config_service`: Mocks ConfigService with temporary config files
|
|
- `temp_config_dir`: Provides temporary directory for config test isolation
|
|
|
|
### Testing Patterns
|
|
|
|
#### Async/Await Pattern
|
|
|
|
All tests use `pytest.mark.anyio` decorator for async test support:
|
|
|
|
```python
|
|
@pytest.mark.anyio
|
|
async def test_example(authenticated_client):
|
|
response = await authenticated_client.get("/api/endpoint")
|
|
assert response.status_code == 200
|
|
```
|
|
|
|
#### Authentication Testing
|
|
|
|
Tests use fixture-based authentication:
|
|
|
|
```python
|
|
@pytest.fixture
|
|
async def authenticated_client():
|
|
"""Create authenticated async client."""
|
|
if not auth_service.is_configured():
|
|
auth_service.setup_master_password("TestPass123!")
|
|
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as client:
|
|
r = await client.post("/api/auth/login", json={"password": "TestPass123!"})
|
|
token = r.json()["access_token"]
|
|
client.headers["Authorization"] = f"Bearer {token}"
|
|
yield client
|
|
```
|
|
|
|
#### Service Mocking
|
|
|
|
External dependencies are mocked using `unittest.mock`:
|
|
|
|
```python
|
|
@pytest.fixture
|
|
def mock_download_service():
|
|
"""Mock DownloadService for testing."""
|
|
with patch("src.server.utils.dependencies.get_download_service") as mock:
|
|
service = MagicMock()
|
|
service.get_queue_status = AsyncMock(return_value=QueueStatus(...))
|
|
mock.return_value = service
|
|
yield service
|
|
```
|
|
|
|
## Running Tests
|
|
|
|
### Run All API Tests
|
|
|
|
```bash
|
|
conda run -n AniWorld python -m pytest tests/api/ -v
|
|
```
|
|
|
|
### Run Specific Test File
|
|
|
|
```bash
|
|
conda run -n AniWorld python -m pytest tests/api/test_auth_endpoints.py -v
|
|
```
|
|
|
|
### Run Specific Test
|
|
|
|
```bash
|
|
conda run -n AniWorld python -m pytest tests/api/test_auth_endpoints.py::test_auth_flow_setup_login_status_logout -v
|
|
```
|
|
|
|
### Run Only Asyncio Tests (Skip Trio)
|
|
|
|
```bash
|
|
conda run -n AniWorld python -m pytest tests/api/ -v -k "asyncio or not anyio"
|
|
```
|
|
|
|
### Run with Detailed Output
|
|
|
|
```bash
|
|
conda run -n AniWorld python -m pytest tests/api/ -v --tb=short
|
|
```
|
|
|
|
## Current Test Status
|
|
|
|
### Summary
|
|
|
|
- **Total Tests**: 71
|
|
- **Passing**: 16 (22.5%)
|
|
- **Failing**: 19 (26.8%)
|
|
- **Errors**: 36 (50.7%)
|
|
|
|
### By Category
|
|
|
|
1. **Anime Endpoints**: 11/11 ✅ (100%)
|
|
2. **Auth Endpoints**: 1/2 ✅ (50%) - trio race condition
|
|
3. **Config Endpoints**: 0/18 ❌ (0%) - authentication issues
|
|
4. **Download Endpoints**: 2/36 ⚠️ (5.6%) - fixture dependency issues
|
|
|
|
## Known Issues
|
|
|
|
### 1. Rate Limiting Race Conditions
|
|
|
|
**Symptom**: Tests fail with 429 (Too Many Requests) when run with trio backend
|
|
**Solution**:
|
|
|
|
- Fixed for asyncio by adding `reset_auth_state` fixture
|
|
- Trio still has timing issues with shared state
|
|
- Recommend running tests with asyncio only: `-k "asyncio or not anyio"`
|
|
|
|
### 2. Download Service Fixture Dependencies
|
|
|
|
**Symptom**: `authenticated_client` fixture fails when it depends on `mock_download_service`
|
|
**Error**: `assert 429 == 200` during login
|
|
**Solution**: Need to refactor fixture dependencies to avoid circular authentication issues
|
|
|
|
### 3. Config Endpoint Authentication
|
|
|
|
**Symptom**: Config endpoints return 404 or authentication errors
|
|
**Solution**:
|
|
|
|
- ✅ Added config router to fastapi_app.py
|
|
- ⚠️ Still need to verify authentication requirements and update test fixtures
|
|
|
|
## Improvements Needed
|
|
|
|
### High Priority
|
|
|
|
1. **Fix Download Endpoint Tests**: Resolve fixture dependency issues
|
|
2. **Fix Config Endpoint Tests**: Ensure proper authentication in tests
|
|
3. **Resolve Trio Rate Limiting**: Investigate shared state issues
|
|
|
|
### Medium Priority
|
|
|
|
1. **Add More Edge Cases**: Test boundary conditions and error scenarios
|
|
2. **Improve Test Coverage**: Add tests for WebSocket endpoints
|
|
3. **Performance Tests**: Add tests for high-load scenarios
|
|
|
|
### Low Priority
|
|
|
|
1. **Test Documentation**: Add more inline documentation
|
|
2. **Test Utilities**: Create helper functions for common test patterns
|
|
3. **CI/CD Integration**: Set up automated test runs
|
|
|
|
## Contributing
|
|
|
|
When adding new API endpoint tests:
|
|
|
|
1. **Follow Existing Patterns**: Use the same fixture and assertion patterns
|
|
2. **Test Both Success and Failure**: Include positive and negative test cases
|
|
3. **Use Proper Fixtures**: Leverage existing fixtures for authentication and mocking
|
|
4. **Document Test Purpose**: Add clear docstrings explaining what each test validates
|
|
5. **Clean Up State**: Use fixtures to ensure tests are isolated and don't affect each other
|
|
|
|
## References
|
|
|
|
- [FastAPI Testing Documentation](https://fastapi.tiangolo.com/tutorial/testing/)
|
|
- [Pytest Documentation](https://docs.pytest.org/)
|
|
- [HTTPX AsyncClient Documentation](https://www.python-httpx.org/advanced/)
|
|
- [Project Coding Guidelines](../../.github/copilot-instructions.md)
|