diff --git a/tests/unit/proxy-route-caddy.bats b/tests/unit/proxy-route-caddy.bats index 609914f6a..cfe82c9c1 100644 --- a/tests/unit/proxy-route-caddy.bats +++ b/tests/unit/proxy-route-caddy.bats @@ -92,14 +92,32 @@ teardown() { 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" + echo "output: $output" + echo "status: $status" assert_success + + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + 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" - run /bin/bash -c "grep -c 'python3 -m http.server' /tmp/route-removed-body || true" + local body="" + for attempt in $(seq 1 30); do + run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSs "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile" + body="$output" + if ! grep -q 'python3 -m http.server' <<<"$body"; then + break + fi + sleep 1 + done + echo "final body attempt $attempt: $body" + run /bin/bash -c "grep -c 'python3 -m http.server' <<<\"$body\" || true" assert_output "0" } diff --git a/tests/unit/proxy-route-k3s-nginx.bats b/tests/unit/proxy-route-k3s-nginx.bats index 6dc750c88..ddcda9d0b 100644 --- a/tests/unit/proxy-route-k3s-nginx.bats +++ b/tests/unit/proxy-route-k3s-nginx.bats @@ -109,14 +109,30 @@ teardown() { 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 - - # The rewrite-target Ingress should be gone after removal. - run /bin/bash -c "kubectl get ingress -o json | jq -r '[.items[] | select(.metadata.annotations[\"nginx.ingress.kubernetes.io/rewrite-target\"] != null)] | length'" echo "output: $output" echo "status: $status" assert_success - assert_output "0" + + # Confirm storage was cleared before checking cluster state. + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + + # The rewrite-target Ingress should be gone after removal. Retry briefly + # in case the chart re-render hasn't settled. + local count="1" + for attempt in $(seq 1 30); do + run /bin/bash -c "kubectl get ingress -o json | jq -r '[.items[] | select(.metadata.annotations[\"nginx.ingress.kubernetes.io/rewrite-target\"] != null)] | length'" + count="$output" + if [[ "$count" == "0" ]]; then + break + fi + sleep 1 + done + echo "final ingress count after $attempt attempts: $count" + assert_equal "$count" "0" } add_api_process_callback() { diff --git a/tests/unit/proxy-route-k3s-traefik.bats b/tests/unit/proxy-route-k3s-traefik.bats index 76188dbbe..89d6e0243 100644 --- a/tests/unit/proxy-route-k3s-traefik.bats +++ b/tests/unit/proxy-route-k3s-traefik.bats @@ -109,13 +109,30 @@ teardown() { 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 "kubectl get middleware.traefik.io -o json | jq -r '[.items[] | select(.spec.stripPrefix != null)] | length'" echo "output: $output" echo "status: $status" assert_success - assert_output "0" + + # Confirm storage was cleared before checking cluster state. + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + + # The stripPrefix Middleware should be gone after removal. Retry briefly + # in case the chart re-render hasn't settled. + local count="1" + for attempt in $(seq 1 30); do + run /bin/bash -c "kubectl get middleware.traefik.io -o json | jq -r '[.items[] | select(.spec.stripPrefix != null)] | length'" + count="$output" + if [[ "$count" == "0" ]]; then + break + fi + sleep 1 + done + echo "final middleware count after $attempt attempts: $count" + assert_equal "$count" "0" } add_api_process_callback() { diff --git a/tests/unit/proxy-route-nginx.bats b/tests/unit/proxy-route-nginx.bats index b8961358e..5bad68a87 100644 --- a/tests/unit/proxy-route-nginx.bats +++ b/tests/unit/proxy-route-nginx.bats @@ -82,12 +82,35 @@ teardown() { 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" + echo "output: $output" + echo "status: $status" assert_success - # 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" + # Confirm storage was actually mutated; a CommandRouteRemove that returns + # changed=false silently skips BuildConfig and leaves nginx with the old + # route block. + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + + # nginx reload races with the curl after route removal: both api and web + # return 200 for /api/v0/Procfile so the polling loop in + # assert_http_localhost_response_contains exits on status alone before + # nginx picks up the new config. Hand-roll a retry that polls the BODY + # until it no longer contains api's marker. + local body="" + for attempt in $(seq 1 30); do + run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSs "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile" + body="$output" + if ! grep -q 'python3 -m http.server' <<<"$body"; then + break + fi + sleep 1 + done + echo "final body attempt $attempt: $body" + run /bin/bash -c "grep -c 'python3 -m http.server' <<<\"$body\" || true" assert_output "0" } diff --git a/tests/unit/proxy-route-openresty.bats b/tests/unit/proxy-route-openresty.bats index 03ab980cb..3053542ff 100644 --- a/tests/unit/proxy-route-openresty.bats +++ b/tests/unit/proxy-route-openresty.bats @@ -92,14 +92,32 @@ teardown() { 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" + echo "output: $output" + echo "status: $status" assert_success + + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + 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" - run /bin/bash -c "grep -c 'python3 -m http.server' /tmp/route-removed-body || true" + local body="" + for attempt in $(seq 1 30); do + run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSs "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile" + body="$output" + if ! grep -q 'python3 -m http.server' <<<"$body"; then + break + fi + sleep 1 + done + echo "final body attempt $attempt: $body" + run /bin/bash -c "grep -c 'python3 -m http.server' <<<\"$body\" || true" assert_output "0" } diff --git a/tests/unit/proxy-route-traefik.bats b/tests/unit/proxy-route-traefik.bats index 25abd2fdd..cb5f0e0ea 100644 --- a/tests/unit/proxy-route-traefik.bats +++ b/tests/unit/proxy-route-traefik.bats @@ -96,14 +96,36 @@ teardown() { 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" + echo "output: $output" + echo "status: $status" assert_success + + # Confirm storage was actually mutated before doing the slow rebuild. + run /bin/bash -c "dokku proxy:route:report $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "(none)" + 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" - run /bin/bash -c "grep -c 'python3 -m http.server' /tmp/route-removed-body || true" + # After ps:rebuild, traefik recreates the api container without the route + # labels, but there is still a race with traefik picking up the new state. + # Hand-roll a retry that polls the BODY until api's marker is gone. + local body="" + for attempt in $(seq 1 30); do + run curl --connect-to "${TEST_APP}.${DOKKU_DOMAIN}:80:localhost:80" -kSs "http://${TEST_APP}.${DOKKU_DOMAIN}:80/api/v0/Procfile" + body="$output" + if ! grep -q 'python3 -m http.server' <<<"$body"; then + break + fi + sleep 1 + done + echo "final body attempt $attempt: $body" + run /bin/bash -c "grep -c 'python3 -m http.server' <<<\"$body\" || true" assert_output "0" }