test(integration): add Suite 7 for filter_aaaa + SUITES env filter
Suite 7 exercises the full pipeline end-to-end: A resolves, AAAA returns NODATA, local [[zones]] AAAA bypasses the filter, and HTTPS ipv6hint is stripped from a real cloudflare.com response. A second config run with the flag unset guards against network-failure false-positives. SUITES=N (comma list) runs a subset, e.g. `SUITES=7 bash tests/integration.sh` skips suites 1-6 for fast iteration.
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Integration test suite for Numa
|
# Integration test suite for Numa
|
||||||
# Runs a test instance on port 5354, validates all features, exits with status.
|
# Runs a test instance on port 5354, validates all features, exits with status.
|
||||||
# Usage: ./tests/integration.sh [release|debug]
|
# Usage:
|
||||||
|
# ./tests/integration.sh [release|debug] # all suites
|
||||||
|
# SUITES=7 ./tests/integration.sh # only Suite 7
|
||||||
|
# SUITES=1,3,7 ./tests/integration.sh # Suites 1, 3, and 7
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -14,6 +17,14 @@ LOG="/tmp/numa-integration-test.log"
|
|||||||
PASSED=0
|
PASSED=0
|
||||||
FAILED=0
|
FAILED=0
|
||||||
|
|
||||||
|
# Suite filter: empty runs all; comma list runs a subset.
|
||||||
|
SUITES="${SUITES:-}"
|
||||||
|
should_run_suite() {
|
||||||
|
[ -z "$SUITES" ] && return 0
|
||||||
|
case ",$SUITES," in *",$1,"*) return 0;; esac
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
GREEN="\033[32m"
|
GREEN="\033[32m"
|
||||||
RED="\033[31m"
|
RED="\033[31m"
|
||||||
@@ -166,6 +177,7 @@ CONF
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ---- Suite 1: Recursive mode + DNSSEC ----
|
# ---- Suite 1: Recursive mode + DNSSEC ----
|
||||||
|
if should_run_suite 1; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 1: Recursive + DNSSEC + Blocking ║"
|
echo "║ Suite 1: Recursive + DNSSEC + Blocking ║"
|
||||||
@@ -234,7 +246,10 @@ kill "$NUMA_PID" 2>/dev/null || true
|
|||||||
wait "$NUMA_PID" 2>/dev/null || true
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
fi # end Suite 1
|
||||||
|
|
||||||
# ---- Suite 2: Forward mode (backward compat) ----
|
# ---- Suite 2: Forward mode (backward compat) ----
|
||||||
|
if should_run_suite 2; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 2: Forward (DoH) + Blocking ║"
|
echo "║ Suite 2: Forward (DoH) + Blocking ║"
|
||||||
@@ -261,7 +276,10 @@ enabled = true
|
|||||||
enabled = false
|
enabled = false
|
||||||
"
|
"
|
||||||
|
|
||||||
|
fi # end Suite 2
|
||||||
|
|
||||||
# ---- Suite 3: Forward UDP (plain, no DoH) ----
|
# ---- Suite 3: Forward UDP (plain, no DoH) ----
|
||||||
|
if should_run_suite 3; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 3: Forward (UDP) + No Blocking ║"
|
echo "║ Suite 3: Forward (UDP) + No Blocking ║"
|
||||||
@@ -307,7 +325,10 @@ kill "$NUMA_PID" 2>/dev/null || true
|
|||||||
wait "$NUMA_PID" 2>/dev/null || true
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
fi # end Suite 3
|
||||||
|
|
||||||
# ---- Suite 4: Local zones + Overrides API ----
|
# ---- Suite 4: Local zones + Overrides API ----
|
||||||
|
if should_run_suite 4; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 4: Local Zones + Overrides API ║"
|
echo "║ Suite 4: Local Zones + Overrides API ║"
|
||||||
@@ -416,7 +437,10 @@ kill "$NUMA_PID" 2>/dev/null || true
|
|||||||
wait "$NUMA_PID" 2>/dev/null || true
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
fi # end Suite 4
|
||||||
|
|
||||||
# ---- Suite 5: DNS-over-TLS (RFC 7858) ----
|
# ---- Suite 5: DNS-over-TLS (RFC 7858) ----
|
||||||
|
if should_run_suite 5; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 5: DNS-over-TLS (RFC 7858) ║"
|
echo "║ Suite 5: DNS-over-TLS (RFC 7858) ║"
|
||||||
@@ -538,7 +562,10 @@ CONF
|
|||||||
fi
|
fi
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
fi # end Suite 5
|
||||||
|
|
||||||
# ---- Suite 6: Proxy + DoT coexistence ----
|
# ---- Suite 6: Proxy + DoT coexistence ----
|
||||||
|
if should_run_suite 6; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════════╗"
|
||||||
echo "║ Suite 6: Proxy + DoT Coexistence ║"
|
echo "║ Suite 6: Proxy + DoT Coexistence ║"
|
||||||
@@ -698,6 +725,135 @@ CONF
|
|||||||
rm -rf "$NUMA_DATA"
|
rm -rf "$NUMA_DATA"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
fi # end Suite 6
|
||||||
|
|
||||||
|
# ---- Suite 7: filter_aaaa (IPv4-only networks) ----
|
||||||
|
if should_run_suite 7; then
|
||||||
|
echo ""
|
||||||
|
echo "╔══════════════════════════════════════════╗"
|
||||||
|
echo "║ Suite 7: filter_aaaa ║"
|
||||||
|
echo "╚══════════════════════════════════════════╝"
|
||||||
|
|
||||||
|
# Config A — filter on, with a local AAAA zone to prove local data bypass.
|
||||||
|
cat > "$CONFIG" << 'CONF'
|
||||||
|
[server]
|
||||||
|
bind_addr = "127.0.0.1:5354"
|
||||||
|
api_port = 5381
|
||||||
|
filter_aaaa = true
|
||||||
|
|
||||||
|
[upstream]
|
||||||
|
mode = "forward"
|
||||||
|
address = "9.9.9.9"
|
||||||
|
port = 53
|
||||||
|
|
||||||
|
[cache]
|
||||||
|
max_entries = 10000
|
||||||
|
|
||||||
|
[blocking]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
[proxy]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
[[zones]]
|
||||||
|
domain = "v6.test"
|
||||||
|
record_type = "AAAA"
|
||||||
|
value = "2001:db8::1"
|
||||||
|
ttl = 60
|
||||||
|
CONF
|
||||||
|
|
||||||
|
RUST_LOG=info "$BINARY" "$CONFIG" > "$LOG" 2>&1 &
|
||||||
|
NUMA_PID=$!
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
DIG="dig @127.0.0.1 -p $PORT +time=5 +tries=1"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== filter_aaaa = true ==="
|
||||||
|
|
||||||
|
# A queries must be untouched.
|
||||||
|
check "A record resolves under filter_aaaa" \
|
||||||
|
"." \
|
||||||
|
"$($DIG google.com A +short | head -1)"
|
||||||
|
|
||||||
|
# AAAA must be NOERROR (NODATA), not NXDOMAIN, not SERVFAIL.
|
||||||
|
check "AAAA returns NOERROR (not NXDOMAIN)" \
|
||||||
|
"status: NOERROR" \
|
||||||
|
"$($DIG google.com AAAA 2>&1 | grep 'status:')"
|
||||||
|
|
||||||
|
check "AAAA returns zero answers (NODATA shape)" \
|
||||||
|
"ANSWER: 0" \
|
||||||
|
"$($DIG google.com AAAA 2>&1 | grep -oE 'ANSWER: [0-9]+' | head -1)"
|
||||||
|
|
||||||
|
# Local zone AAAA must survive the filter (PR claim: local data bypasses).
|
||||||
|
check "Local [[zones]] AAAA bypasses filter" \
|
||||||
|
"2001:db8::1" \
|
||||||
|
"$($DIG v6.test AAAA +short)"
|
||||||
|
|
||||||
|
# HTTPS RR: ipv6hint (SvcParamKey 6) must be stripped. Query as `type65`
|
||||||
|
# because dig 9.10.6 (macOS) misparses `HTTPS` as a domain name; `type65`
|
||||||
|
# works on both 9.10.6 and 9.18. Assert on the raw rdata hex (RFC 3597
|
||||||
|
# generic format), since dig 9.10.6 doesn't pretty-print HTTPS params.
|
||||||
|
# cloudflare.com's ipv6hint values sit under the 2606:4700 prefix —
|
||||||
|
# checking that `26064700` is absent from the rdata hex is a precise,
|
||||||
|
# upstream-stable signal that the TLV was stripped.
|
||||||
|
HTTPS_OUT=$($DIG cloudflare.com type65 2>&1)
|
||||||
|
if echo "$HTTPS_OUT" | grep -qE "cloudflare\.com\..*IN[[:space:]]+TYPE65"; then
|
||||||
|
HTTPS_HEX=$(echo "$HTTPS_OUT" | grep -A5 "IN[[:space:]]*TYPE65" | tr -d " \t\n")
|
||||||
|
if echo "$HTTPS_HEX" | grep -qi "26064700"; then
|
||||||
|
check "HTTPS ipv6hint stripped (2606:4700 absent from rdata)" "absent" "present"
|
||||||
|
else
|
||||||
|
check "HTTPS ipv6hint stripped (2606:4700 absent from rdata)" "absent" "absent"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Upstream didn't return an HTTPS record — skip rather than false-pass.
|
||||||
|
printf " ${DIM}~ HTTPS ipv6hint stripped (skipped: no HTTPS RR returned by upstream)${RESET}\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
kill "$NUMA_PID" 2>/dev/null || true
|
||||||
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Config B — filter off. Regression guard: prove AAAA answers come back
|
||||||
|
# when the flag isn't set, so a network failure in Config A can't silently
|
||||||
|
# pass as "filter working".
|
||||||
|
cat > "$CONFIG" << 'CONF'
|
||||||
|
[server]
|
||||||
|
bind_addr = "127.0.0.1:5354"
|
||||||
|
api_port = 5381
|
||||||
|
|
||||||
|
[upstream]
|
||||||
|
mode = "forward"
|
||||||
|
address = "9.9.9.9"
|
||||||
|
port = 53
|
||||||
|
|
||||||
|
[cache]
|
||||||
|
max_entries = 10000
|
||||||
|
|
||||||
|
[blocking]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
[proxy]
|
||||||
|
enabled = false
|
||||||
|
CONF
|
||||||
|
|
||||||
|
RUST_LOG=info "$BINARY" "$CONFIG" > "$LOG" 2>&1 &
|
||||||
|
NUMA_PID=$!
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== filter_aaaa unset (regression guard) ==="
|
||||||
|
|
||||||
|
check "AAAA returns real answers with filter off" \
|
||||||
|
":" \
|
||||||
|
"$($DIG google.com AAAA +short | head -1)"
|
||||||
|
|
||||||
|
kill "$NUMA_PID" 2>/dev/null || true
|
||||||
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
fi # end Suite 7
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
echo ""
|
echo ""
|
||||||
TOTAL=$((PASSED + FAILED))
|
TOTAL=$((PASSED + FAILED))
|
||||||
|
|||||||
Reference in New Issue
Block a user