feat(controller-peers-env-fallback): fall back to XCE_CONTROLLER_PEERS in the scheduler (task 3.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-03 06:46:34 +00:00
parent 9018980b08
commit 55193fcb4b
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
3 changed files with 187 additions and 14 deletions

View file

@ -504,6 +504,152 @@ case_controller_flag_own_name_unchecked() {
add_case case_controller_flag_own_name_unchecked \
"controller: explicit --peers without the own name is not checked at startup (1.6)"
# ── Task 3.1 (Req 1.1-1.5, 1.7, 1.8): the scheduler resolves its candidate
# list from --peers, else XCE_CONTROLLER_PEERS, else the single-controller
# path. A valid list keeps the scheduler running (it retries its controller),
# so those runs are started in the background, stopped once the startup line
# is in the log, and only then asserted on. Argument errors exit on their own.
# Either startup line; every successful scheduler start logs exactly one.
SCHED_ANCHOR_RE='HA cluster config|No --peers flag'
SCHED_STANDALONE_RE='No --peers flag and XCE_CONTROLLER_PEERS unset or empty; using single-controller path, version '
# start_scheduler <dir> <env-args...> -- [scheduler args...]
# Start the scheduler in the background with --logfile <dir>/scheduler.log,
# wait for its startup line, then stop it. Fails (with the log tail) when
# the line never appears.
start_scheduler() {
local dir="$1"; shift
local envargs=() pid
while [ $# -gt 0 ] && [ "$1" != -- ]; do
envargs+=("$1"); shift
done
[ $# -gt 0 ] && shift
start_bg "$dir" "${envargs[@]}" "$SCHEDULER_BIN" \
--logfile "$dir/scheduler.log" "$@"
pid="$LAST_PID"
if ! wait_for_line "$dir/scheduler.log" "$SCHED_ANCHOR_RE" 10 "$pid"; then
stop_proc "$pid"
red " scheduler never logged its startup line"
_show_tail "$dir/scheduler.log"
_show_tail "$dir/stderr"
return 1
fi
stop_proc "$pid"
}
# run_scheduler <dir> <env-args...> -- [scheduler args...]
# Run the scheduler to completion (argument errors, --sim, --help).
run_scheduler() {
local dir="$1"; shift
local envargs=()
while [ $# -gt 0 ] && [ "$1" != -- ]; do
envargs+=("$1"); shift
done
[ $# -gt 0 ] && shift
run_to_completion "$dir" 10 "${envargs[@]}" "$SCHEDULER_BIN" \
--logfile "$dir/scheduler.log" "$@"
}
case_scheduler_env_list() {
local d; d="$(new_scratch scheduler-env-list)"
start_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- || return 1
assert_grep "$d/scheduler.log" \
'HA cluster config: 3 candidate\(s\), identity=xce_scheduler \(from XCE_CONTROLLER_PEERS\), version ' || return 1
assert_no_grep "$d/scheduler.log" 'No --peers flag' || return 1
}
add_case case_scheduler_env_list \
"scheduler: XCE_CONTROLLER_PEERS used when --peers is absent (1.2)"
case_scheduler_peers_wins() {
local d; d="$(new_scratch scheduler-peers-wins)"
start_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- \
--peers solo=localhost:7 || return 1
assert_grep "$d/scheduler.log" \
'HA cluster config: 1 candidate\(s\), identity=xce_scheduler, version ' || return 1
assert_no_grep "$d/scheduler.log" '3 candidate|from XCE_CONTROLLER_PEERS' || return 1
}
add_case case_scheduler_peers_wins \
"scheduler: explicit --peers wins over XCE_CONTROLLER_PEERS (1.1)"
case_scheduler_neither_set() {
local d; d="$(new_scratch scheduler-neither)"
start_scheduler "$d" -u XCE_CONTROLLER_PEERS -- || return 1
assert_grep "$d/scheduler.log" "$SCHED_STANDALONE_RE" || return 1
assert_no_grep "$d/scheduler.log" 'HA cluster config' || return 1
}
add_case case_scheduler_neither_set \
"scheduler: neither --peers nor the variable -> single-controller path, line names the variable (1.3, 1.8)"
case_scheduler_env_empty() {
local d; d="$(new_scratch scheduler-env-empty)"
start_scheduler "$d" "XCE_CONTROLLER_PEERS=" -- || return 1
assert_grep "$d/scheduler.log" "$SCHED_STANDALONE_RE" || return 1
assert_no_grep "$d/scheduler.log" 'HA cluster config' || return 1
}
add_case case_scheduler_env_empty \
"scheduler: empty XCE_CONTROLLER_PEERS behaves as unset (1.7, 1.8)"
case_scheduler_parse_error_source() {
local d
d="$(new_scratch scheduler-parse-env)"
run_scheduler "$d" "XCE_CONTROLLER_PEERS=a=nocolon" --
assert_rc 1 || return 1
assert_grep "$d/stderr" 'xce_scheduler: XCE_CONTROLLER_PEERS parse error' "stderr (env value)" || return 1
d="$(new_scratch scheduler-parse-flag)"
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- --peers a=nocolon
assert_rc 1 || return 1
assert_grep "$d/stderr" 'xce_scheduler: --peers parse error' "stderr (--peers value)" || return 1
assert_no_grep "$d/stderr" 'XCE_CONTROLLER_PEERS' "stderr (--peers value)" || return 1
}
add_case case_scheduler_parse_error_source \
"scheduler: parse error names --peers or XCE_CONTROLLER_PEERS (1.4)"
case_scheduler_validate_error_source() {
local d
d="$(new_scratch scheduler-port0-env)"
run_scheduler "$d" "XCE_CONTROLLER_PEERS=a=localhost:0" --
assert_rc 1 || return 1
assert_grep "$d/stderr" 'xce_scheduler: XCE_CONTROLLER_PEERS: invalid cluster config' "stderr (env value)" || return 1
d="$(new_scratch scheduler-port0-flag)"
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- --peers a=localhost:0
assert_rc 1 || return 1
assert_grep "$d/stderr" 'xce_scheduler: --peers: invalid cluster config' "stderr (--peers value)" || return 1
assert_no_grep "$d/stderr" 'XCE_CONTROLLER_PEERS' "stderr (--peers value)" || return 1
}
add_case case_scheduler_validate_error_source \
"scheduler: cluster-config validation error (port 0) names --peers or XCE_CONTROLLER_PEERS (1.4)"
case_scheduler_help_names_variable() {
local d; d="$(new_scratch scheduler-help)"
run_to_completion "$d" 10 -u XCE_CONTROLLER_PEERS "$SCHEDULER_BIN" --help
assert_rc 0 || return 1
# argp wraps help text, so join the lines before matching.
tr '\n' ' ' <"$d/stdout" | tr -s ' ' >"$d/help.txt"
assert_grep "$d/help.txt" 'XCE_CONTROLLER_PEERS' "--help output" || return 1
assert_grep "$d/help.txt" 'unset or empty' "--help output" || return 1
assert_grep "$d/help.txt" 'single-controller' "--help output" || return 1
}
add_case case_scheduler_help_names_variable \
"scheduler: --help documents XCE_CONTROLLER_PEERS and the opt-out (1.5, 1.7)"
# Guard (passes before and after 3.1): --sim returns before the peers block,
# so the variable must not reach simulation mode. The "--sim startup failed"
# line, which only the --sim branch prints, proves that branch ran.
case_scheduler_sim_ignores_variable() {
local d; d="$(new_scratch scheduler-sim)"
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- \
--sim "$d/does-not-exist.replay"
assert_rc nonzero || return 1
assert_grep "$d/stderr" 'xce_scheduler: --sim startup failed' "stderr" || return 1
assert_no_grep "$d/scheduler.log" "$SCHED_ANCHOR_RE" || return 1
assert_no_grep "$d/stderr" "$SCHED_ANCHOR_RE" "stderr" || return 1
}
add_case case_scheduler_sim_ignores_variable \
"scheduler: --sim never reaches the peers block, even with the variable set"
# ════════════════════════════════════════════════════════════════════════════
# main