The Python tests of Cluster ERP live in tests/ and run with pytest. This page lists the configuration, the command CI uses, the files grouped by area, and the rules for tests that need a live server or database. Browser tests are a separate suite; see e2e battery.
Scope and source¶
- Defined in:
tests/test_*.pyand[tool.pytest.ini_options]inpyproject.toml. - Run by: the CI job
test(.github/workflows/ci.yml:124). - Count: 106 test files, counted with
ls tests/test_*.py. The folder has noconftest.py, and the repository root has none either (searched withls).
Configuration¶
| Name | Value | Meaning | Source |
|---|---|---|---|
asyncio_mode |
auto |
async def tests run without a marker |
pyproject.toml:152 |
testpaths |
tests |
pytest collects only tests/ |
pyproject.toml:153 |
| pytest | >=8.0.0 |
Version floor in the dev extra |
pyproject.toml:81 |
| pytest-asyncio | >=0.24.0 |
Version floor in the dev extra |
pyproject.toml:82 |
Running the tests¶
CI runs the suite after it has applied all migrations to an empty PostgreSQL 16 database (.github/workflows/ci.yml:113, .github/workflows/ci.yml:124):
python -m pytest -q --no-header -p no:cacheprovider
The same job sets CLUSTER_SKIP_LIVE_TESTS to 1 (.github/workflows/ci.yml:99). The workflow comment states why: the live guards need a booted server, and CI waives them so that the waiver is visible (.github/workflows/ci.yml:17-20).
Live tests¶
A live test needs a running server or a reachable test database. Eight files read CLUSTER_SKIP_LIVE_TESTS (counted with grep -l). They use two patterns.
| Pattern | Behaviour | Files | Source |
|---|---|---|---|
| Skip the whole module when waived | A module-level skipif skips every test when the variable is 1 |
test_cal03_owner_calendars_live.py, test_calendar_owner_inherits_group_live.py, test_change_history_tables_live.py, test_deactivation_sweep_live.py, test_demo_data_live.py, test_login_budget_live.py |
tests/test_demo_data_live.py:24-27, tests/test_cal03_owner_calendars_live.py:22-24 |
| Fail unless waived | Without a server the test fails; only the variable turns the failure into a skip | test_readiness_contract.py, test_search_contract.py |
tests/test_readiness_contract.py:37-44, tests/test_search_contract.py:162-171 |
The second pattern exists because "a silently skipped guard is indistinguishable from a passing one" (tests/test_readiness_contract.py:12-14). The live HTTP tests read the server address from CLUSTER_E2E_BASE, the same variable the browser battery uses (tests/test_readiness_contract.py:27).
Other tests depend on their environment without that variable:
| Condition | Behaviour | Source |
|---|---|---|
| No reachable database | The partial-index and foreign-key index checks skip | tests/test_live_row_uniqueness.py:88-89, tests/test_fk_indexes.py:97-98 |
No bash on the machine |
The node script tests skip | tests/test_bootstrap_node_script.py:35, tests/test_pg_tune_script.py:32 |
No bash or git |
The install script test skips | tests/test_install_role_gate.py:41-44 |
Test files by area¶
The files are grouped by their names and module docstrings. A file sits in one group only.
| Area | Count | Files |
|---|---|---|
| Architecture, static quality, and schema guards | 9 | test_architecture_boundaries.py, test_e2e_db_isolation.py, test_fk_indexes.py, test_fresh_install_contract.py, test_live_row_uniqueness.py, test_meta_representations.py, test_metadata_driven_rules.py, test_static_quality.py, test_webapp_asset_links.py |
| Analytics | 18 | test_analytics_classification.py, test_analytics_contributions.py, test_analytics_cross.py, test_analytics_forecasting.py, test_analytics_gates.py, test_analytics_inference.py, test_analytics_inference2.py, test_analytics_logit.py, test_analytics_pca_kmeans.py, test_analytics_plots.py, test_analytics_profiling.py, test_analytics_recipe.py, test_analytics_rmanova.py, test_analytics_saved_models.py, test_analytics_shapiro.py, test_analytics_statistics.py, test_analytics_stratification.py, test_analytics_summaries.py |
| Identity, access, tenancy, and privacy | 30 | test_abac_enforcement.py, test_abac_evaluator.py, test_abac_policy_condition.py, test_admin_bootstrap.py, test_at_rest_and_second_factor.py, test_auth_cache_stamp.py, test_authz_conformance.py, test_change_history_redaction.py, test_content_disposition.py, test_data_map_package1.py, test_data_map_package2.py, test_data_map_package3.py, test_data_map_package4.py, test_entitlement_stamp.py, test_erasure_ledger.py, test_log_sanitizer.py, test_login_budget_live.py, test_login_identifier.py, test_privacy_requests.py, test_residency_check.py, test_row_scope.py, test_secure_defaults.py, test_sensitive_fields_policy.py, test_settings_regions.py, test_settings_secret.py, test_signup_closed.py, test_signup_notice.py, test_signup_tokens.py, test_signup_validation.py, test_tenancy.py |
| Operations, deployment, and start-up | 18 | test_alembic_env_logging.py, test_backup_pipe.py, test_backup_retention.py, test_boot_migration_lock.py, test_bootstrap_node_script.py, test_change_history_tables_live.py, test_control_retention.py, test_database_plan_cache.py, test_deactivation_sweep_live.py, test_demo_data_live.py, test_install_restart_policy.py, test_install_role_gate.py, test_pg_tune_script.py, test_readiness_contract.py, test_request_cost.py, test_security_txt.py, test_server_keep_alive.py, test_staging_fixtures_guard.py |
| Business rules and module behaviour | 28 | test_board_calendar_chain.py, test_bom_bugfix_batch_2026_10_08.py, test_cal03_owner_calendars_live.py, test_calendar_owner_inherits_group_live.py, test_intranet_event_lifecycle.py, test_intranet_request_type_seeds.py, test_leave_day_math.py, test_mail_transport.py, test_nesting_units.py, test_order_shipment_chain.py, test_party_form_contract.py, test_procurement_descriptions.py, test_record_formatter_csv.py, test_record_links.py, test_refresh_routing_body.py, test_sales_delivery_day_party.py, test_scheduling_calendar.py, test_scheduling_calendar_chain.py, test_scheduling_capacity_units.py, test_search_contract.py, test_store_catalog_assets.py, test_subscription_math.py, test_system_mail.py, test_tenant_field_catalog.py, test_tenant_fields.py, test_work_center_capacity_cap.py, test_working_time_dst.py, test_working_time_overrides.py |
| Desktop client | 3 | test_desktop_app_scope.py, test_desktop_datetime_field.py, test_desktop_table_text_insets.py |
The architecture guards are explained on architecture boundaries. The static quality test runs Ruff and mypy; see lint and type check. tests/test_e2e_db_isolation.py checks the browser suites as text; see e2e battery.
Constraints and validation¶
- Tests that start subprocesses or reach a database name their own database; the battery isolation guard applies to the browser suites only (
tests/test_e2e_db_isolation.py:1-19). - Not determined from code: a coverage measurement. No coverage tool is declared in
pyproject.tomland none runs in.github/workflows/ci.yml.
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| live test | CLUSTER_SKIP_LIVE_TESTS |
A pytest test that needs a running server or a reachable test database and that the variable can waive. | Canlı test | tests/test_readiness_contract.py:12-14 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.