-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathtest.sh
More file actions
291 lines (245 loc) · 9.45 KB
/
test.sh
File metadata and controls
291 lines (245 loc) · 9.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/common.sh
source "${SCRIPT_DIR}/scripts/common.sh"
CONFIGURATION="$(normalize_configuration "${CONFIGURATION:-Release}")"
TEST_MODE="${TEST_MODE:-auto}"
DOTNET_TEST_ARGS=()
ORIGINAL_IPTABLES_TARGET=""
ORIGINAL_IP6TABLES_TARGET=""
IPTABLES_BACKEND="${IPTABLES_BACKEND:-legacy}"
RUN_UNSTABLE_SYSTEM_TESTS="${RUN_UNSTABLE_SYSTEM_TESTS:-0}"
has_explicit_test_filter() {
local arg
for arg in "${DOTNET_TEST_ARGS[@]}"; do
if [[ "$arg" == "--filter" || "$arg" == --filter=* ]]; then
return 0
fi
done
return 1
}
normalize_iptables_backend() {
local value="${1:-legacy}"
case "${value,,}" in
legacy|nft|current)
printf '%s\n' "${value,,}"
;;
*)
die "Unsupported iptables backend '${value}'. Expected one of: legacy, nft, current."
;;
esac
}
resolve_command_path() {
local command_path
command_path="$(command -v "$1" 2>/dev/null)" || return 1
if command_exists readlink; then
readlink -f "$command_path" 2>/dev/null || printf '%s\n' "$command_path"
return
fi
printf '%s\n' "$command_path"
}
restore_iptables_backend() {
if [[ -n "$ORIGINAL_IPTABLES_TARGET" ]]; then
run_as_root update-alternatives --set iptables "$ORIGINAL_IPTABLES_TARGET" >/dev/null 2>&1 || true
fi
if [[ -n "$ORIGINAL_IP6TABLES_TARGET" ]]; then
run_as_root update-alternatives --set ip6tables "$ORIGINAL_IP6TABLES_TARGET" >/dev/null 2>&1 || true
fi
}
switch_to_selected_backend() {
local backend="$1"
local current_v4
local current_v6
local desired_v4
local desired_v6
local resolved_current_v4
local resolved_current_v6
local resolved_desired_v4
local resolved_desired_v6
if [[ "$backend" == "current" ]]; then
info "Using the current iptables backend for full-system tests"
return
fi
desired_v4="$(command -v "iptables-${backend}" 2>/dev/null)" || die "The iptables-${backend} binary is required for --iptables-backend ${backend}."
desired_v6="$(command -v "ip6tables-${backend}" 2>/dev/null)" || die "The ip6tables-${backend} binary is required for --iptables-backend ${backend}."
resolved_current_v4="$(resolve_command_path iptables)" || die "The iptables binary is required for full system tests."
resolved_current_v6="$(resolve_command_path ip6tables)" || die "The ip6tables binary is required for full system tests."
resolved_desired_v4="$(resolve_command_path "iptables-${backend}")"
resolved_desired_v6="$(resolve_command_path "ip6tables-${backend}")"
if [[ "$resolved_current_v4" == "$resolved_desired_v4" && "$resolved_current_v6" == "$resolved_desired_v6" ]]; then
info "Using iptables-${backend} for full-system tests"
return
fi
if ! command_exists update-alternatives; then
die "Cannot switch to the ${backend} backend because update-alternatives is unavailable. Use --iptables-backend current to keep the existing backend."
fi
current_v4="$(update-alternatives --query iptables 2>/dev/null | awk '/^Value: / { print $2 }')"
current_v6="$(update-alternatives --query ip6tables 2>/dev/null | awk '/^Value: / { print $2 }')"
if [[ -z "$current_v4" || -z "$current_v6" ]]; then
die "Unable to determine the current iptables alternatives."
fi
if [[ "$resolved_current_v4" != "$resolved_desired_v4" ]]; then
ORIGINAL_IPTABLES_TARGET="$current_v4"
info "Switching iptables to the ${backend} backend for full-system tests"
run_as_root update-alternatives --set iptables "$desired_v4"
fi
if [[ "$resolved_current_v6" != "$resolved_desired_v6" ]]; then
ORIGINAL_IP6TABLES_TARGET="$current_v6"
info "Switching ip6tables to the ${backend} backend for full-system tests"
run_as_root update-alternatives --set ip6tables "$desired_v6"
fi
}
load_kernel_modules() {
if ! command_exists modprobe; then
return
fi
local module
for module in ip_tables iptable_filter iptable_mangle ip6_tables ip6table_filter ip6table_mangle nf_conntrack; do
run_as_root modprobe "$module" >/dev/null 2>&1 || true
done
}
cleanup_test_chains_for_binary() {
local binary="$1"
local chain
if ! command_exists "$binary"; then
return
fi
for chain in test test2 test3; do
run_as_root "$binary" -F "$chain" >/dev/null 2>&1 || true
run_as_root "$binary" -X "$chain" >/dev/null 2>&1 || true
done
}
cleanup_test_chains() {
local binary
local -a binaries=(
iptables
iptables-legacy
iptables-nft
ip6tables
ip6tables-legacy
ip6tables-nft
)
for binary in "${binaries[@]}"; do
cleanup_test_chains_for_binary "$binary"
done
}
run_full_tests() {
local results_dir
local trap_command
local -a effective_test_args=("${DOTNET_TEST_ARGS[@]}")
results_dir="$(mktemp -d)"
trap_command="$(printf 'rm -rf -- %q; cleanup_test_chains; restore_iptables_backend' "$results_dir")"
trap "$trap_command" EXIT
switch_to_selected_backend "$IPTABLES_BACKEND"
load_kernel_modules
command_exists iptables || die "The iptables binary is required for full system tests."
command_exists ip6tables || die "The ip6tables binary is required for full system tests."
cleanup_test_chains
if [[ "$RUN_UNSTABLE_SYSTEM_TESTS" != "1" ]] && ! has_explicit_test_filter; then
effective_test_args+=("--filter" "Category!=NotWorkingOnTravis")
fi
if [[ "${EUID:-$(id -u)}" -eq 0 ]]; then
dotnet_test "${REPO_ROOT}/IPTables.Net.Tests/IPTables.Net.Tests.csproj" "$CONFIGURATION" \
--results-directory "$results_dir" "${effective_test_args[@]}"
return
fi
run_and_check_core_dumps run_as_root env \
"PATH=$PATH" \
"DOTNET_ROOT=${DOTNET_ROOT}" \
"DOTNET_CLI_HOME=/root/.dotnet-cli" \
"NUGET_PACKAGES=${NUGET_PACKAGES}" \
"DOTNET_CLI_TELEMETRY_OPTOUT=${DOTNET_CLI_TELEMETRY_OPTOUT}" \
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE=${DOTNET_SKIP_FIRST_TIME_EXPERIENCE}" \
"LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}" \
"HOME=/root" \
dotnet test "${REPO_ROOT}/IPTables.Net.Tests/IPTables.Net.Tests.csproj" \
--configuration "$CONFIGURATION" \
--no-build \
--no-restore \
--nologo \
-m:1 \
-p:UseSharedCompilation=false \
--results-directory "$results_dir" \
"${effective_test_args[@]}"
}
while (($# > 0)); do
case "$1" in
--fast)
TEST_MODE="fast"
;;
--full)
TEST_MODE="full"
;;
--configuration)
shift
[[ $# -gt 0 ]] || die "--configuration requires a value"
CONFIGURATION="$(normalize_configuration "$1")"
;;
--iptables-backend)
shift
[[ $# -gt 0 ]] || die "--iptables-backend requires a value"
IPTABLES_BACKEND="$(normalize_iptables_backend "$1")"
;;
--iptables-backend=*)
IPTABLES_BACKEND="$(normalize_iptables_backend "${1#*=}")"
;;
--help|-h)
cat <<'EOF'
Usage: ./test.sh [--fast|--full] [--iptables-backend <legacy|nft|current>] [--configuration <Debug|Release>] [dotnet test arguments...]
Modes:
--fast Skip privileged/system iptables tests by setting SKIP_SYSTEM_TESTS=1.
--full Run the full xUnit suite, including native helper and system iptables tests.
Backend selection:
--iptables-backend legacy Use iptables-legacy/ip6tables-legacy for full-system tests. This is the default.
--iptables-backend nft Use iptables-nft/ip6tables-nft for full-system tests.
--iptables-backend current Keep the host's current iptables/ip6tables backend.
Default behavior:
TEST_MODE=auto chooses --full on Linux when passwordless sudo/root is available,
otherwise it falls back to --fast.
Environment:
IPTABLES_BACKEND=legacy|nft|current sets the default full-test backend.
RUN_UNSTABLE_SYSTEM_TESTS=1 includes tests marked NotWorkingOnTravis, such as
the conntrack coverage that can crash on some containerized hosts.
EOF
exit 0
;;
*)
DOTNET_TEST_ARGS+=("$1")
;;
esac
shift
done
IPTABLES_BACKEND="$(normalize_iptables_backend "$IPTABLES_BACKEND")"
if [[ "$TEST_MODE" == "auto" ]]; then
if is_linux && can_run_privileged; then
TEST_MODE="full"
else
TEST_MODE="fast"
fi
fi
info "Preparing test environment (${TEST_MODE})"
ensure_dotnet
if is_linux; then
if [[ "$TEST_MODE" == "full" ]]; then
build_ipthelper "$CONFIGURATION"
else
if helper_build_requirements_present; then
build_ipthelper "$CONFIGURATION"
else
warn "Skipping libipthelper build in fast mode because native dependencies are not installed."
fi
fi
fi
info "Restoring NuGet packages"
dotnet_restore "${REPO_ROOT}/IPTables.Net.sln"
info "Building solution (${CONFIGURATION})"
dotnet_build "${REPO_ROOT}/IPTables.Net.sln" "$CONFIGURATION"
if [[ "$TEST_MODE" == "fast" ]]; then
info "Running tests with SKIP_SYSTEM_TESTS=1"
SKIP_SYSTEM_TESTS=1 dotnet_test "${REPO_ROOT}/IPTables.Net.Tests/IPTables.Net.Tests.csproj" "$CONFIGURATION" "${DOTNET_TEST_ARGS[@]}"
else
info "Running the full test suite"
run_full_tests
fi
info "Tests completed successfully."