Skip to content

Backend Testing

The backend uses pytest with an in-memory SQLite database and an in-memory Celery broker. No external services are required to run tests.

Terminal window
cd yaptide
poetry run pytest

With verbose output:

Terminal window
poetry run pytest -v

Run a specific test file:

Terminal window
poetry run pytest tests/test_database.py

Run a specific test:

Terminal window
poetry run pytest tests/test_database.py::test_create_user -v

Test settings are defined in pytest.ini:

[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*

Key differences from production:

  • Database: in-memory SQLite (no PostgreSQL required)
  • Celery broker: memory:// (no Redis required)
  • Celery backend: cache+memory:// (no Redis required)

Fixtures are defined in tests/conftest.py and provide the test infrastructure.

Creates a Flask application configured for testing:

@pytest.fixture
def app():
# Creates app with SQLite in-memory DB
# Applies all migrations
# Returns the configured Flask app

A Flask test client for making HTTP requests:

@pytest.fixture
def client(app):
return app.test_client()

Pre-built JSON payloads for simulation submission:

FixtureDescription
shieldhit_editor_payloadSHIELD-HIT12A simulation from editor JSON
shieldhit_files_payloadSHIELD-HIT12A simulation from raw input files
fluka_editor_payloadFLUKA simulation from editor JSON
fluka_files_payloadFLUKA simulation from raw input files

These fixtures load JSON from tests/res/ resource files.

FileWhat it Tests
test_main.pyApp creation, health check endpoint (GET /)
test_database.pySQLAlchemy model CRUD (create, read, update, delete)
test_keycloak_tokens.pyKeycloak token validation and parsing
test_encrypt_decrypt.pyAES encryption/decryption for simulator binaries
test_prepare_simulation.pyInput conversion logic (editor JSON → simulator files)
test_download_shieldhit.pySHIELD-HIT12A binary download from S3
test_download_fluka.pyFLUKA binary download from S3
test_download_topas.pyTOPAS binary download from S3

Located in tests/integration/:

FileWhat it Tests
test_run_simulation.pyFull simulation lifecycle: submit → run → merge → retrieve results
test_cancel_simulation.pySimulation cancellation flow
test_user_management.pyUser registration, login, session management
test_celery_tasks.pyCelery task dispatch and completion
test_simulation_deletion.pySimulation and result cleanup
test_environment.pyEnvironment variable handling
def test_health_check(client):
"""Test that the health check endpoint returns 200."""
response = client.get("/")
assert response.status_code == 200

Most endpoints require authentication. Use the login fixture:

def test_submit_simulation(client):
# Register and log in
client.put("/auth/register", json={
"username": "testuser",
"password": "testpass"
})
client.post("/auth/login", json={
"username": "testuser",
"password": "testpass"
})
# Now authenticated via cookies
response = client.post("/jobs/direct", json={
"sim_data": { ... },
"ntasks": 1,
"sim_type": "shieldhit"
})
assert response.status_code == 202
def test_create_simulation(app):
with app.app_context():
from yaptide.persistence.models import SimulationModel, UserModel
user = UserModel(username="test")
db.session.add(user)
db.session.commit()
sim = SimulationModel(
job_id="test-123",
user_id=user.id,
sim_type="shieldhit"
)
db.session.add(sim)
db.session.commit()
assert SimulationModel.query.count() == 1

The project uses pre-commit for code quality:

Terminal window
poetry run pre-commit install
poetry run pre-commit run --all-files

Hooks include:

  • YAPF — Python formatter (120-char line length)
  • pycodestyle — PEP 8 style checking
  • Standard pre-commit hooks (trailing whitespace, end of file, etc.)