The CI pipeline includes comprehensive end-to-end (E2E) tests that validate the Docker container against the OpenAPI specification. These tests ensure that the deployed service correctly implements the API contract.
The E2E tests use Schemathesis, a property-based testing tool specifically designed for testing APIs against OpenAPI/Swagger specifications.
- Automatic test generation: Generates test cases from the OpenAPI spec
- Property-based testing: Uses Hypothesis to generate edge cases automatically
- OpenAPI-native: Understands OpenAPI schemas and validates responses
- Comprehensive validation: Checks response schemas, status codes, headers, etc.
The E2E test job (e2e-test) includes:
Tests public endpoints without authentication:
GET /health- Health check endpointGET /- Root SpaceAPI endpointGET /api/space- SpaceAPI data endpoint
Validates:
- Response schemas match OpenAPI spec
- Status codes are correct
- Content types are correct
- Response structure is valid
Tests protected endpoints with valid API key:
POST /api/space/state- Update space statePOST /api/space/people- Update people countPOST /api/space/event- Add event
Validates:
- Authentication works correctly
- Request/response schemas match spec
- All documented fields are handled properly
Explicit tests for authentication error cases:
- Missing API key (expects 401)
- Invalid API key (expects 401)
Ensures security is properly implemented.
Tests the complete flow of API operations:
- Update space state to open
- Update people count
- Create check-in event
- Verify all updates are reflected in GET responses
Explicit validation that POST operations actually persist data:
- State changes: Verifies
state.openis set totrueafter POST - State message: Verifies
state.messagecontains the update message - People count: Verifies
sensors.people_now_present[0].valuereflects the updated count - Timestamps: Verifies
state.lastchangeis recent (updated within last 5 minutes)
This step performs a GET request to /api/space and uses JSON parsing to verify the exact structure and values, ensuring complete end-to-end data persistence.
The tests use specific validation checks focused on practical API conformance:
Enabled Checks:
- ✅
status_code_conformance- Validates HTTP status codes match the OpenAPI spec - ✅
content_type_conformance- Validates response Content-Type headers - ✅
response_schema_conformance- Validates response bodies match schemas - ✅
response_headers_conformance- Validates response headers
Not Included:
- ❌
negative_data_rejection- Malformed request testing (handled by HTTP server layer) - ❌ Coverage phase tests - Unsupported HTTP method checks (TRACE, OPTIONS edge cases)
- ❌
not_a_server_error- 5xx error detection (not applicable for simple APIs)
This focused approach ensures:
- 🎯 Validation of all documented API functionality
- 🎯 Schema compliance for requests and responses
- 🎯 Correct authentication and authorization
- 🎯 Fast test execution without irrelevant edge cases
HTTP-level edge cases (like TRACE method handling) are not relevant to typical API usage and are better handled at the reverse proxy or HTTP server level.
# Install Schemathesis
pip install schemathesis requests
# Ensure you have Docker with Compose V2 installed# 1. Prepare test configuration
cp spaceapi.json.example spaceapi.json
# 2. Start the service
export SPACEAPI_AUTH_KEY="test-api-key"
docker compose up -d
# 3. Wait for service to be healthy
until docker compose ps | grep -q "healthy"; do sleep 2; done
# 4. Run OpenAPI conformance tests (public endpoints)
schemathesis run openapi.yaml \
--url http://localhost:8089 \
--checks status_code_conformance,content_type_conformance,response_schema_conformance,response_headers_conformance \
--workers 4 \
--include-path-regex "^/(health|api/space)$" \
--exclude-path-regex ".*/(state|people|event)$"
# 5. Run OpenAPI conformance tests (protected endpoints)
schemathesis run openapi.yaml \
--url http://localhost:8089 \
--header "X-API-Key: test-api-key" \
--checks status_code_conformance,content_type_conformance,response_schema_conformance,response_headers_conformance \
--workers 4 \
--include-path-regex ".*/(state|people|event)$"
# 6. Test authentication (manual curl tests)
# Missing API key (should return 401)
curl -X POST http://localhost:8089/api/space/state \
-H "Content-Type: application/json" \
-d '{"open": true}'
# Invalid API key (should return 401)
curl -X POST http://localhost:8089/api/space/state \
-H "Content-Type: application/json" \
-H "X-API-Key: invalid-key" \
-d '{"open": true}'
# 7. Test successful operations
# Update state
curl -X POST http://localhost:8089/api/space/state \
-H "Content-Type: application/json" \
-H "X-API-Key: test-api-key" \
-d '{"open": true, "message": "Test", "trigger_person": "Tester"}'
# Update people count
curl -X POST http://localhost:8089/api/space/people \
-H "Content-Type: application/json" \
-H "X-API-Key: test-api-key" \
-d '{"value": 5, "location": "Main Space"}'
# Add event
curl -X POST http://localhost:8089/api/space/event \
-H "Content-Type: application/json" \
-H "X-API-Key: test-api-key" \
-d '{"name": "Tester", "type": "check-in", "extra": "Testing"}'
# 8. Verify data persistence with detailed checks
echo "Verifying all data was persisted correctly..."
response=$(curl -s http://localhost:8089/api/space)
# Pretty print the response
echo "$response" | jq .
# Check specific values
echo ""
echo "Checking state.open:"
echo "$response" | jq '.state.open'
echo "Checking state.message:"
echo "$response" | jq '.state.message'
echo "Checking people count:"
echo "$response" | jq '.sensors.people_now_present[0].value'
echo "Checking lastchange timestamp:"
echo "$response" | jq '.state.lastchange'
# 9. Cleanup
docker compose down -vThe e2e-test job runs:
- In parallel with
docker-build(after basic tests pass) - Before deployment to catch issues early
- On all branches to validate PRs
test, build, lint, license-check, openapi-validate
↓
e2e-test (runs in parallel with docker-build)
Check if the service started correctly:
docker compose logs
docker compose ps- Check OpenAPI spec matches implementation
- Review the Schemathesis output for details
- Test endpoint manually with curl
- Check authentication header is passed correctly
The healthcheck waits up to 60 seconds. If it fails:
- Check
spaceapi.jsonconfiguration is valid - Check Docker logs for startup errors
- Verify the
/healthendpoint is accessible
Create a new step in the e2e-test job:
- name: Test custom scenario
run: |
# Your custom test logic here
response=$(curl -s http://localhost:8089/your-endpoint)
# Validate responseModify Schemathesis checks:
schemathesis run openapi.yaml \
--url http://localhost:8089 \
--checks all \
--hypothesis-max-examples 50 # More test casesInstall and use locust or k6 for load testing:
- name: Load test
run: |
pip install locust
locust -f load_test.py --headless -u 10 -r 1 -t 30s