uWSGI Protocol Docker Integration Tests

This directory contains Docker-based integration tests that verify gunicorn's uWSGI binary protocol implementation works correctly with nginx's uwsgi_pass directive.

Architecture

[pytest] --HTTP--> [nginx:8080] --uwsgi_pass--> [gunicorn:8000]

The tests make HTTP requests to nginx, which proxies them to gunicorn using the uWSGI binary protocol. This validates the complete request/response cycle through the protocol.

Prerequisites

  • Docker
  • Docker Compose (v2)
  • Python 3.8+
  • pytest
  • requests

Running Tests

From repository root:

# Run all uWSGI integration tests
pytest tests/docker/uwsgi/ -v

# Run specific test class
pytest tests/docker/uwsgi/ -v -k TestBasicRequests

# Skip Docker tests (for CI environments without Docker)
pytest tests/ -v -m "not docker"

Manual testing:

cd tests/docker/uwsgi

# Start services
docker compose up -d

# Wait for services to be healthy
docker compose ps

# Test endpoints
curl http://localhost:8080/
curl -X POST -d "test body" http://localhost:8080/echo
curl http://localhost:8080/headers
curl "http://localhost:8080/query?foo=bar"
curl http://localhost:8080/environ
curl http://localhost:8080/error/404
curl http://localhost:8080/large > /dev/null  # 1MB response

# View logs
docker compose logs gunicorn
docker compose logs nginx

# Stop services
docker compose down -v

Test Categories

Category Description
TestBasicRequests GET, POST, query strings, large bodies
TestHeaderPreservation Custom headers, Host, Content-Type, User-Agent
TestKeepAlive Multiple requests per connection
TestErrorResponses HTTP error codes (400, 404, 500, etc.)
TestEnvironVariables WSGI environ: REQUEST_METHOD, PATH_INFO, etc.
TestLargeResponses 1MB response body streaming
TestConcurrency Parallel request handling
TestSpecialCases Edge cases: binary data, unicode, long headers

Files

File Purpose
docker-compose.yml Orchestrates nginx + gunicorn containers
Dockerfile.gunicorn Builds gunicorn image with test app
Dockerfile.nginx Builds nginx with uwsgi config
nginx.conf nginx configuration using uwsgi_pass
uwsgi_params Standard uwsgi parameter mappings
app.py Test WSGI application with multiple endpoints
conftest.py pytest fixtures for Docker lifecycle
test_uwsgi_integration.py Test cases

Test App Endpoints

Endpoint Method Description
/ GET Basic hello response
/echo POST Echo request body
/headers GET/POST Return received headers as JSON
/environ GET/POST Return WSGI environ as JSON
/query GET Return query params as JSON
/json POST Parse and echo JSON body
/error/{code} GET Return specified HTTP error
/large GET Return 1MB response

Gunicorn Configuration

The gunicorn container runs with:

gunicorn \
  --protocol uwsgi \
  --uwsgi-allow-from "*" \
  --bind 0.0.0.0:8000 \
  --workers 2 \
  --log-level debug \
  app:application

Key settings:

  • --protocol uwsgi: Enable uWSGI binary protocol
  • --uwsgi-allow-from "*": Accept connections from Docker network IPs

Troubleshooting

Services won't start

Check Docker logs:

docker compose logs

Connection refused

Wait for health checks:

docker compose ps  # Check health status

Tests timing out

Increase STARTUP_TIMEOUT in conftest.py or check if ports are in use:

lsof -i :8080
lsof -i :8000

Rebuild after code changes

docker compose build --no-cache
docker compose up -d