|
| 1 | +#!/usr/bin/env bats |
| 2 | +# |
| 3 | +# End-to-end: a partial batch failure recovers on re-run (#61). |
| 4 | +# |
| 5 | +# Runs process_submodule_list over real git fixtures with one submodule's remote |
| 6 | +# transiently unavailable, so it fails while the others succeed. The re-run, with |
| 7 | +# the remote restored, completes the previously-failed submodule and leaves the |
| 8 | +# already-synced ones untouched (no new commit). |
| 9 | + |
| 10 | +setup() { |
| 11 | + # shellcheck source=tests/helpers/test_helper.bash |
| 12 | + source "$BATS_TEST_DIRNAME/helpers/test_helper.bash" |
| 13 | + load_submodule_ops # lib.sh state/summary + process_submodule_list |
| 14 | + # shellcheck source=/dev/null |
| 15 | + source "$ASSETS_DIR/translation.sh" # sync_repo_master |
| 16 | + init_git_fixture_root |
| 17 | + init_translation_state |
| 18 | + init_submodule_summary_buckets |
| 19 | + libs_ref="develop" |
| 20 | +} |
| 21 | + |
| 22 | +teardown() { |
| 23 | + cleanup_git_fixture_root |
| 24 | +} |
| 25 | + |
| 26 | +# Bare mirror remote + a dest clone + a source-content dir for one submodule. |
| 27 | +install_recovery_fixture() { |
| 28 | + local sub="$1" |
| 29 | + create_bare_remote_with_clone "$sub" |
| 30 | + git clone "$GIT_FIXTURE_ROOT/${sub}.git" "$GIT_FIXTURE_ROOT/${sub}-dest" |
| 31 | + mkdir -p "$GIT_FIXTURE_ROOT/${sub}-src/doc" |
| 32 | + echo "$sub documentation" >"$GIT_FIXTURE_ROOT/${sub}-src/doc/page.adoc" |
| 33 | +} |
| 34 | + |
| 35 | +# process_submodule_list processor: mirror one submodule's source into its dest |
| 36 | +# repo and push. Returns sync_repo_master's status (0 success, 2 failure). |
| 37 | +recovery_processor() { |
| 38 | + local sub="$1" |
| 39 | + sync_repo_master "$GIT_FIXTURE_ROOT/${sub}-dest" "$GIT_FIXTURE_ROOT/${sub}-src" "$libs_ref" |
| 40 | +} |
| 41 | + |
| 42 | +remote_head() { |
| 43 | + git -C "$GIT_FIXTURE_ROOT/$1.git" rev-parse "$MASTER_BRANCH" |
| 44 | +} |
| 45 | + |
| 46 | +@test "process_submodule_list: a partial batch failure recovers on re-run" { |
| 47 | + install_recovery_fixture algorithm |
| 48 | + install_recovery_fixture json |
| 49 | + install_recovery_fixture system |
| 50 | + |
| 51 | + local algo_start json_start system_start |
| 52 | + algo_start=$(remote_head algorithm) |
| 53 | + json_start=$(remote_head json) |
| 54 | + system_start=$(remote_head system) |
| 55 | + |
| 56 | + # --- Run 1: json's remote is transiently unavailable (moved aside). --- |
| 57 | + mv "$GIT_FIXTURE_ROOT/json.git" "$GIT_FIXTURE_ROOT/json.git.offline" |
| 58 | + |
| 59 | + set +e |
| 60 | + process_submodule_list recovery_processor algorithm json system |
| 61 | + local rc1=$? |
| 62 | + set -e |
| 63 | + [ "$rc1" -eq 0 ] |
| 64 | + |
| 65 | + # algorithm and system are updated; json is the only fatal. |
| 66 | + [ "${UPDATES[*]}" = "algorithm system" ] |
| 67 | + [ "${SUBMODULE_FATAL[*]}" = "json" ] |
| 68 | + [ "$submodule_fatal" -eq 1 ] |
| 69 | + |
| 70 | + # The two healthy remotes advanced; the summary counts json as a failure. |
| 71 | + local algo_after1 system_after1 |
| 72 | + algo_after1=$(remote_head algorithm) |
| 73 | + system_after1=$(remote_head system) |
| 74 | + [ "$algo_after1" != "$algo_start" ] |
| 75 | + [ "$system_after1" != "$system_start" ] |
| 76 | + |
| 77 | + local summary |
| 78 | + summary="$(print_submodule_processing_summary 2>&1)" |
| 79 | + echo "$summary" | grep -E "Successfully updated \(2\):.*algorithm.*system" |
| 80 | + echo "$summary" | grep -E "processing error \(1\):.*json" |
| 81 | + |
| 82 | + # --- Run 2: json's remote is restored; re-run the same batch fresh. --- |
| 83 | + mv "$GIT_FIXTURE_ROOT/json.git.offline" "$GIT_FIXTURE_ROOT/json.git" |
| 84 | + # The failed run committed locally but never pushed, so the remote is untouched. |
| 85 | + [ "$(remote_head json)" = "$json_start" ] |
| 86 | + |
| 87 | + # Production clones each destination fresh per run (sync_one_submodule works in |
| 88 | + # a mktemp -d workspace), so re-clone from each bare remote instead of reusing |
| 89 | + # run 1's checkout. This proves the recovering submodule re-commits and pushes |
| 90 | + # against the unchanged remote rather than pushing run 1's leftover local commit. |
| 91 | + for sub in algorithm json system; do |
| 92 | + rm -rf "$GIT_FIXTURE_ROOT/${sub}-dest" |
| 93 | + git clone "$GIT_FIXTURE_ROOT/${sub}.git" "$GIT_FIXTURE_ROOT/${sub}-dest" |
| 94 | + done |
| 95 | + |
| 96 | + init_translation_state |
| 97 | + init_submodule_summary_buckets |
| 98 | + |
| 99 | + set +e |
| 100 | + process_submodule_list recovery_processor algorithm json system |
| 101 | + local rc2=$? |
| 102 | + set -e |
| 103 | + [ "$rc2" -eq 0 ] |
| 104 | + |
| 105 | + # No fatals remain and json is now recovered. |
| 106 | + [ "$submodule_fatal" -eq 0 ] |
| 107 | + [ "${#SUBMODULE_FATAL[@]}" -eq 0 ] |
| 108 | + [ "${UPDATES[*]}" = "algorithm json system" ] |
| 109 | + [ "$(remote_head json)" != "$json_start" ] |
| 110 | + |
| 111 | + # The already-synced remotes are idempotent: no new commit on the re-run. |
| 112 | + [ "$(remote_head algorithm)" = "$algo_after1" ] |
| 113 | + [ "$(remote_head system)" = "$system_after1" ] |
| 114 | +} |
0 commit comments