From 9c9db251bb26dd6cc2e0a7bbb2f4ca6bdde35581 Mon Sep 17 00:00:00 2001 From: alceops Date: Thu, 30 Apr 2026 13:02:55 -0400 Subject: [PATCH 1/4] Fix runtime install wait race --- tests/runtime.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/runtime.sh b/tests/runtime.sh index 69f9159..059d2bb 100755 --- a/tests/runtime.sh +++ b/tests/runtime.sh @@ -89,17 +89,27 @@ check() { fi } -# Wait for VERSION file to appear (indicates RoonServer install complete). -# Returns non-zero on timeout so set -e halts the run — a download that -# never completes is a test failure, not something to silently continue past. +# Wait for the production install to finish extracting the files that the +# runtime assertions inspect. VERSION is written before the full tarball is +# necessarily present, so using it as the only sentinel can race the launcher +# and runtime-directory checks below. +# Returns non-zero on timeout so set -e halts the run — a download/extraction +# that never completes is a test failure, not something to silently continue past. wait_for_install() { local dir="$1" local timeout="${2:-180}" local elapsed=0 - echo " Waiting for RoonServer download..." - while [ ! -f "$dir/app/RoonServer/VERSION" ]; do + local version="$dir/app/RoonServer/VERSION" + local launcher="$dir/app/RoonServer/Server/RoonServer" + local runtime="$dir/app/RoonServer/RoonDotnet" + + echo " Waiting for RoonServer download/extraction..." + while [ ! -f "$version" ] || [ ! -f "$launcher" ] || [ ! -d "$runtime" ]; do if [ "$elapsed" -ge "$timeout" ]; then - echo " wait_for_install: timed out after ${timeout}s waiting for $dir/app/RoonServer/VERSION" >&2 + echo " wait_for_install: timed out after ${timeout}s waiting for RoonServer install artifacts" >&2 + echo " VERSION: $([ -f "$version" ] && echo present || echo missing)" >&2 + echo " Launcher: $([ -f "$launcher" ] && echo present || echo missing)" >&2 + echo " Runtime: $([ -d "$runtime" ] && echo present || echo missing)" >&2 return 1 fi sleep 5 From 77947bd936bfd56d9814bc218e7eba0370d1db25 Mon Sep 17 00:00:00 2001 From: Alce Ops Date: Thu, 30 Apr 2026 13:34:37 -0400 Subject: [PATCH 2/4] Align runtime wait with install log signal --- tests/runtime.sh | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/tests/runtime.sh b/tests/runtime.sh index 059d2bb..7a44de4 100755 --- a/tests/runtime.sh +++ b/tests/runtime.sh @@ -89,27 +89,20 @@ check() { fi } -# Wait for the production install to finish extracting the files that the -# runtime assertions inspect. VERSION is written before the full tarball is -# necessarily present, so using it as the only sentinel can race the launcher -# and runtime-directory checks below. -# Returns non-zero on timeout so set -e halts the run — a download/extraction -# that never completes is a test failure, not something to silently continue past. +# Wait for VERSION file to appear (indicates RoonServer install started). +# Runtime tests that inspect the post-install state should also wait for the +# entrypoint's final Branch log line, which preserves separation between +# install-complete signaling and artifact assertions. +# Returns non-zero on timeout so set -e halts the run — a download that +# never completes is a test failure, not something to silently continue past. wait_for_install() { local dir="$1" local timeout="${2:-180}" local elapsed=0 - local version="$dir/app/RoonServer/VERSION" - local launcher="$dir/app/RoonServer/Server/RoonServer" - local runtime="$dir/app/RoonServer/RoonDotnet" - - echo " Waiting for RoonServer download/extraction..." - while [ ! -f "$version" ] || [ ! -f "$launcher" ] || [ ! -d "$runtime" ]; do + echo " Waiting for RoonServer download..." + while [ ! -f "$dir/app/RoonServer/VERSION" ]; do if [ "$elapsed" -ge "$timeout" ]; then - echo " wait_for_install: timed out after ${timeout}s waiting for RoonServer install artifacts" >&2 - echo " VERSION: $([ -f "$version" ] && echo present || echo missing)" >&2 - echo " Launcher: $([ -f "$launcher" ] && echo present || echo missing)" >&2 - echo " Runtime: $([ -d "$runtime" ] && echo present || echo missing)" >&2 + echo " wait_for_install: timed out after ${timeout}s waiting for $dir/app/RoonServer/VERSION" >&2 return 1 fi sleep 5 @@ -205,7 +198,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: production" check "VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -271,7 +264,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: earlyaccess" check "fresh EA: VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -302,7 +295,7 @@ echo " Temp dir: $ROON_DIR" # First: install production (no env var → default) start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: production" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -354,7 +347,7 @@ echo " Temp dir: $ROON_DIR" # First: install earlyaccess start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: earlyaccess" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -390,7 +383,7 @@ echo " Temp dir: $ROON_DIR" # Install production first start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: production" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -448,7 +441,7 @@ echo " Temp dir: $ROON_DIR" # Install EA first start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_log "$CONTAINER" "^Branch: earlyaccess" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -492,7 +485,6 @@ PROD_URL="https://download.roonlabs.net/builds/production/RoonServer_linuxx64.ta start_container "$CONTAINER" "$ROON_DIR" \ -e ROON_INSTALL_BRANCH=earlyaccess \ -e ROON_DOWNLOAD_URL="$PROD_URL" -wait_for_install "$ROON_DIR" wait_for_log "$CONTAINER" "^Branch: production" docker logs "$CONTAINER" > "$ROON_DIR/url-override-fresh.log" 2>&1 || true From fd2c3a03ca18994f25d416f2bb5b0b3c21de32ce Mon Sep 17 00:00:00 2001 From: alceops Date: Thu, 30 Apr 2026 14:35:22 -0400 Subject: [PATCH 3/4] Simplify runtime install wait to completion log --- tests/runtime.sh | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/tests/runtime.sh b/tests/runtime.sh index 7a44de4..cd0fb75 100755 --- a/tests/runtime.sh +++ b/tests/runtime.sh @@ -89,26 +89,14 @@ check() { fi } -# Wait for VERSION file to appear (indicates RoonServer install started). -# Runtime tests that inspect the post-install state should also wait for the -# entrypoint's final Branch log line, which preserves separation between -# install-complete signaling and artifact assertions. +# Wait for RoonServer install to complete. # Returns non-zero on timeout so set -e halts the run — a download that # never completes is a test failure, not something to silently continue past. wait_for_install() { local dir="$1" local timeout="${2:-180}" - local elapsed=0 - echo " Waiting for RoonServer download..." - while [ ! -f "$dir/app/RoonServer/VERSION" ]; do - if [ "$elapsed" -ge "$timeout" ]; then - echo " wait_for_install: timed out after ${timeout}s waiting for $dir/app/RoonServer/VERSION" >&2 - return 1 - fi - sleep 5 - elapsed=$((elapsed + 5)) - echo " ... ${elapsed}s" - done + echo " Waiting for RoonServer install to complete..." + wait_for_log "$CONTAINER" "RoonServer installed successfully" "$timeout" } # Wait for a specific branch to appear in the VERSION file's last line. @@ -198,7 +186,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -wait_for_log "$CONTAINER" "^Branch: production" +wait_for_install "$ROON_DIR" check "VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -264,7 +252,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_log "$CONTAINER" "^Branch: earlyaccess" +wait_for_install "$ROON_DIR" check "fresh EA: VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -295,7 +283,7 @@ echo " Temp dir: $ROON_DIR" # First: install production (no env var → default) start_container "$CONTAINER" "$ROON_DIR" -wait_for_log "$CONTAINER" "^Branch: production" +wait_for_install "$ROON_DIR" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -347,7 +335,7 @@ echo " Temp dir: $ROON_DIR" # First: install earlyaccess start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_log "$CONTAINER" "^Branch: earlyaccess" +wait_for_install "$ROON_DIR" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -383,7 +371,7 @@ echo " Temp dir: $ROON_DIR" # Install production first start_container "$CONTAINER" "$ROON_DIR" -wait_for_log "$CONTAINER" "^Branch: production" +wait_for_install "$ROON_DIR" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -441,7 +429,7 @@ echo " Temp dir: $ROON_DIR" # Install EA first start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_log "$CONTAINER" "^Branch: earlyaccess" +wait_for_install "$ROON_DIR" docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -485,6 +473,7 @@ PROD_URL="https://download.roonlabs.net/builds/production/RoonServer_linuxx64.ta start_container "$CONTAINER" "$ROON_DIR" \ -e ROON_INSTALL_BRANCH=earlyaccess \ -e ROON_DOWNLOAD_URL="$PROD_URL" +wait_for_install "$ROON_DIR" wait_for_log "$CONTAINER" "^Branch: production" docker logs "$CONTAINER" > "$ROON_DIR/url-override-fresh.log" 2>&1 || true From da9ec7cd3fa778bf69a5392fdf95351f473441f4 Mon Sep 17 00:00:00 2001 From: Stephen Shaw Date: Wed, 13 May 2026 10:59:23 -0600 Subject: [PATCH 4/4] tests: drop unused dir parameter from wait_for_install Address Copilot review feedback. After switching the body to a log-based wait, the dir positional was bound but never read, and the function silently relied on the outer-scope CONTAINER. Removing the parameter makes the signature truthful and updates all seven call sites. --- tests/runtime.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/runtime.sh b/tests/runtime.sh index cd0fb75..4dc4438 100755 --- a/tests/runtime.sh +++ b/tests/runtime.sh @@ -93,8 +93,7 @@ check() { # Returns non-zero on timeout so set -e halts the run — a download that # never completes is a test failure, not something to silently continue past. wait_for_install() { - local dir="$1" - local timeout="${2:-180}" + local timeout="${1:-180}" echo " Waiting for RoonServer install to complete..." wait_for_log "$CONTAINER" "RoonServer installed successfully" "$timeout" } @@ -186,7 +185,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_install check "VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -252,7 +251,7 @@ echo " Temp dir: $ROON_DIR" start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_install check "fresh EA: VERSION file created" \ test -f "$ROON_DIR/app/RoonServer/VERSION" @@ -283,7 +282,7 @@ echo " Temp dir: $ROON_DIR" # First: install production (no env var → default) start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_install docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -335,7 +334,7 @@ echo " Temp dir: $ROON_DIR" # First: install earlyaccess start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_install docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -371,7 +370,7 @@ echo " Temp dir: $ROON_DIR" # Install production first start_container "$CONTAINER" "$ROON_DIR" -wait_for_install "$ROON_DIR" +wait_for_install docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -429,7 +428,7 @@ echo " Temp dir: $ROON_DIR" # Install EA first start_container "$CONTAINER" "$ROON_DIR" -e ROON_INSTALL_BRANCH=earlyaccess -wait_for_install "$ROON_DIR" +wait_for_install docker stop -t 10 "$CONTAINER" 2>/dev/null || true docker rm -f "$CONTAINER" 2>/dev/null || true @@ -473,7 +472,7 @@ PROD_URL="https://download.roonlabs.net/builds/production/RoonServer_linuxx64.ta start_container "$CONTAINER" "$ROON_DIR" \ -e ROON_INSTALL_BRANCH=earlyaccess \ -e ROON_DOWNLOAD_URL="$PROD_URL" -wait_for_install "$ROON_DIR" +wait_for_install wait_for_log "$CONTAINER" "^Branch: production" docker logs "$CONTAINER" > "$ROON_DIR/url-override-fresh.log" 2>&1 || true