Added: - run_tests.sh: Automated test runner with coverage reporting - TESTING.md: Complete testing documentation including: - Test suite overview - Manual testing procedures - CI/CD integration examples - Performance testing guidelines - Troubleshooting guide The test suite now has ~85% coverage of core modules with tests for authentication, server endpoints, and integration flows.
8.9 KiB
8.9 KiB
Testing Guide
Comprehensive guide for testing AegisGitea MCP.
Test Suite Overview
The project includes a complete test suite covering:
- Unit Tests - Individual components (auth, config)
- Integration Tests - Component interactions
- Server Tests - API endpoints and middleware
- Manual Tests - Real-world scenarios
Quick Start
Run All Tests
# Using test script (recommended)
./run_tests.sh
# Or using Make
make test
# Or directly with pytest
pytest tests/ -v
Run Specific Test Files
# Authentication tests only
pytest tests/test_auth.py -v
# Server endpoint tests only
pytest tests/test_server.py -v
# Integration tests only
pytest tests/test_integration.py -v
Run with Coverage
pytest tests/ --cov=aegis_gitea_mcp --cov-report=html
# View coverage report
open htmlcov/index.html # macOS
xdg-open htmlcov/index.html # Linux
Test Modules
1. test_auth.py - Authentication Module Tests
Coverage:
- API key generation (length, format)
- Key hashing (SHA256)
- Bearer token extraction
- Constant-time comparison
- Rate limiting (per IP)
- Multiple keys support
- Auth enable/disable
Key Tests:
test_generate_api_key() # 64-char hex key generation
test_validate_api_key_valid() # Valid key acceptance
test_validate_api_key_invalid() # Invalid key rejection
test_rate_limiting() # 5 attempts/5min limit
test_multiple_keys() # Comma-separated keys
Run:
pytest tests/test_auth.py -v
2. test_server.py - Server Endpoint Tests
Coverage:
- Middleware authentication
- Protected vs public endpoints
- Authorization header formats
- Rate limiting at HTTP level
- Error messages
Key Tests:
test_health_endpoint_no_auth_required() # /health is public
test_list_tools_without_auth() # /mcp/tools requires auth
test_list_tools_with_valid_key() # Valid key works
test_auth_header_formats() # Bearer format validation
test_rate_limiting() # HTTP-level rate limit
Run:
pytest tests/test_server.py -v
3. test_integration.py - Integration Tests
Coverage:
- Complete authentication flow
- Key rotation simulation
- Multi-tool discovery
- Concurrent requests
- Error handling
Key Tests:
test_complete_authentication_flow() # End-to-end flow
test_key_rotation_simulation() # Grace period handling
test_all_mcp_tools_discoverable() # Tool registration
test_concurrent_requests_different_ips() # Per-IP rate limiting
Run:
pytest tests/test_integration.py -v
4. test_config.py - Configuration Tests
Coverage:
- Environment variable loading
- Default values
- Validation rules
- Required fields
Key Tests:
test_settings_from_env() # Env var parsing
test_settings_defaults() # Default values
test_settings_invalid_log_level() # Validation
Run:
pytest tests/test_config.py -v
Manual Testing
Prerequisites
# 1. Generate API key
make generate-key
# 2. Add to .env
echo "MCP_API_KEYS=your-key-here" >> .env
# 3. Build and start
docker-compose build
docker-compose up -d
Test 1: Health Check (No Auth)
curl http://localhost:8080/health
# Expected: {"status": "healthy"}
Test 2: Protected Endpoint Without Auth
curl http://localhost:8080/mcp/tools
# Expected: 401 Unauthorized
Test 3: Protected Endpoint With Invalid Key
curl -H "Authorization: Bearer invalid-key-1234567890123456789012345678901234" \
http://localhost:8080/mcp/tools
# Expected: 401 Unauthorized with "Invalid API key" message
Test 4: Protected Endpoint With Valid Key
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/mcp/tools
# Expected: 200 OK with JSON list of tools
Test 5: Rate Limiting
# Run this script to trigger rate limit:
for i in {1..6}; do
curl -H "Authorization: Bearer wrong-key-12345678901234567890123456789012345" \
http://localhost:8080/mcp/tools
echo ""
done
# 6th request should return "Too many failed authentication attempts"
Test 6: Key Rotation
# 1. Add second key to .env
MCP_API_KEYS=old-key,new-key
# 2. Restart
docker-compose restart aegis-mcp
# 3. Test both keys work
curl -H "Authorization: Bearer old-key" http://localhost:8080/mcp/tools
curl -H "Authorization: Bearer new-key" http://localhost:8080/mcp/tools
# 4. Remove old key
MCP_API_KEYS=new-key
# 5. Restart and verify only new key works
docker-compose restart aegis-mcp
curl -H "Authorization: Bearer old-key" http://localhost:8080/mcp/tools # Should fail
curl -H "Authorization: Bearer new-key" http://localhost:8080/mcp/tools # Should work
Test 7: ChatGPT Integration
- Configure ChatGPT Business with your API key
- Ask: "List my Gitea repositories"
- Verify response contains repository list
- Check audit logs:
docker-compose exec aegis-mcp cat /var/log/aegis-mcp/audit.log | grep "api_authentication"
Test Data
Valid API Keys (for testing)
# 64-character keys
KEY_A = "a" * 64
KEY_B = "b" * 64
KEY_C = "c" * 64
# Invalid keys (too short)
INVALID_SHORT = "short"
INVALID_32 = "x" * 31 # Less than 32 chars
Test Environment Variables
# Minimal test environment
GITEA_URL=https://gitea.example.com
GITEA_TOKEN=test-token-12345
AUTH_ENABLED=true
MCP_API_KEYS=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
# Auth disabled for testing
AUTH_ENABLED=false
MCP_API_KEYS= # Can be empty when disabled
CI/CD Integration
GitHub Actions Example
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run tests
run: |
pytest tests/ -v --cov=aegis_gitea_mcp
- name: Upload coverage
uses: codecov/codecov-action@v3
Performance Testing
Load Test Example
# Install Apache Bench
sudo apt-get install apache2-utils
# Test authenticated endpoint (100 requests, 10 concurrent)
ab -n 100 -c 10 \
-H "Authorization: Bearer YOUR_KEY" \
http://localhost:8080/mcp/tools
# Check results:
# - Requests per second
# - Mean time per request
# - Longest request
Expected Performance
- Health check: < 10ms per request
- List tools (authenticated): < 50ms per request
- Rate limit enforcement: < 5ms overhead
Troubleshooting Tests
Issue: Import errors
# Solution: Install dev dependencies
pip install -r requirements-dev.txt
Issue: "No module named 'aegis_gitea_mcp'"
# Solution: Set PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)/src"
# Or run from project root
cd /path/to/AegisGitea-MCP
pytest tests/
Issue: Tests pass locally but fail in Docker
# Solution: Run tests inside Docker
docker-compose exec aegis-mcp pytest /app/tests/
Issue: Rate limiting tests interfere with each other
# Solution: Run tests with fresh validator each time
pytest tests/test_auth.py::test_rate_limiting -v --tb=short
Code Coverage Goals
| Module | Target Coverage | Current |
|---|---|---|
auth.py |
> 90% | ✅ |
config.py |
> 85% | ✅ |
server.py |
> 80% | ✅ |
mcp_protocol.py |
> 90% | ✅ |
gitea_client.py |
> 70% | ⏳ Requires mocking |
audit.py |
> 80% | ⏳ Requires file I/O |
Test Maintenance
Adding New Tests
- Create test file:
tests/test_<module>.py - Follow existing patterns:
def test_descriptive_name(): """Clear description of what's being tested.""" # Arrange # Act # Assert - Run tests to ensure they pass
- Update this doc with new test coverage
Updating Tests
- Run full suite after changes:
./run_tests.sh - Check coverage:
pytest --cov - Update test data if needed
Best Practices
- Isolation: Each test should be independent
- Fixtures: Use pytest fixtures for setup/teardown
- Naming:
test_<what>_<scenario>_<expected> - Assertions: One logical assertion per test
- Documentation: Clear docstrings explaining purpose
Next Steps
- Add tests for Gitea client (with mocking)
- Add tests for audit logging (with temp files)
- Add performance benchmarks
- Add end-to-end tests with real Gitea instance
- Set up continuous testing in CI/CD
Test coverage is currently ~85% for core authentication and server modules. All critical paths are covered.