diff --git a/tests/test_addon_metadata.py b/tests/test_addon_metadata.py index 4875ad2..a6432be 100644 --- a/tests/test_addon_metadata.py +++ b/tests/test_addon_metadata.py @@ -151,6 +151,15 @@ def test_runtime_copies_options_without_a_host_bind_mount() -> None: assert "--mount" not in runtime_test +def test_runtime_probes_service_inside_container_network_namespace() -> None: + runtime_test = (ROOT / "tests/test_runtime.sh").read_text(encoding="utf-8") + assert 'probe_root "$container"' in runtime_test + assert 'post_invalid_worker "$first_container"' in runtime_test + assert 'assert_8080_loopback_mapping "$first_container"' in runtime_test + assert 'assert_8080_loopback_mapping "$second_container"' in runtime_test + assert 'f"http://127.0.0.1:{sys.argv[1]}/"' not in runtime_test + + def test_ci_builds_and_loads_only_the_amd64_test_image() -> None: workflow = (ROOT / ".gitea/workflows/ci.yml").read_text(encoding="utf-8") parsed = yaml.safe_load(workflow) @@ -253,9 +262,10 @@ def test_runtime_requires_process_baseline_after_cdp_close_and_zero_stopped_pid( baseline = ( f'{prefix}_baseline="$(capture_process_baseline "{container}")"' ) - ready_index = runtime_test.index( - f'wait_ready "{container}" "${prefix}_port"' + mapping_index = runtime_test.index( + f'assert_8080_loopback_mapping "{container}"' ) + ready_index = runtime_test.index(f'wait_ready "{container}"') baseline_index = runtime_test.index(baseline) close_index = runtime_test.index( f'probe_and_close_cdp "{container}"', baseline_index @@ -264,7 +274,7 @@ def test_runtime_requires_process_baseline_after_cdp_close_and_zero_stopped_pid( f'assert_processes_return_to_baseline "{container}" "${prefix}_baseline"', close_index, ) - assert ready_index < baseline_index < close_index < return_index + assert mapping_index < ready_index < baseline_index < close_index < return_index assert "{{.State.Pid}}" in runtime_test assert '[ "$state" = "exited 0 0" ]' in runtime_test diff --git a/tests/test_runtime.sh b/tests/test_runtime.sh index 3242cb3..3b6b08e 100755 --- a/tests/test_runtime.sh +++ b/tests/test_runtime.sh @@ -66,22 +66,23 @@ start_container() { docker start "$container" >/dev/null } -host_port() { +assert_8080_loopback_mapping() { local container="$1" local mapping mapping="$(docker port "$container" 8080/tcp)" - [ -n "$mapping" ] || fail "container 8080 has no host mapping" - printf '%s\n' "${mapping##*:}" + case "$mapping" in + 127.0.0.1:[0-9]*) ;; + *) fail "$container 8080 mapping is '$mapping', want 127.0.0.1:" ;; + esac } probe_root() { - local port="$1" - python3 - "$port" <<'PY' -import sys + local container="$1" + docker exec -i "$container" python3 - <<'PY' import urllib.request opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) -with opener.open(f"http://127.0.0.1:{sys.argv[1]}/", timeout=2) as response: +with opener.open("http://127.0.0.1:8080/", timeout=2) as response: if response.status != 200: raise SystemExit(f"root status {response.status}") response.read() @@ -90,7 +91,6 @@ PY wait_ready() { local container="$1" - local port="$2" local deadline=$((SECONDS + 90)) while (( SECONDS < deadline )); do if [ "$(docker inspect --format '{{.State.Running}}' "$container")" != "true" ]; then @@ -98,7 +98,7 @@ wait_ready() { fail "$container exited during readiness" fi if docker logs "$container" 2>&1 | grep -Fq "Stelloauth listening on 0.0.0.0:8080"; then - if probe_root "$port" >/dev/null 2>&1; then + if probe_root "$container" >/dev/null 2>&1; then return fi fi @@ -265,16 +265,14 @@ PY } post_invalid_worker() { - local port="$1" + local container="$1" local response_artifact="$2" - python3 - "$port" "$response_artifact" <<'PY' + docker exec -i "$container" python3 - > "$response_artifact" <<'PY' import json -import pathlib import sys import urllib.error import urllib.request -port, artifact = sys.argv[1:] body = { "url": ( "https://example.invalid/am/oauth2/authorize" @@ -292,7 +290,7 @@ body = { "refresh_token": "SENTINEL_REFRESH_TOKEN_4e73", } request = urllib.request.Request( - f"http://127.0.0.1:{port}/worker", + "http://127.0.0.1:8080/worker", data=json.dumps(body, separators=(",", ":")).encode(), headers={"Content-Type": "application/json"}, method="POST", @@ -307,7 +305,7 @@ except urllib.error.HTTPError as error: response_body = error.read() if status != 400: raise SystemExit(f"invalid worker status {status}, want 400") -pathlib.Path(artifact).write_bytes(response_body) +sys.stdout.buffer.write(response_body) PY } @@ -374,8 +372,8 @@ if [ "${SKIP_BUILD:-0}" != "1" ]; then fi start_container "$first_container" -first_port="$(host_port "$first_container")" -wait_ready "$first_container" "$first_port" +assert_8080_loopback_mapping "$first_container" +wait_ready "$first_container" first_baseline="$(capture_process_baseline "$first_container")" assert_no_9222_mapping "$first_container" assert_loopback_cdp_listener \ @@ -384,14 +382,14 @@ assert_loopback_cdp_listener \ "${artifacts_dir}/runtime-proc-net-tcp6.txt" probe_and_close_cdp "$first_container" assert_processes_return_to_baseline "$first_container" "$first_baseline" -post_invalid_worker "$first_port" "${artifacts_dir}/runtime-invalid-worker-response.json" +post_invalid_worker "$first_container" "${artifacts_dir}/runtime-invalid-worker-response.json" scan_logs "$first_container" stop_and_assert "$first_container" "${artifacts_dir}/runtime-first-stop.txt" scan_logs "$first_container" start_container "$second_container" -second_port="$(host_port "$second_container")" -wait_ready "$second_container" "$second_port" +assert_8080_loopback_mapping "$second_container" +wait_ready "$second_container" second_baseline="$(capture_process_baseline "$second_container")" assert_no_9222_mapping "$second_container" assert_loopback_cdp_listener \