Add parallel test execution with pytest-xdist
Implements per-worker database isolation for parallel test runs: - Add pytest-xdist and pytest-cov to test dependencies - Configure Makefile to run tests with -n auto flag - Update test.ini to use environment variable for database path - Create conftest.py with per-worker database isolation - Enable SQLite WAL mode for better concurrency - Auto-cleanup test databases after completion Expected performance improvement similar to make_post_sell (~16x speedup). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
06ba106795
commit
a49446cfef
4 changed files with 83 additions and 5 deletions
5
Makefile
5
Makefile
|
|
@ -113,11 +113,10 @@ activate:
|
|||
@echo "To activate the virtual environment, run:"
|
||||
@echo " source $(VENV_DIR)/bin/activate"
|
||||
|
||||
# Run the test suite (installs test dependencies if needed)
|
||||
# Run the test suite (installs test dependencies if needed)
|
||||
test: install-source-dev-and-test
|
||||
@echo "Running tests..."
|
||||
$(VENV_DIR)/bin/py.test
|
||||
@echo "Running tests in parallel..."
|
||||
$(VENV_DIR)/bin/py.test -n auto
|
||||
|
||||
# Start a simple HTTP server (for serving static files like index.html)
|
||||
http: venv
|
||||
|
|
|
|||
77
remarkbox/tests/conftest.py
Normal file
77
remarkbox/tests/conftest.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
"""
|
||||
Pytest configuration for parallel test execution.
|
||||
|
||||
This module configures pytest-xdist to use isolated databases per worker
|
||||
to avoid SQLite locking issues during parallel test runs.
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
Configure test database isolation for parallel execution.
|
||||
|
||||
Each pytest-xdist worker gets its own database file to prevent
|
||||
SQLite locking conflicts. WAL mode is enabled for better concurrency.
|
||||
"""
|
||||
# Get worker ID (e.g., "gw0", "gw1", etc.) for pytest-xdist
|
||||
worker_id = os.environ.get("PYTEST_XDIST_WORKER", "master")
|
||||
|
||||
# Set unique database path for this worker
|
||||
test_db_path = f"test-remarkbox_{worker_id}.sqlite"
|
||||
os.environ["TEST_DATABASE_PATH"] = test_db_path
|
||||
|
||||
# Store for cleanup
|
||||
config.test_db_path = test_db_path
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
"""Clean up test database after all tests complete."""
|
||||
if hasattr(config, "test_db_path"):
|
||||
db_path = config.test_db_path
|
||||
if os.path.exists(db_path):
|
||||
try:
|
||||
os.remove(db_path)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not remove test database {db_path}: {e}")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def db_engine(request):
|
||||
"""
|
||||
Create a SQLAlchemy engine with WAL mode enabled for concurrency.
|
||||
|
||||
WAL (Write-Ahead Logging) mode allows multiple readers while a writer
|
||||
is active, improving parallel test performance.
|
||||
"""
|
||||
from sqlalchemy import create_engine, event
|
||||
|
||||
# Use worker-specific database
|
||||
worker_id = os.environ.get("PYTEST_XDIST_WORKER", "master")
|
||||
db_path = f"test-remarkbox_{worker_id}.sqlite"
|
||||
db_url = f"sqlite:///{db_path}"
|
||||
|
||||
engine = create_engine(
|
||||
db_url,
|
||||
echo=False,
|
||||
# Important: Use NullPool to avoid connection sharing issues
|
||||
poolclass=__import__("sqlalchemy.pool", fromlist=["NullPool"]).NullPool,
|
||||
)
|
||||
|
||||
# Enable WAL mode for better concurrency
|
||||
@event.listens_for(engine, "connect")
|
||||
def set_sqlite_pragma(dbapi_conn, connection_record):
|
||||
cursor = dbapi_conn.cursor()
|
||||
# Enable WAL mode for concurrent access
|
||||
cursor.execute("PRAGMA journal_mode=WAL")
|
||||
# Increase cache size for better performance
|
||||
cursor.execute("PRAGMA cache_size=-64000") # 64MB
|
||||
# Enable foreign keys
|
||||
cursor.execute("PRAGMA foreign_keys=ON")
|
||||
cursor.close()
|
||||
|
||||
yield engine
|
||||
|
||||
# Cleanup
|
||||
engine.dispose()
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
# testing.
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-xdist # Parallel test execution
|
||||
nose
|
||||
mock
|
||||
webtest
|
||||
|
|
|
|||
4
test.ini
4
test.ini
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
[alembic]
|
||||
script_location = remarkbox:scripts/alembic
|
||||
sqlalchemy.url = sqlite:///%(here)s/test-remarkbox.sqlite
|
||||
sqlalchemy.url = sqlite:///%(here)s/${TEST_DATABASE_PATH:-test-remarkbox.sqlite}
|
||||
|
||||
[app:main]
|
||||
use = egg:remarkbox
|
||||
|
||||
sqlalchemy.url = sqlite:///%(here)s/test-remarkbox.sqlite
|
||||
sqlalchemy.url = sqlite:///%(here)s/${TEST_DATABASE_PATH:-test-remarkbox.sqlite}
|
||||
#sqlalchemy.url = postgres://localhost/remarkbox_test
|
||||
|
||||
###
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue