Production-ready Django package for safe and configurable concurrent testing with isolated databases, timing analytics, and concurrency simulation middleware
Project description
Django Concurrent Test
A production-ready Django package for safe and configurable concurrent testing with isolated databases, timing analytics, and concurrency simulation middleware.
🚀 Features
- 🔒 Secure Database Templating: Zero-config parallel testing with isolated database instances
- ⚡ Concurrent Test Execution: ThreadPoolExecutor and asyncio-based concurrency
- 📊 Timing Analytics: Comprehensive test timing analysis and benchmarking
- 🛡️ Concurrency Safety: Middleware for detecting race conditions and state mutations
- 🔧 Runtime Configuration: Dynamic worker scaling and timeout management
- 📈 Performance Monitoring: Connection pooling, resource monitoring, and metrics
- 🎯 DRF Integration: Optional Django REST Framework compatibility
- 📋 JUnit XML Output: CI/CD friendly test reporting
- 🔍 Telemetry-Free: No data collection or external dependencies
📦 Installation
pip install django-concurrent-test
🏃♂️ Quick Start
Basic Usage
# settings.py
INSTALLED_APPS = [
# ... your apps
'django_concurrent_test',
]
# Enable concurrent testing
DJANGO_ENABLE_CONCURRENT = True
Command Line Usage
# Run tests with concurrent execution
pytest --concurrent
# Specify number of workers
pytest --concurrent --workers 4
# Set timeouts
pytest --concurrent --timeout 300 --test-timeout 60
# Export timing data
pytest --concurrent --export-timings results.json
# Import previous timings and export to CSV
pytest --concurrent --import-timings results.json --export-timings-csv results.csv
🔧 Configuration
Environment Variables
# Enable concurrent testing
export DJANGO_ENABLE_CONCURRENT=True
# Configure workers (auto-detected if not set)
export DJANGO_TEST_WORKERS=4
# Set timeouts
export DJANGO_TEST_TIMEOUT=300
export DJANGO_TEST_BENCHMARK=True
Django Settings
# settings.py
CONCURRENT_TEST = {
'ENABLED': True,
'WORKERS': 4, # Auto-detected if not set
'TIMEOUT': 300,
'TEST_TIMEOUT': 60,
'WORKER_TIMEOUT': 120,
'BENCHMARK': True,
'EXPORT_TIMINGS': 'test_timings.json',
}
🛡️ Concurrency Safety
Using assert_concurrent_safety
Test your functions for concurrent execution safety:
from django_concurrent_test.middleware import assert_concurrent_safety
def test_user_creation():
"""Test that user creation is safe for concurrent execution."""
def create_user():
from django.contrib.auth.models import User
return User.objects.create_user(
username=f'user_{time.time()}',
email='test@example.com'
)
# This will run the function concurrently and check for race conditions
assert_concurrent_safety(create_user, max_workers=4, iterations=10)
Using simulate_concurrent_requests
Simulate concurrent request scenarios:
from django_concurrent_test.middleware import simulate_concurrent_requests
from django.test import RequestFactory
def test_api_endpoint_concurrency():
"""Test API endpoint under concurrent load."""
factory = RequestFactory()
def make_request():
request = factory.get('/api/users/')
response = your_view_function(request)
return response.status_code
# Simulate 10 concurrent requests
results = simulate_concurrent_requests(make_request, num_requests=10)
# Check results
successful = [r for r in results if r['status'] == 'success']
assert len(successful) == 10
🔌 Middleware Integration
Auto-Registration
The middleware can be auto-registered during pytest sessions:
# conftest.py
import pytest
from django_concurrent_test.middleware import auto_register_middleware
@pytest.fixture(scope='session', autouse=True)
def setup_concurrent_middleware():
"""Auto-register concurrent testing middleware."""
added_middleware = auto_register_middleware()
if added_middleware:
print(f"Auto-registered middleware: {added_middleware}")
Manual Configuration
Add middleware to your Django settings:
# settings.py
MIDDLEWARE = [
# ... existing middleware
'django_concurrent_test.middleware.ConcurrentSafetyMiddleware',
'django_concurrent_test.middleware.StateMutationMiddleware',
'django_concurrent_test.middleware.ConcurrencySimulationMiddleware',
]
Runtime Configuration
Configure middleware behavior at runtime:
from django_concurrent_test.middleware import (
set_test_override,
concurrent_test_context
)
# Adjust middleware behavior
set_test_override('delay_range', (0.2, 0.8))
set_test_override('probability', 0.5)
# Use context manager for temporary changes
with concurrent_test_context():
# All middleware uses testing configuration
run_tests()
🍰 DRF Integration
Testing DRF Viewsets
from django_concurrent_test.middleware import assert_concurrent_safety
from rest_framework.test import APITestCase
from rest_framework import status
class UserViewSetTest(APITestCase):
def test_concurrent_user_creation(self):
"""Test concurrent user creation via DRF."""
def create_user_via_api():
data = {
'username': f'user_{time.time()}',
'email': 'test@example.com',
'password': 'testpass123'
}
response = self.client.post('/api/users/', data)
return response.status_code
# Test concurrent API calls
assert_concurrent_safety(create_user_via_api, max_workers=4, iterations=5)
Testing DRF Serializers
from django_concurrent_test.middleware import assert_concurrent_safety
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'email']
def test_serializer_concurrency():
"""Test serializer validation under concurrent load."""
def validate_user_data():
data = {
'username': f'user_{time.time()}',
'email': 'test@example.com'
}
serializer = UserSerializer(data=data)
return serializer.is_valid()
assert_concurrent_safety(validate_user_data, max_workers=4, iterations=10)
📊 Timing Analytics
Export and Import Timing Data
from django_concurrent_test.timing_utils import (
load_timings,
save_timings,
filter_timings,
export_timings_to_csv
)
# Load timing data
timings = load_timings('test_timings.json')
# Filter slow tests
slow_tests = filter_timings(timings, min_duration=5.0)
# Export to CSV
export_timings_to_csv(slow_tests, 'slow_tests.csv')
# Analyze timing data
for test_name, timing_data in slow_tests.items():
print(f"{test_name}: {timing_data['duration']:.2f}s")
Benchmark Analysis
from django_concurrent_test.timing_utils import get_slowest_tests, get_fastest_tests
# Get performance insights
slowest = get_slowest_tests(timings, count=5)
fastest = get_fastest_tests(timings, count=5)
print("Slowest tests:")
for test_name, duration in slowest:
print(f" {test_name}: {duration:.2f}s")
print("Fastest tests:")
for test_name, duration in fastest:
print(f" {test_name}: {duration:.2f}s")
🔒 Security Features
Environment Validation
from django_concurrent_test.security import (
security_context,
get_safe_worker_count,
validate_environment
)
# Validate environment before testing
with security_context():
worker_count = get_safe_worker_count()
print(f"Safe worker count: {worker_count}")
# Manual validation
validate_environment()
Resource Monitoring
from django_concurrent_test.security import check_system_resources
# Check system resources
resources = check_system_resources()
print(f"Available memory: {resources['memory_available_gb']:.1f}GB")
print(f"CPU cores: {resources['cpu_count']}")
print(f"Safe worker count: {resources['safe_worker_count']}")
🧪 Advanced Testing
Custom Test Runner
from django_concurrent_test.runner import ConcurrentTestRunner
class CustomConcurrentRunner(ConcurrentTestRunner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.custom_metrics = {}
def run_tests(self, test_labels, **kwargs):
# Custom pre-test setup
self.setup_custom_environment()
# Run tests with concurrent execution
failures = super().run_tests(test_labels, **kwargs)
# Custom post-test cleanup
self.cleanup_custom_environment()
return failures
Database Isolation Testing
from django_concurrent_test.db import verify_database_isolation
def test_database_isolation():
"""Verify that worker databases are properly isolated."""
# Run concurrent tests
runner = ConcurrentTestRunner()
failures = runner.run_tests(['myapp.tests'])
# Verify isolation
worker_connections = runner.get_worker_connections()
isolation_verified = verify_database_isolation(worker_connections)
assert isolation_verified, "Database isolation verification failed"
📈 Performance Monitoring
Connection Pool Statistics
from django_concurrent_test.db import get_connection_pool_stats
# Get connection pool metrics
stats = get_connection_pool_stats()
print(f"Active connections: {stats.get('active', 0)}")
print(f"Pooled connections: {stats.get('pooled', 0)}")
print(f"Connection hits: {stats.get('hits', 0)}")
print(f"Connection misses: {stats.get('misses', 0)}")
Memory-Based Scaling
The package automatically scales worker count based on available memory:
from django_concurrent_test.runner import ConcurrentTestRunner
# Memory-based scaling is automatic
runner = ConcurrentTestRunner()
# Worker count will be calculated based on available memory
🚨 Error Handling
Timeout Management
from django_concurrent_test.exceptions import TestTimeoutException
def test_with_timeout():
"""Test with custom timeout handling."""
try:
# Run test with timeout
result = run_test_with_timeout(test_function, timeout=30)
assert result is not None
except TestTimeoutException:
pytest.fail("Test timed out")
Database Error Recovery
from django_concurrent_test.db import wait_for_database_ready
def test_database_recovery():
"""Test database connection recovery."""
# Wait for database to be ready
ready = wait_for_database_ready('test_db', timeout=30)
assert ready, "Database not ready within timeout"
🔧 Development
Running Tests
# Run package tests
pytest tests/
# Run with coverage
pytest --cov=django_concurrent_test tests/
# Run with concurrent execution
pytest --concurrent tests/
Building Documentation
# Build package
python -m build
# Upload to PyPI
twine upload dist/*
📋 Requirements
- Python 3.9+
- Django 3.2+
- PostgreSQL 10+ or MySQL 5.7+ (for production features)
- SQLite (for development)
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
📞 Contact
- Email: ranaehtashamali1@gmail.com
- Phone: +923224712517
- GitHub: @RanaEhtashamAli
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Django team for the excellent testing framework
- PostgreSQL and MySQL communities for database support
- All contributors who have helped improve this package
📞 Support
- Issues: GitHub Issues
- Documentation: Read the Docs
- Discussions: GitHub Discussions
- Email: ranaehtashamali1@gmail.com
- Phone: +923224712517
Made with ❤️ for the Django community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_concurrent_test-1.0.0.tar.gz.
File metadata
- Download URL: django_concurrent_test-1.0.0.tar.gz
- Upload date:
- Size: 74.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c60d472d98cc6fa00c857ebc19925bb9f41a467bdddd1aad300e762284fc0ee4
|
|
| MD5 |
64f3018c73fa4a9b616e739177b98387
|
|
| BLAKE2b-256 |
072b2183bf69dd7b72319980cea9cbff412622039458061d1fdb93fe5917142e
|
File details
Details for the file django_concurrent_test-1.0.0-py3-none-any.whl.
File metadata
- Download URL: django_concurrent_test-1.0.0-py3-none-any.whl
- Upload date:
- Size: 40.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cd969e2164b92b25c4aec6c2f4f14b0210b923de54484e0c0584748a52caa49
|
|
| MD5 |
ab164c997e6c0c60f1b7b7d1cd677de1
|
|
| BLAKE2b-256 |
0076fbc0cdb7c71dd52334308a9b2af5682f9440ae61c06f95e41d31259ec95f
|