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_*.pysplit
Covers: promotion.identity
tests/promotion/_promotion_support.py
source · 0 tests · 99 lines
Shared real-infra fixtures/helpers for the
test_promotion_*.pysplit
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 showparsing 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 |