fix: address PR review feedback on per-backend route tests

T1 of every per-backend test file asserted 200 with the api Procfile body for a request that lacks --strip-prefix, but without the strip the upstream sees /api/v0/Procfile and python's http.server returns 404; the retry loop polled on status only and accepted web's catch-all 200 first. The assertion now expects 404, which is the right signal that the route reaches the api process. T3 was rewritten to follow T2's two-step pattern (404 without strip, then 200 with strip) so the route is proven applied before checking content. T4 of proxy-route-nginx.bats relaxes the WebSocket header assertions to allow more than one occurrence because the headers correctly appear in both the route location block and the existing location / block. Backticks in fn-traefik-host-rule and fn-traefik-route-labels are now triple-escaped so they survive the docker-args eval path that turns the labels into a docker run invocation, matching the existing convention in docker-args-process-deploy. The label-based backend test files also echo the ps:rebuild output now so future failures of that step surface in the CI logs instead of silently exiting non-zero.
This commit is contained in:
Jose Diaz-Gonzalez
2026-06-01 18:44:34 -04:00
parent 4a550fe4b9
commit 40e13b5f13
7 changed files with 133 additions and 14 deletions

View File

@@ -23,7 +23,8 @@ fn-traefik-route-labels() {
service_name="${APP}-${route_proc}-${route_slug}"
path_len="${#route_path}"
local rule="PathPrefix(\`${route_path}\`)"
# Triple-backslash for the same eval-survival reason as fn-traefik-host-rule.
local rule="PathPrefix(\\\`${route_path}\\\`)"
if [[ -n "$host_rule" ]]; then
rule="(${host_rule}) && ${rule}"
fi
@@ -75,12 +76,17 @@ fn-traefik-host-rule() {
return
fi
# Backticks must be double-escaped so they survive the docker-args eval
# path. A single backslash leaves a bare backtick in the final string,
# which then runs as a command substitution at eval time and breaks the
# docker run invocation. Triple-backslash matches the existing emission
# convention used by docker-args-process-deploy.
for domain in $(echo "$app_domains" | xargs); do
if [[ -z "$result" ]]; then
result="Host(\`${domain}\`)"
result="Host(\\\`${domain}\\\`)"
continue
fi
result="${result} || Host(\`${domain}\`)"
result="${result} || Host(\\\`${domain}\\\`)"
done
echo "$result"
}

View File

@@ -33,9 +33,14 @@ teardown() {
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile
# which python's http.server returns 404 for. A 404 here proves the route
# reaches api - web's catch-all would have returned 200.
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:caddy) --strip-prefix toggles upstream path visibility" {
@@ -48,12 +53,16 @@ teardown() {
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
}
@@ -65,15 +74,28 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Set without --strip-prefix first; 404 proves the labels attached.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
run /bin/bash -c "dokku proxy:route:remove $TEST_APP /api/v0"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSso /tmp/route-removed-body "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile"

View File

@@ -40,7 +40,10 @@ teardown() {
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile
# which python's http.server returns 404 for. 404 proves the route reaches
# api (web's catch-all would have returned 200).
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:k3s-nginx) --strip-prefix renders rewrite-target Ingress and strips upstream path" {
@@ -59,6 +62,12 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Set without strip first; the 404 proves the route reached api before we
# assert the strip-prefix HTTP behavior.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
@@ -89,6 +98,12 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Verify the route reaches api first (404 proves routing) before checking
# that strip applied (200 with Procfile content).
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"

View File

@@ -40,7 +40,10 @@ teardown() {
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile
# which python's http.server returns 404 for. 404 proves the route reaches
# api (web's catch-all would have returned 200).
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:k3s-traefik) --strip-prefix renders stripPrefix Middleware and strips upstream path" {
@@ -59,6 +62,12 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Set without strip first; the 404 proves the route reached api before we
# assert the strip-prefix HTTP behavior.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
@@ -89,6 +98,12 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Verify the route reaches api first (404 proves routing) before checking
# that strip applied (200 with Procfile content).
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"

View File

@@ -29,7 +29,11 @@ teardown() {
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile.
# api (python's http.server) does not have that file on disk and returns
# 404. A 404 here proves the route reaches api - web's catch-all would
# have returned 200 instead.
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:nginx) --strip-prefix toggles upstream path visibility" {
@@ -65,6 +69,14 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# First set the route without --strip-prefix so a 404 from api uniquely
# identifies that the route reached api (avoids racing with web's catch-all
# 200 during the brief window before nginx fully reloads).
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
# Now switch the route to --strip-prefix and assert api serves the Procfile.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
@@ -72,8 +84,8 @@ teardown() {
run /bin/bash -c "dokku proxy:route:remove $TEST_APP /api/v0"
assert_success
# Web does not serve /api/v0/Procfile; we just assert it is no longer the
# api-served Procfile content.
# After removal, /api/v0/Procfile no longer reaches api - it falls through
# to web's catch-all. Assert the response is no longer api's Procfile body.
run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSso /tmp/route-removed-body "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile"
run /bin/bash -c "grep -c 'python3 -m http.server' /tmp/route-removed-body || true"
assert_output "0"
@@ -92,9 +104,12 @@ teardown() {
echo "status: $status"
assert_success
assert_output_contains "location /api/v0"
assert_output_contains "proxy_http_version 1.1"
assert_output_contains "proxy_set_header Upgrade \$http_upgrade"
assert_output_contains "proxy_set_header Connection \$http_connection"
# These headers appear in both the route's location block AND the existing
# location / block, so allow >= 1 occurrence (count = -1) rather than the
# default exact-count-of-1.
assert_output_contains "proxy_http_version 1.1" -1
assert_output_contains "proxy_set_header Upgrade \$http_upgrade" -1
assert_output_contains "proxy_set_header Connection \$http_connection" -1
}
add_api_process_callback() {

View File

@@ -33,9 +33,14 @@ teardown() {
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile
# which python's http.server returns 404 for. A 404 here proves the route
# reaches api - web's catch-all would have returned 200.
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:openresty) --strip-prefix toggles upstream path visibility" {
@@ -48,12 +53,16 @@ teardown() {
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
}
@@ -65,15 +74,28 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Set without --strip-prefix first; 404 proves the labels attached.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
run /bin/bash -c "dokku proxy:route:remove $TEST_APP /api/v0"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSso /tmp/route-removed-body "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile"

View File

@@ -35,9 +35,14 @@ teardown() {
# Routes are applied via container labels - rebuild so the api container
# restarts with the new labels attached.
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
# Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile
# which python's http.server returns 404 for. A 404 here proves the route
# reaches api - web's catch-all would have returned 200.
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
}
@test "(proxy-route:traefik) --strip-prefix toggles upstream path visibility" {
@@ -50,12 +55,16 @@ teardown() {
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
}
@@ -67,15 +76,30 @@ teardown() {
run /bin/bash -c "dokku ps:scale $TEST_APP web=1 api=1"
assert_success
# Set the route without --strip-prefix first; a 404 from api proves the
# labels attached and traefik is routing correctly.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "" "404"
# Switch to --strip-prefix and verify api now serves the Procfile.
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0 --port 5001 --strip-prefix"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server"
run /bin/bash -c "dokku proxy:route:remove $TEST_APP /api/v0"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSso /tmp/route-removed-body "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile"