Orchestrata Ultimate › Tests › Reference › promotion

Tests reference — tests/promotion

tests/promotion — 22 test modules, 241 test functions. Source tree: tests/promotion at commit 8a2cb42ad. Generated from the tests AST snapshot by scripts/gen-data-pages.py.

Prose pending.

Modules

Module Tests Covers
_identity_fixtures.py 0 1
_promotion_support.py 0 1
test_identity_check_c0.py 11 1
test_identity_check_path_directives.py 5 1
test_identity_cli.py 6 1
test_identity_integration_basic.py 13 2
test_identity_integration_process.py 6 1
test_identity_integration_scope.py 5 1
test_identity_parsing.py 36 1
test_identity_skips.py 3 1
test_identity_tool_tree_instances.py 10 3
test_identity_url_edge_cases.py 4 1
test_identity_url_shapes.py 3 1
test_projects_coverage.py 8 1
test_promotion.py 15 3
test_promotion_ingest.py 9 3
test_promotion_prod_lessons.py 8 3
test_promotion_streaming.py 10 2
test_promotion_units.py 20 4
test_runner_coverage.py 10 3
test_stages_coverage.py 51 3
test_verify_settle_hold.py 8 4

Module details

tests/promotion/_identity_fixtures.py

source · 0 tests · 260 lines

Shared real-infra fixtures/helpers for the test_identity_*.py split

Covers: promotion.identity

tests/promotion/_promotion_support.py

source · 0 tests · 99 lines

Shared real-infra fixtures/helpers for the test_promotion_*.py split

Covers: promotion.stages

tests/promotion/test_identity_check_c0.py

source · 11 tests · 211 lines

Pure-function tests: identity_core.check_c0 (U-T6, amendment

Covers: promotion.identity_core

Kind Name Line Description
class TestCheckC0 25
method TestCheckC0.test_all_tokens_under_root_pass 28
method TestCheckC0.test_argv0_under_usr_is_judged_not_dropped_but_can_still_pass_c0 36
method TestCheckC0.test_workingdirectory_under_home_is_a_mismatch 51
method TestCheckC0.test_environment_files_path_outside_root_is_a_mismatch 61
method TestCheckC0.test_environment_pythonpath_outside_root_is_a_mismatch 73
method TestCheckC0.test_multiline_continuation_token_outside_root_is_a_mismatch 85
method TestCheckC0.test_argument_after_an_embedded_semicolon_is_still_judged 101
method TestCheckC0.test_opt_equals_path_argument_is_judged 120
method TestCheckC0.test_oneshot_argv0_under_usr_fails_c0_with_no_system_prefix_exemption 146
method TestCheckC0.test_working_directory_with_the_missing_is_ok_marker_is_still_judged 168
method TestCheckC0.test_at_prefixed_execstart_path_field_is_judged_like_argv0 187

tests/promotion/test_identity_check_path_directives.py

source · 5 tests · 98 lines

Pure-function tests: identity_core.check_path_directives (U-T6,

Covers: promotion.identity_core

Kind Name Line Description
class TestCheckPathDirectives 17
method TestCheckPathDirectives.test_fragment_referencing_workspace_is_a_mismatch 18
method TestCheckPathDirectives.test_dropin_referencing_workspace_is_a_mismatch 33
method TestCheckPathDirectives.test_continuation_line_referencing_workspace_is_a_mismatch 49
method TestCheckPathDirectives.test_comments_and_non_directive_lines_ignored 71
method TestCheckPathDirectives.test_unreadable_fragment_is_cannot_inspect 87

tests/promotion/test_identity_cli.py

source · 6 tests · 69 lines

CLI tests for promotion/identity.py (U-T6, amendment 2026-09-23;

Covers: promotion.identity

Kind Name Line Description
function test_cli_help_exits_zero 17
function test_cli_root_nonexistent_exits_two 25
function test_cli_expect_sha_empty_exits_two 32
function test_cli_missing_expect_sha_is_a_usage_error 36 [U-T6 attempt-4 finding 6]: --expect-sha is required -- the contract's
function test_cli_json_flag_emits_full_report 47
function test_cli_plain_output_on_a_non_git_root 60

tests/promotion/test_identity_integration_basic.py

source · 13 tests · 192 lines

Real-infra integration tests: prerequisites (ROOT/VERSION/git HEAD/

Covers: promotion.identity, promotion.identity_core

Kind Name Line Description
function test_root_not_a_directory_cannot_inspect 33
function test_empty_expect_sha_is_a_usage_error 39
function test_missing_version_file_cannot_inspect 47
function test_key_equals_value_version_is_rejected_by_the_real_checker 55
function test_not_a_git_repo_cannot_inspect 68
function test_show_helper_reports_a_real_systemctl_failure 77
function test_full_happy_path_real_unit_real_proc 86
function test_zero_units_matching_the_pattern_cannot_inspect 95
function test_sha_disagrees_with_version_commit_is_a_mismatch 108
function test_expect_sha_mismatch_is_reported 116
function test_scope_excludes_bare_host_timers_and_requires_a_prod_unit 124 [U-T6 attempt-4 finding 1]: scope is orchestrata-/orchgraph-
function test_unparsable_start_time_on_a_live_process_is_an_error_not_a_pass 149 [U-T6 attempt-4 finding 9]: systemd always sets ExecMainStartTimestamp
function test_module_imports_fine_from_root_cwd 183

tests/promotion/test_identity_integration_process.py

source · 6 tests · 173 lines

Real-infra integration tests: /proc-derived process identity (check d)

Covers: promotion.identity

Kind Name Line Description
function test_argv0_pointing_at_system_python_is_judged_not_dropped 31 D2 done_when: a prod-named unit with argv0 /usr/bin/python3 is judged
function test_working_directory_with_missing_is_ok_marker_is_a_mismatch_real_unit 55 [U-T6 attempt-5 finding 1] A real transient oneshot whose
function test_wrong_proc_cwd_is_a_mismatch 104
function test_missing_proc_entry_for_a_real_pid_cannot_inspect 121
function test_process_started_before_deploy_is_a_mismatch 133
function test_long_running_unit_with_no_process_is_cannot_inspect_not_dropped 145

tests/promotion/test_identity_integration_scope.py

source · 5 tests · 190 lines

Real-infra integration tests: Type=idle liveness, oneshot/sibling-timer

Covers: promotion.identity

Kind Name Line Description
function test_type_idle_unit_is_judged_not_silently_passed 29 [U-T6 attempt-4 finding 5]: ANY Type that is not oneshot is long-
function test_oneshot_with_active_timer_passes 58
function test_oneshot_failure_and_missing_timer_are_both_reported 81
function test_dropin_referencing_workspace_is_caught_end_to_end 111 done_when: a drop-in override.conf pointing Environment at
function test_mixed_user_and_system_discovery 143 Proves BOTH managers are queried, each unit judged with the scope it

tests/promotion/test_identity_parsing.py

source · 36 tests · 274 lines

Pure-function tests: VERSION/timestamp/systemctl show parsing and the

Covers: promotion.identity_core

Kind Name Line Description
function test_default_globs_cover_the_real_naming_convention 36
class TestParseVersion 48
method TestParseVersion.test_installer_exact_printf_output 49
method TestParseVersion.test_key_equals_value_form_is_rejected 60
method TestParseVersion.test_missing_commit_is_none 65
method TestParseVersion.test_missing_deployed_is_none 71
class TestParseTimestamp 75
method TestParseTimestamp.test_iso_with_offset 76
method TestParseTimestamp.test_systemd_default_format 81
method TestParseTimestamp.test_na_and_garbage_are_none 86
class TestParseShow 92
method TestParseShow.test_repeated_key_is_concatenated_not_overwritten 93
method TestParseShow.test_lines_without_equals_are_skipped 106
class TestExtractArgv 112
method TestExtractArgv.test_multi_block_execstartpre_yields_all_tokens 113
method TestExtractArgv.test_multiline_continuation_resolved_value 117
method TestExtractArgv.test_path_only_form 127
method TestExtractArgv.test_bare_string_form 133
method TestExtractArgv.test_semicolon_inside_an_argument_does_not_truncate_argv 136
class TestExtractPath 152
method TestExtractPath.test_extracts_the_path_field_not_argv0 153
method TestExtractPath.test_multiple_blocks_yield_every_path 160
method TestExtractPath.test_no_path_field_yields_empty 164
method TestExtractPath.test_data_path_argument_is_not_mistaken_for_the_field 167
method TestExtractPath.test_classpath_argument_is_not_mistaken_for_the_field 179
method TestExtractPath.test_argv_embedded_semicolon_path_is_not_mistaken_for_the_field 187
class TestNormalizeDirectiveValue 205
method TestNormalizeDirectiveValue.test_strips_the_missing_is_ok_marker 206
method TestNormalizeDirectiveValue.test_strips_a_bare_dash_marker 212
method TestNormalizeDirectiveValue.test_plain_path_is_unchanged 215
method TestNormalizeDirectiveValue.test_bare_tilde_expands_to_home 218
method TestNormalizeDirectiveValue.test_tilde_slash_expands_to_home 221
class TestEnvironmentParsing 225
method TestEnvironmentParsing.test_environment_file_paths_multiple_entries 226
method TestEnvironmentParsing.test_environment_path_values_extracts_workspace_leak 230
method TestEnvironmentParsing.test_environment_path_values_ignores_non_path_values 239
method TestEnvironmentParsing.test_environment_path_values_splits_colon_lists 242
method TestEnvironmentParsing.test_environment_path_values_two_tokens_url_does_not_hide_a_sibling_leak 246
class TestResolvesSafely 257
method TestResolvesSafely.test_under_root_passes 260
method TestResolvesSafely.test_root_itself_passes 263
method TestResolvesSafely.test_system_prefixes_pass 266
method TestResolvesSafely.test_home_always_fails 270
method TestResolvesSafely.test_unrelated_absolute_path_fails 273

tests/promotion/test_identity_skips.py

source · 3 tests · 152 lines

Real-infra integration tests: unit-scope skip rules (U-VERIFY1) for

Covers: promotion.identity

Kind Name Line Description
function test_unit_with_unloadable_dependency_is_skipped_sibling_still_proven 59 U-VERIFY1: a discovered unit whose Requires=/BindsTo= names a unit
function test_orchestrata_canvas_service_is_skipped_by_r8_without_process_inspection 106 ADR-0062 read with ruling R8: orchestrata-canvas.service lives in
function test_inactive_unit_still_fails_skips_never_widen_leniency 134 Pin: neither skip rule ever widens into general leniency -- a plain

tests/promotion/test_identity_tool_tree_instances.py

source · 10 tests · 278 lines

Tool-tree template instances are judged against /opt/orchestrata-tools

Covers: promotion.identity, promotion.identity_checks, promotion.identity_scope

Kind Name Line Description
function test_template_instance_passes_against_the_tool_tree 111
function test_token_outside_both_roots_still_fails 129
function test_instance_with_argv0_outside_the_tool_tree_keeps_the_product_root 150
function test_plain_unit_result_and_render_are_unchanged 173
function test_tool_tree_root_is_none_without_an_instance_or_outside_the_tree 194
function test_start_time_is_compared_with_the_tools_version 214
function test_systemd_unescape_decodes_the_live_instance_name 232
function test_systemd_unescape_matches_real_systemd_escape 238
function test_missing_tools_version_is_an_error_naming_the_path 254
function test_malformed_tools_version_is_an_error_naming_the_path 268

tests/promotion/test_identity_url_edge_cases.py

source · 4 tests · 158 lines

Attempt-7b residuals 2 and 3: Environment= nested-equals splitting and

Covers: promotion.identity_core

Kind Name Line Description
class TestEnvironmentNestedEquals 59
method TestEnvironmentNestedEquals.test_environment_splits_on_first_equals_only 65
method TestEnvironmentNestedEquals.test_check_c0_environment_nested_equals 78
class TestStandardIo 133
method TestStandardIo.test_standard_io_path 137
method TestStandardIo.test_check_c0_standard_io 144

tests/promotion/test_identity_url_shapes.py

source · 3 tests · 207 lines

Table-driven URL-vs-path judging (attempt-7): environment_path_values

Covers: promotion.identity_core

Kind Name Line Description
class TestUrlPathCases 149
method TestUrlPathCases.test_environment_path_values 162
method TestUrlPathCases.test_check_c0_argv 175
method TestUrlPathCases.test_url_then_separate_token_leak_is_still_flagged 192

tests/promotion/test_projects_coverage.py

source · 8 tests · 100 lines

Coverage tests for promotion.projects — the workspace discovery layer.

Covers: promotion.projects

Kind Name Line Description
class TestProjectGitDir 39
method TestProjectGitDir.test_git_dir_points_at_dot_git_under_path 40
method TestProjectGitDir.test_git_dir_of_worktree_is_a_file 46
class TestDiscoverProjectsNonDirectory 53
method TestDiscoverProjectsNonDirectory.test_missing_workspace_returns_empty 54
method TestDiscoverProjectsNonDirectory.test_file_workspace_returns_empty 58
class TestDescribe 64
method TestDescribe.test_describe_counts_projects_worktrees_and_non_repos 65
method TestDescribe.test_describe_empty_workspace 80
method TestDescribe.test_describe_missing_workspace_reports_zeroes 87
method TestDescribe.test_describe_file_workspace_reports_zeroes 95

tests/promotion/test_promotion.py

source · 15 tests · 270 lines

Tests for the deployment stages — promotion has to mean deployment.

Covers: promotion.models, promotion.projects, promotion.stages

Kind Name Line Description
class TestProjectDiscovery 52 A worktree is a second checkout of a repo the graph already holds.
method TestProjectDiscovery.test_a_repo_is_a_project_and_a_worktree_is_not 59
method TestProjectDiscovery.test_discovery_excludes_worktrees_structurally 68 Not by name — a hardcoded list is stale the moment one is made.
method TestProjectDiscovery.test_discovery_does_not_recurse 82 Recursing would pull in vendored checkouts and swamp the real ones.
class TestResolveRefusesUndeployableCommits 95
method TestResolveRefusesUndeployableCommits.test_a_dirty_tree_is_refused 96 A working copy is not any commit, so no sha would describe it.
method TestResolveRefusesUndeployableCommits.test_session_tracker_exhaust_does_not_block_a_deploy 105 context.json/md are rewritten by the session CLI constantly.
method TestResolveRefusesUndeployableCommits.test_an_unpushed_commit_is_refused 118 A sha only this machine has cannot be reproduced or rolled forward.
method TestResolveRefusesUndeployableCommits.test_a_clean_pushed_commit_is_pinned 130
class TestResolveIgnoresGeneratedArtifacts 139 resolve must agree with deploy/ship.sh about what "dirty" means.
method TestResolveIgnoresGeneratedArtifacts.test_a_tree_dirty_only_with_generated_artifacts_resolves 151
method TestResolveIgnoresGeneratedArtifacts.test_untracked_files_do_not_block_a_deploy 165 --untracked-files=no, matching ship.sh: an untracked scratch
method TestResolveIgnoresGeneratedArtifacts.test_a_real_source_edit_still_refuses_alongside_generated_churn 179 Excluding generated paths must never swallow a genuine source edit.
class TestTreeAdvance 197
method TestTreeAdvance.test_same_sha_still_runs_a_real_reset_hard 198 Re-running a completed deploy is a visible no-op in RESULT, but
method TestTreeAdvance.test_dry_run_reports_the_move_without_making_it 219
method TestTreeAdvance.test_a_target_that_is_not_a_checkout_fails 239
class TestDependencySync 248
method TestDependencySync.test_an_unchanged_lock_is_skipped 249 uv sync on an unchanged lock trains everyone to ignore the stage.
method TestDependencySync.test_a_moved_lock_would_sync 262

tests/promotion/test_promotion_ingest.py

source · 9 tests · 218 lines

Ingest-argv-contract, ingest-parallelism, profile-completeness and dry-run

Covers: promotion.models, promotion.projects, promotion.stages

Kind Name Line Description
class TestIngestArgvContract 36 The ingest stage must speak the CLI the AST tool actually exposes.
method TestIngestArgvContract.test_serialize_argv_is_accepted_by_the_real_parser 39
method TestIngestArgvContract.test_load_argv_is_accepted_by_the_real_parser 52
method TestIngestArgvContract.test_the_two_steps_agree_on_the_snapshot_path 62
class TestIngestParallelism 72 The corpus rebuild fans out; it does not crawl one core at a time.
method TestIngestParallelism.test_projects_ingest_concurrently_not_serially 82
class TestIncompleteProfilesAreRefused 126 RUL-003: a missing endpoint key FAILS the stage; it never defaults.
method TestIncompleteProfilesAreRefused.test_a_profile_without_a_redis_port_is_refused 138
method TestIncompleteProfilesAreRefused.test_a_graph_uri_without_a_port_is_refused 148
method TestIncompleteProfilesAreRefused.test_verify_refuses_a_profile_with_no_kernel_endpoint 164
class TestTheDryRunReportsWhatTheDeployWouldDo 172 A dry run is read INSTEAD of deploying; a blank in it is a defect.
method TestTheDryRunReportsWhatTheDeployWouldDo.test_the_sha_is_resolved_even_when_nothing_is_executed 182
method TestTheDryRunReportsWhatTheDeployWouldDo.test_deps_does_not_claim_the_lock_is_unchanged 203

tests/promotion/test_promotion_prod_lessons.py

source · 8 tests · 251 lines

Regression tests pinned by real prod deployments (U-SIZE-B1: split out of

Covers: promotion.models, promotion.runner, promotion.stages

Kind Name Line Description
class TestWhatTheFirstProdDeploymentTaught 28 Each of these was a live failure, not a hypothetical.
method TestWhatTheFirstProdDeploymentTaught.test_a_sourced_helper_is_not_treated_as_a_hook 39 _payload.sh is 100644 in git and must stay that way.
method TestWhatTheFirstProdDeploymentTaught.test_a_non_executable_hook_fails_the_stage_instead_of_being_chmodded 64
method TestWhatTheFirstProdDeploymentTaught.test_verify_waits_for_a_port_rather_than_sleeping_a_guess 86 The kernel bound 9s after restart; a 3s sleep called it shut.
method TestWhatTheFirstProdDeploymentTaught.test_deploy_does_not_shadow_verifys_measured_settle 141 A 3.0 default in deploy overrode verify's measured 90.0.
method TestWhatTheFirstProdDeploymentTaught.test_an_operators_explicit_settle_still_reaches_the_stage 199 Omitting the key must not also swallow a deliberate --settle.
method TestWhatTheFirstProdDeploymentTaught.test_the_settle_default_lives_only_in_verify 204 One default, owned by the stage whose docstring measured it.
class TestASlowCommandFailsRatherThanCrashing 215 A stage that runs long must produce a FAIL, not a traceback.
method TestASlowCommandFailsRatherThanCrashing.test_a_timeout_becomes_a_nonzero_return_code 225
method TestASlowCommandFailsRatherThanCrashing.test_the_graphs_stage_reports_a_timeout_as_a_failed_stage 230

tests/promotion/test_promotion_streaming.py

source · 10 tests · 220 lines

Substep-streaming, timeout-cleanup and environment-selector tests for the

Covers: promotion.models, promotion.stages

Kind Name Line Description
class TestTheGraphsStageStreamsItsSubsteps 27 The bootstrap's step lines must reach the progress callback live.
method TestTheGraphsStageStreamsItsSubsteps.test_stdout_and_stderr_step_lines_reach_progress_as_they_appear 49
method TestTheGraphsStageStreamsItsSubsteps.test_streamed_lines_survive_a_timeout_and_the_stage_still_fails 67
method TestTheGraphsStageStreamsItsSubsteps.test_without_progress_the_stage_still_captures_and_passes 82
class TestATimeoutLeavesNothingRunning 92 The grandchild is the one that got away.
method TestATimeoutLeavesNothingRunning.test_a_grandchild_does_not_survive_the_timeout 103
class TestTheChildIsToldWhichEnvironmentItIsDeploying 137 The selector names the profile FILE, so merging keys cannot fix it.
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_the_selector_names_the_target_environment 157
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_an_inherited_selector_does_not_survive 163
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_profile_keys_still_beat_the_inherited_environment 172
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_the_target_trees_own_secrets_beat_the_inherited_environment 178 A deployment is its own project; its .env is its own.
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_the_profile_still_beats_the_target_trees_secrets 200
method TestTheChildIsToldWhichEnvironmentItIsDeploying.test_a_target_without_a_dotenv_keeps_the_inherited_environment 211

tests/promotion/test_promotion_units.py

source · 20 tests · 349 lines

Unit-selection, drift, runner-ordering, progress and report tests for the

Covers: promotion.models, promotion.runner, promotion.stages, promotion.stages_units

Kind Name Line Description
class TestUnitSelection 24
method TestUnitSelection.test_timer_driven_oneshots_are_not_restarted 35 A .service with a sibling .timer runs on schedule.
method TestUnitSelection.test_a_template_unit_and_an_out_of_root_unit_yield_neither 52 F2 (reviewer on attempt 1): a *@.service TEMPLATE is never
method TestUnitSelection.test_a_missing_binary_is_not_runnable_here_yet 73 F2: the unit FILE is real and its ExecStart resolves under the
method TestUnitSelection.test_the_real_repo_units_are_the_four_daemons 87 The real committed deploy/systemd/*.service files, discovered
method TestUnitSelection.test_a_unit_requiring_an_unloadable_unit_is_not_restarted 119 U-UNIT2: measured on a prod promote (2026-09-24) -- install.sh
method TestUnitSelection.test_a_unit_requiring_a_loadable_unit_is_still_restarted 156 The mirror case: Requires=default.target names a unit
class TestDriftDetection 175 The failure that motivated the package: a record that stopped being true.
method TestDriftDetection.test_a_ledger_without_a_sha_cannot_be_checked 178 This is the live prod state as of 2026-08-10, and it must be loud.
method TestDriftDetection.test_a_matching_sha_is_clean 186
method TestDriftDetection.test_a_stale_target_reports_drifted 194
class TestRunnerOrdering 210
method TestRunnerOrdering.test_the_run_stops_at_the_first_failure 211 A deploy that half-lands and reports success is worse than a refusal.
method TestRunnerOrdering.test_a_failure_before_the_restart_does_not_roll_back 225 Nothing was in front of traffic yet, so there is nothing to undo.
class TestProgressStreaming 241
method TestProgressStreaming.test_every_stage_emits_a_start_and_an_end_line 242 Stages must STREAM, not buffer. The first live promote ran its
method TestProgressStreaming.test_no_progress_callback_is_silent_and_still_works 272
class TestReport 286
method TestReport.test_a_skip_is_success_not_failure 287
method TestReport.test_the_record_carries_the_sha 292 The field whose absence let PROMOTED coexist with a stale tree.
method TestReport.test_a_failed_report_says_failed 299
class TestUnitProbe 306 WI-UNITS (failure #2 of the 2026-10-08 recorded run, task 573): the
method TestUnitProbe.test_an_empty_directory_probe_excludes_a_unit_with_an_unknown_requires 323
method TestUnitProbe.test_a_directory_probe_holding_the_required_unit_includes_it 329
method TestUnitProbe.test_the_systemd_probe_answers_from_the_host 341
method TestUnitProbe.test_the_default_probe_is_systemd 347

tests/promotion/test_runner_coverage.py

source · 10 tests · 558 lines

Coverage for the deploy runner's ordering, rollback, and drift paths.

Covers: promotion.models, promotion.runner, promotion.stages

Kind Name Line Description
class TestDriftRefusesANonCheckout 83
method TestDriftRefusesANonCheckout.test_a_target_without_git_metadata_cannot_be_compared 84 A bare directory has no HEAD, so any verdict about it would be
class TestDeployRunsEveryStageWhenNothingIsSkipped 96
method TestDeployRunsEveryStageWhenNothingIsSkipped.test_graphs_and_ingest_are_part_of_the_default_run 97 skip_graphs/skip_ingest are the operator's escape hatch, not the
class TestRollbackRefusesToImplyARecovery 158
method TestRollbackRefusesToImplyARecovery.test_no_previous_sha_is_a_skip_not_a_recovery 159 A first deploy has nothing to return to; saying otherwise would
method TestRollbackRefusesToImplyARecovery.test_previous_equal_to_current_is_a_skip 171 Returning to the sha already served is a no-op, and the record
method TestRollbackRefusesToImplyARecovery.test_a_failed_checkout_is_a_failed_rollback 182 If the target cannot be returned, the record says FAIL — implying
class TestRollbackReturnsTheTarget 199
method TestRollbackReturnsTheTarget.test_a_restart_failure_during_rollback_is_reported_not_hidden 200 A unit that genuinely does not exist: systemctl really runs,
method TestRollbackReturnsTheTarget.test_a_real_unit_restart_during_rollback_succeeds 233 The other half of the same proof: a REAL, restartable unit makes
method TestRollbackReturnsTheTarget.test_rollback_reinstalls_the_old_trees_units_before_restarting 273 A tree reset does not undo what assets installed: the NEW
class TestDeployRollsBackWhenALiveStageFails 370
method TestDeployRollsBackWhenALiveStageFails.test_a_restart_failure_returns_the_target_to_what_it_served 371 The whole product in one test: the tree advances, the restart of
class TestRollbackAfterVenvLessFirstDeploy 439
method TestRollbackAfterVenvLessFirstDeploy.test_rollback_restarts_what_restart_services_actually_restarted 440 N1 (reviewer on U-T7): deploy() resolves ctx.units ONCE,

tests/promotion/test_stages_coverage.py

source · 51 tests · 1007 lines

Branch-complete coverage for promotion/stages.py.

Covers: promotion.models, promotion.runner, promotion.stages

Kind Name Line Description
class TestKillGroup 113 The TERM-then-KILL escalation, against real process groups.
method TestKillGroup.test_a_reaped_child_needs_no_signal 116
method TestKillGroup.test_a_child_that_ignores_sigterm_is_killed 126
class TestEndpointParsing 150 _endpoint invents nothing: no port in the URI means no probe.
method TestEndpointParsing.test_a_uri_without_a_scheme_says_nothing 153
method TestEndpointParsing.test_a_uri_without_a_port_says_nothing 156
method TestEndpointParsing.test_a_uri_without_a_host_says_nothing 159
method TestEndpointParsing.test_a_full_uri_parses_host_and_port 162
class TestProbeEndpointsAgainstRealSockets 167 The infra stage probes what the profile declares — really probes it.
method TestProbeEndpointsAgainstRealSockets.test_the_live_test_fleet_probes_reachable 170
method TestProbeEndpointsAgainstRealSockets.test_an_unreachable_endpoint_fails_with_its_name 186
method TestProbeEndpointsAgainstRealSockets.test_only_the_unreachable_target_is_named 199
class TestResolveCommitEdge 213
method TestResolveCommitEdge.test_a_repo_with_no_commits_cannot_resolve_head 214
class TestAdvanceTreeExecutePaths 225
method TestAdvanceTreeExecutePaths.test_a_git_dir_that_is_not_a_repo_fails 226
method TestAdvanceTreeExecutePaths.test_a_failed_fetch_fails_the_stage 234
method TestAdvanceTreeExecutePaths.test_a_sha_the_remote_does_not_have_fails_checkout 248
method TestAdvanceTreeExecutePaths.test_a_real_advance_moves_the_target_to_the_pinned_sha 260
class TestSyncDepsRealUv 281
method TestSyncDepsRealUv.test_no_lock_in_the_target_is_a_skip 282
method TestSyncDepsRealUv.test_a_moved_lock_runs_a_real_uv_sync 288
method TestSyncDepsRealUv.test_a_broken_lock_fails_the_stage 306
class TestInstallAssetsExecutePaths 321
method TestInstallAssetsExecutePaths.test_a_missing_installer_fails 327
method TestInstallAssetsExecutePaths.test_a_successful_install_reports_the_hook_count 334
method TestInstallAssetsExecutePaths.test_a_failing_installer_fails_the_stage 347
class TestRestartServices 360
method TestRestartServices.test_no_units_is_a_skip 361
method TestRestartServices.test_a_dry_run_lists_the_units_it_would_restart 368
method TestRestartServices.test_a_failed_restart_is_reported_by_unit_name 374
method TestRestartServices.test_a_real_unit_restarts_clean 384
class TestVerifyPollAndDeadline 407
method TestVerifyPollAndDeadline.test_a_dry_run_reports_without_probing 408
method TestVerifyPollAndDeadline.test_a_dry_run_with_no_units_fails_loud 414 Item 1 (reviewer on attempt 1): even a dry run must not predict
method TestVerifyPollAndDeadline.test_no_units_fails_loud_even_with_ports_listening 422 Item 1 (reviewer on attempt 1): a target with NO daemon units has
method TestVerifyPollAndDeadline.test_inactive_units_and_shut_ports_fail_at_the_deadline 454
class TestBootstrapGraphsGates 472
method TestBootstrapGraphsGates.test_a_target_without_the_script_skips 473
method TestBootstrapGraphsGates.test_a_dry_run_reports_the_bootstrap_it_would_run 479
method TestBootstrapGraphsGates.test_the_promote_bootstraps_the_kg_and_never_runs_the_rag_ingest 487 ADR-0076 (Mohamed 2026-10-19, "drop injest"): the promote's graphs
class TestIngestProjectsRealSubprocesses 522 The fan-out runs real serialize/ast-to-kg argv against a real script.
method TestIngestProjectsRealSubprocesses.test_a_dry_run_reports_the_workspace_with_a_limit 565
method TestIngestProjectsRealSubprocesses.test_an_empty_workspace_skips 574
method TestIngestProjectsRealSubprocesses.test_a_parse_failure_fails_the_stage_with_the_project_named 583
method TestIngestProjectsRealSubprocesses.test_a_load_failure_is_labelled_separately_from_a_parse_failure 593
method TestIngestProjectsRealSubprocesses.test_a_clean_workspace_ingests_every_project 606
class TestScopeHeader 617 _scope(unit_file) -- restart/verify/rollback's per-unit resolution,
method TestScopeHeader.test_a_missing_file_defaults_to_user 621
method TestScopeHeader.test_no_header_defaults_to_user 624
method TestScopeHeader.test_a_system_header_is_honoured 629
method TestScopeHeader.test_an_explicit_user_header_still_says_user 636
method TestScopeHeader.test_missing_space_after_hash_is_not_a_header 641 F5 (reviewer on attempt 1): anchored EXACTLY to install.sh's own
method TestScopeHeader.test_extra_whitespace_around_the_value_is_not_a_header 648
method TestScopeHeader.test_leading_indentation_is_not_a_header 655
class TestRecordVersion 661 record_version -- D1's staged-then-promoted VERSION write.
method TestRecordVersion.test_a_dry_run_touches_nothing 671
method TestRecordVersion.test_a_real_write_is_staged_then_promoted_in_the_installer_format 679
method TestRecordVersion.test_the_previous_version_text_is_captured_before_overwriting 705
method TestRecordVersion.test_no_origin_remote_fails_the_stage 719
class TestVerifyCallsIdentity 779 verify() proves identity after its poll succeeds -- health is not
method TestVerifyCallsIdentity.test_record_version_then_restart_then_verify_end_in_identity_ok 801 F4(a) (reviewer on attempt 1): the real D1 pipeline -- record_version,
method TestVerifyCallsIdentity.test_a_real_matching_deployment_passes_identity 858
method TestVerifyCallsIdentity.test_a_mismatched_working_directory_fails_identity 890
class TestDeployRollsBackOnIdentityMismatch 933 The whole product, end to end: a deploy whose units restart cleanly
method TestDeployRollsBackOnIdentityMismatch.test_a_forced_identity_mismatch_rolls_back_tree_and_version 939

tests/promotion/test_verify_settle_hold.py

source · 8 tests · 309 lines

P6b: the promoter's verify settles before it judges.

Covers: promotion.models, promotion.stages_context, promotion.stages_units, promotion.stages_verify

Kind Name Line Description
function test_timespan_parsing_matches_systemd_renderings 134
function test_timespan_parsing_refuses_garbage 139
function test_a_unit_crashing_inside_the_hold_is_refused_as_not_active 144 Exit at 2.5 s, restart at 7.5 s (RestartSec=5): the hold (6.0 s) re-reads
function test_a_crash_looping_unit_is_refused_as_restarted 174 Exit at 0.8 s, restart at 2.8 s (RestartSec=2): the hold (3.0 s) re-reads
function test_a_restart_interval_longer_than_the_patience_is_refused_without_waiting 204 RestartSec=200 against settle=10: refused unslept, naming the unit.
function test_a_steady_unit_passes_and_the_hold_is_read_from_the_unit 234 RestartSec=3 in the unit file sizes the hold: 3 + 1 = 4.0 s.
function test_a_unit_that_never_restarts_holds_for_the_one_second_floor 262 RestartSec=infinity cannot crash-loop: the hold is the 1 s floor, and
function test_a_unit_that_cannot_be_shown_is_refused 292 A unit that was never loaded fails the poll on is-active -- the