Skip to content

Commit 76e6aab

Browse files
authored
test: end-to-end partial-batch failure recovers on re-run (#61) (#62)
* test(recovery): end-to-end test that a partial batch failure recovers on re-run Drive process_submodule_list over real git fixtures with one submodule's remote transiently offline, so it fails while the others succeed. The re-run, with the remote restored, completes the previously-failed submodule and leaves the already-synced ones untouched (no new commit). Closes #61. * test(recovery): assert the failed remote is untouched before re-run Before Run 2, verify the restored json remote still points at json_start, confirming the failed push committed locally but never reached the remote. * test(recovery): re-clone destinations fresh before the re-run Match sync_one_submodule's per-run mktemp workspace: delete and re-clone each destination from its bare remote before run 2. This proves the recovering submodule re-commits and pushes against the unchanged remote rather than pushing run 1's leftover local commit.
1 parent 19cf076 commit 76e6aab

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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

Comments
 (0)