test: prove native reconnect recovery

This commit is contained in:
2026-09-11 08:08:32 +00:00
parent e79f882993
commit f86abcecb5
9 changed files with 158 additions and 17 deletions
+48
View File
@@ -78,6 +78,15 @@ compose() {
docker compose -p "$project" -f "$repo_root/test/linux-server/compose.yaml" "$@"
}
remove_project_networks() {
# The project label is Docker Compose's exact resource-ownership key. This
# also reclaims legacy certgen default networks left by fixtures created
# before certgen joined the labeled native network.
for network_id in $(docker network ls --filter "label=com.docker.compose.project=$project" --quiet); do
docker network rm "$network_id" >/dev/null || fail "could not remove owned Docker network $network_id"
done
}
rvc() {
compose exec -T server /opt/rvbox/rvc --socket /run/rvbox/server.sock "$@"
}
@@ -205,6 +214,43 @@ assert_signal_term() {
fail "TERM command did not reach terminal state"
}
assert_server_restart_reconnect() {
issued=$(rvc run --background --shell cmd "$client_id" 'ping -t 127.0.0.1 >NUL' 2>&1) || fail "restart command admission failed: $issued"
issue=$(printf '%s\n' "$issued" | awk 'NR == 1 { print $1 }')
case $issue in ????????-????-7???-????-????????????) ;; *) fail "restart command returned invalid issue UUID: $issued" ;; esac
attempt=0
while [ "$attempt" -lt 30 ]; do
result=$(rvc stat "$client_id" "$issue" 2>/dev/null || true)
if printf '%s\n' "$result" | grep -q 'lifecycle=COMMAND_RUNNING'; then break; fi
attempt=$((attempt + 1)); sleep 1
done
[ "$attempt" -lt 30 ] || fail "restart command did not reach running state"
# This preserves the server state volume while replacing the actual server
# process behind nginx. A later TERM terminal result can only arrive after
# the Windows daemon has established a fresh reconciled WSS session.
compose restart server
attempt=0
while [ "$attempt" -lt 45 ]; do
if rvc stat "$client_id" >/dev/null 2>&1; then break; fi
attempt=$((attempt + 1)); sleep 1
done
[ "$attempt" -lt 45 ] || fail "server control socket did not recover after restart"
wait_client
rvc kill TERM "$client_id" "$issue" >/dev/null || fail "TERM after server restart failed"
attempt=0
while [ "$attempt" -lt 45 ]; do
result=$(rvc stat "$client_id" "$issue" 2>/dev/null || true)
if printf '%s\n' "$result" | grep -q 'lifecycle=COMMAND_TERMINATED'; then
printf '%s\n' "$result" >"$fixture_dir/server-restart-reconnect.stat"
printf 'passed server-restart-reconnect issue=%s\n' "$issue"
return 0
fi
case $result in *'lifecycle=COMMAND_FAILED'*|*'lifecycle=COMMAND_REJECTED'*|*'lifecycle=COMMAND_SUCCEEDED'*) fail "restart TERM command reached wrong terminal state: $result" ;; esac
attempt=$((attempt + 1)); sleep 1
done
fail "restart TERM command did not reach terminal state"
}
collect() {
if [ "$vm_prepared" = yes ]; then
"$repo_root/scripts/windows/test-host" collect --run-id "$run_id" || true
@@ -216,6 +262,7 @@ collect() {
clean() {
compose down --volumes --remove-orphans || true
remove_project_networks
# A reset is the isolation boundary for the next run. Do not conceal a
# failed shutdown/snapshot restore behind a successful-looking `clean`:
# callers must repair or explicitly inspect the retained VM lease first.
@@ -251,6 +298,7 @@ case $action in
wait_client
assert_stdin_close
assert_signal_term
assert_server_restart_reconnect
assert_context active-user no active-user
assert_context active-user-elevated yes active-user-elevated
"$repo_root/scripts/windows/test-host" run --run-id "$run_id" --fail-contexts ACTIVE_USER_ELEVATED