Fullstack Integration Testing
This document describes the fullstack testing infrastructure for genro-mail-proxy. These tests validate end-to-end functionality using Docker containers.
Overview
The fullstack test suite validates the complete mail proxy functionality:
End-to-end message flow from API to SMTP delivery
S3-compatible storage integration (Minio)
IMAP bounce injection and detection
Delivery reports via HTTP callbacks
Test Structure
Tests mirror the source code structure:
tests/
├── core/mail_proxy/ # Core functionality tests
│ ├── entities/ # Entity table and endpoint tests
│ │ ├── account/
│ │ ├── tenant/
│ │ ├── message/
│ │ ├── instance/
│ │ └── ...
│ ├── interface/ # API and CLI tests
│ ├── smtp/ # SMTP sender, pool, retry tests
│ └── reporting/ # Client reporter tests
│
├── enterprise/mail_proxy/ # Enterprise features tests
│ ├── attachments/ # Large file storage tests
│ ├── bounce/ # Bounce parser and receiver
│ ├── pec/ # PEC parser and receiver
│ ├── imap/ # IMAP client tests
│ └── entities/ # EE entity extensions
│
├── sql/ # Database adapter tests
│
└── fullstack/ # Docker-based integration tests
├── conftest.py # Shared fixtures
├── docker-compose.yml # Service definitions
├── Dockerfile.proxy # Proxy container
├── imap_injector.py # Bounce simulation
└── test_smtp_delivery.py # SMTP delivery tests
Quick Start
Prerequisites
Docker and Docker Compose
Python 3.10+ with pytest
At least 4GB RAM
Running Tests
# Start Docker services
cd tests/fullstack
docker compose up -d
# Wait for services to be healthy
docker compose ps
# Run all tests (from project root)
pytest tests/ -v
# Run only fullstack tests
pytest tests/fullstack/ -v
# Run unit tests (no Docker required)
pytest tests/core/ tests/enterprise/ tests/sql/ -v
# Stop services when done
docker compose down
Infrastructure Services
The test infrastructure uses Docker Compose to orchestrate services.
Mailpit (SMTP/IMAP)
Image |
|
SMTP Port |
1025 |
IMAP Port |
1143 (for bounce injection) |
Web UI |
Mailpit provides a combined SMTP sink and IMAP server for testing. The Web UI allows visual inspection of captured emails.
Minio (S3-Compatible Storage)
Image |
|
S3 API Port |
9000 |
Console Port |
9001 |
Credentials |
|
Test Bucket |
|
S3-compatible storage for large file attachment tests. Console UI available at http://localhost:9001.
Mail Proxy
Build |
|
API Port |
8000 |
Health Check |
The proxy container connects to Mailpit for SMTP delivery and Minio for S3 storage.
Test Fixtures
Key fixtures available in tests/fullstack/conftest.py:
imap_injectorIMAP client for injecting bounce messages into Mailpit.
mailpit_apiHTTP client for the Mailpit REST API (message retrieval, deletion).
minio_configS3 configuration dictionary for storage tests.
minio_availableBoolean indicating if Minio is accessible.
Bounce Injection
The IMAPBounceInjector class simulates bounce messages by injecting
RFC 3464 DSN (Delivery Status Notification) messages directly into the
IMAP mailbox.
Example usage in tests:
async def test_bounce_detection(imap_injector, mailpit_api):
# Inject a bounce message
bounce_msg = create_dsn_bounce(
original_message_id="<msg-123@example.com>",
bounce_type="hard",
diagnostic="550 User unknown"
)
await imap_injector.inject(bounce_msg)
# Verify bounce was processed
# ...
CSV-Driven Tests
Tests can load message scenarios from CSV files in tests/fullstack/fixtures/.
CSV columns:
id: Message identifierfrom: Sender addressto: Recipient addresssubject: Email subjectbody: Email bodyexpected_status: Expected final status (sent,bounced,error)simulate_bounce: Bounce type to inject (hard,soft, or empty)
Environment Variables
The proxy container accepts these environment variables:
Variable |
Default |
Description |
|---|---|---|
|
|
SQLite database path |
|
|
SMTP server hostname |
|
|
SMTP server port |
|
|
IMAP server for bounce polling |
|
|
IMAP server port |
|
|
S3 storage URL |
|
|
S3 endpoint (Minio) |
|
|
S3 access key |
|
|
S3 secret key |
Test Markers
Tests use pytest markers for selective execution:
Marker |
Description |
|---|---|
|
Docker-based integration tests |
|
Async tests (auto-applied via conftest) |
|
Tests requiring network access |
|
Database integration tests |
Usage examples:
# Run fullstack tests only
pytest tests/fullstack/ -m fullstack -v
# Exclude network tests
pytest tests/ -m "not network" -v
Troubleshooting
Services Not Starting
# Check service status
docker compose ps
# Check specific service logs
docker compose logs mailpit
docker compose logs proxy
docker compose logs minio
Tests Skipped
If tests are skipped with “Docker services not available”:
# Ensure services are running
docker compose up -d
# Verify health checks pass
docker compose ps
Minio Not Accessible
# Check minio-setup completed
docker compose logs minio-setup
# Should show bucket creation message
Rebuild After Code Changes
# Rebuild proxy container
docker compose build proxy
docker compose up -d
Writing New Tests
Place tests in the appropriate directory matching source structure
Use
pytest.mark.asynciofor async tests:import pytest @pytest.mark.asyncio async def test_my_feature(): # Test implementation
Use fixtures from
conftest.py:async def test_smtp_delivery(mailpit_api): # Clear previous messages await mailpit_api.delete_all() # ... send message ... # Verify delivery messages = await mailpit_api.get_messages() assert len(messages) == 1
See Also
tests/fullstack/README.md- Quick reference for running testsContributing - Development guidelines