Son aktivite 1 month ago

nuno bu gisti düzenledi 1 month ago. Düzenlemeye git

1 file changed, 506 insertions

gistfile1.txt(dosya oluşturuldu)

@@ -0,0 +1,506 @@
1 + #!/usr/bin/env bash
2 +
3 + WGCTL_BINARY="$(command -v wgctl)"
4 +
5 + # ============================================
6 + # Lifecycle
7 + # ============================================
8 +
9 + function cmd::test::on_load() {
10 + flag::register --destructive
11 + flag::register --section
12 + flag::register --fn
13 + flag::register --function
14 + }
15 +
16 + function cmd::test::help() {
17 + cat <<EOF
18 + Usage: wgctl test [options]
19 +
20 + Run the wgctl test suite.
21 +
22 + Options:
23 + --destructive Include tests that modify state (add/remove/block)
24 + --section <name> Run only a specific section (list, rules, groups, audit, logs, fw)
25 +
26 + Examples:
27 + wgctl test
28 + wgctl test --section rules
29 + wgctl test --destructive
30 + EOF
31 + }
32 +
33 + # ============================================
34 + # Test helpers
35 + # ============================================
36 +
37 + function cmd::test::run_cmd() {
38 + local desc="$1"
39 + local expected="${2:-}"
40 + shift 2
41 +
42 + local tmp exit_code
43 + tmp=$(mktemp)
44 +
45 + set +e # disable exit on error (return 1)
46 +
47 + timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1 &
48 + local pid=$!
49 + wait $pid
50 + exit_code=$?
51 +
52 + set -e # re-enable exit on error
53 +
54 + if [[ $exit_code -eq 124 ]]; then
55 + test::warn "${desc} (timed out after 30s)"
56 + rm -f "$tmp"
57 + return 1
58 + fi
59 +
60 + if [[ $exit_code -ne 0 ]]; then
61 + test::fail "${desc}"
62 + if [[ "${WGCTL_TEST_VERBOSE:-false}" == "true" ]]; then
63 + printf " Output: %s\n" "$(cat "$tmp")"
64 + fi
65 + rm -f "$tmp"
66 + return 1
67 + fi
68 +
69 + if [[ -n "$expected" ]] && ! grep -qF "$expected" "$tmp"; then
70 + local actual
71 + actual=$(head -3 "$tmp" | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100)
72 + test::fail "${desc} (expected '${expected}', got: '${actual}')"
73 + rm -f "$tmp"
74 + return 1
75 + fi
76 +
77 + test::pass "$desc"
78 + rm -f "$tmp"
79 + }
80 +
81 + function cmd::test::run_cmd_fails() {
82 + local desc="$1"
83 + shift
84 +
85 + set +e # disable exit on error (return 1)
86 +
87 + local tmp exit_code
88 + tmp=$(mktemp)
89 + timeout 10 setsid "$WGCTL_BINARY" "$@" > "$tmp" 2>&1
90 + exit_code=$?
91 +
92 + set -e # re-enable exit on error
93 +
94 + rm -f "$tmp"
95 +
96 + if [[ $exit_code -eq 124 ]]; then
97 + test::warn "${desc} (timed out)"
98 + return 1
99 + fi
100 +
101 + if [[ $exit_code -eq 0 ]]; then
102 + test::fail "${desc} (expected failure but succeeded)"
103 + return 1
104 + fi
105 +
106 + test::pass "$desc"
107 + }
108 +
109 + function cmd::test::run_function() {
110 + local fn="$1"
111 +
112 + local namespace
113 + namespace=$(echo "$fn" | cut -d':' -f3)
114 + load_command "$namespace" 2>/dev/null || true
115 +
116 + test::reset
117 + log::section "Function Test: ${fn}"
118 +
119 + case "$fn" in
120 + cmd::block::run) cmd::test::fn_block ;;
121 + cmd::unblock::run) cmd::test::fn_unblock ;;
122 + cmd::remove::run) cmd::test::fn_remove ;;
123 + cmd::rule::assign) cmd::test::fn_rule_assign ;;
124 + cmd::rename::run) cmd::test::fn_rename ;;
125 + cmd::remove::run) cmd::test::fn_remove ;;
126 + cmd::unblock::run) cmd::test::fn_unblock ;;
127 + *)
128 + log::error "No function test defined for: ${fn}"
129 + return 1
130 + ;;
131 + esac
132 +
133 + test::summary
134 + }
135 +
136 + # ============================================
137 + # Test sections
138 + # ============================================
139 +
140 + function cmd::test::section_list() {
141 + test::section "List"
142 + cmd::test::run_cmd "list" "WireGuard Clients" list
143 + cmd::test::run_cmd "list --online" "" list --online
144 + cmd::test::run_cmd "list --offline" "" list --offline
145 + cmd::test::run_cmd "list --blocked" "" list --blocked
146 + cmd::test::run_cmd "list --type phone" "" list --type phone
147 + cmd::test::run_cmd "list --type guest" "" list --type guest
148 + cmd::test::run_cmd "list --detailed" "Client:" list --detailed
149 + cmd::test::run_cmd "list --name phone-nuno" "phone-nuno" list --name phone-nuno
150 + }
151 +
152 + function cmd::test::section_inspect() {
153 + test::section "Inspect"
154 + cmd::test::run_cmd "inspect --name phone-nuno" "IP:" inspect --name phone-nuno
155 + cmd::test::run_cmd "inspect --name nuno --type phone" "IP:" inspect --name nuno --type phone
156 + cmd::test::run_cmd "inspect --name phone-nuno --config" "PrivateKey" inspect --name phone-nuno --config
157 + cmd::test::run_cmd_fails "inspect nonexistent peer" inspect --name nonexistent-peer
158 + }
159 +
160 + function cmd::test::section_config() {
161 + test::section "Config & QR"
162 + cmd::test::run_cmd "config --name phone-nuno" "PrivateKey" config --name phone-nuno
163 + cmd::test::run_cmd "config --name nuno --type phone" "PrivateKey" config --name nuno --type phone
164 + cmd::test::run_cmd "qr --name phone-nuno" "" qr --name phone-nuno
165 + }
166 +
167 + function cmd::test::section_rules() {
168 + test::section "Rules"
169 + cmd::test::run_cmd "rule list" "guest" rule list
170 + cmd::test::run_cmd "rule show --name guest" "Description" rule show --name guest
171 + cmd::test::run_cmd "rule show --name user" "Description" rule show --name user
172 + cmd::test::run_cmd "rule show --name admin" "Description" rule show --name admin
173 + cmd::test::run_cmd_fails "rule show nonexistent" rule show --name nonexistent
174 + }
175 +
176 + function cmd::test::section_groups() {
177 + test::section "Groups"
178 + cmd::test::run_cmd "group list" "Groups" group list
179 + cmd::test::run_cmd "group show --name family" "Peers:" group show --name family
180 + cmd::test::run_cmd_fails "group show nonexistent" group show --name nonexistent
181 + }
182 +
183 + function cmd::test::section_audit() {
184 + test::section "Audit"
185 + cmd::test::run_cmd "audit" "passed" audit
186 + cmd::test::run_cmd "audit --peer phone-nuno" "passed" audit --peer phone-nuno
187 + cmd::test::run_cmd "audit --type phone" "passed" audit --type phone
188 + }
189 +
190 + function cmd::test::section_logs() {
191 + test::section "Logs"
192 + cmd::test::run_cmd "logs" "Activity" logs
193 + cmd::test::run_cmd "logs --name phone-nuno" "Activity" logs --name phone-nuno
194 + cmd::test::run_cmd "logs --type guest" "Activity" logs --type guest
195 + cmd::test::run_cmd "logs --fw" "Activity" logs --fw
196 + cmd::test::run_cmd "logs --wg" "Activity" logs --wg
197 + }
198 +
199 + function cmd::test::section_fw() {
200 + test::section "Firewall"
201 + cmd::test::run_cmd "fw list" "FORWARD" fw list
202 + cmd::test::run_cmd "fw list --peer phone-nuno" "" fw list --peer phone-nuno
203 + cmd::test::run_cmd "fw list --no-nflog" "" fw list --no-nflog
204 + cmd::test::run_cmd "fw list --no-accept" "" fw list --no-accept
205 + cmd::test::run_cmd "fw list --no-drop" "" fw list --no-drop
206 + cmd::test::run_cmd "fw nat" "PREROUTING" fw nat
207 + cmd::test::run_cmd "fw count" "TOTAL" fw count
208 + }
209 + function cmd::test::section_net() {
210 + test::section "Net"
211 +
212 + "$WGCTL_BINARY" net rm --name test-svc --force > /dev/null 2>&1 || true
213 +
214 + cmd::test::run_cmd "net add service" "added" \
215 + net add --name test-svc --ip 10.0.0.99 --desc "Test service"
216 + cmd::test::run_cmd "net add port" "Added" \
217 + net add --name test-svc:web --port 9999:tcp
218 + cmd::test::run_cmd "net list" "test-svc" \
219 + net list
220 + cmd::test::run_cmd "net list --detailed" "web" \
221 + net list --detailed
222 + cmd::test::run_cmd "net show" "9999" \
223 + net show --name test-svc
224 + cmd::test::run_cmd "net rm port" "Removed" \
225 + net rm --name test-svc:web --force
226 + cmd::test::run_cmd "net add port again" "Added" \
227 + net add --name test-svc:web --port 9999:tcp
228 + cmd::test::run_cmd "net rm all ports" "Removed" \
229 + net rm --name test-svc:ports --force
230 + cmd::test::run_cmd "net rm service" "Removed" \
231 + net rm --name test-svc --force
232 + cmd::test::run_cmd_fails "net show nonexistent" \
233 + net show --name nonexistent-svc
234 + cmd::test::run_cmd_fails "net add port no service" \
235 + net add --name nonexistent:web --port 80:tcp
236 + }
237 +
238 + function cmd::test::section_destructive() {
239 + test::section "Destructive (modifying state)"
240 +
241 + # ── Cleanup from any previous failed run ──
242 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
243 + "$WGCTL_BINARY" group remove --name testgroup --force > /dev/null 2>&1 || true
244 + "$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
245 + "$WGCTL_BINARY" net rm --name test-block-svc --force > /dev/null 2>&1 || true
246 + "$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
247 +
248 + # ── Add test peer ──────────────────────────
249 + cmd::test::run_cmd "add phone peer" "added successfully" \
250 + add --name testunit --type phone
251 +
252 + # ── Direct block/unblock ───────────────────
253 + cmd::test::run_cmd "block peer" "blocked" block --name phone-testunit
254 + cmd::test::run_cmd "list shows blocked" "blocked" list --blocked
255 + cmd::test::run_cmd "unblock peer" "unblocked" unblock --name phone-testunit
256 +
257 + # ── Specific IP block/unblock ──────────────
258 + cmd::test::run_cmd "block peer --ip" "blocked for" \
259 + block --name phone-testunit --ip 10.0.0.99
260 + cmd::test::run_cmd "list shows restricted" "restricted" \
261 + list --name phone-testunit
262 + cmd::test::run_cmd "unblock peer --ip" "unblocked" \
263 + unblock --name phone-testunit --ip 10.0.0.99
264 +
265 + # ── Service block/unblock ──────────────────
266 + "$WGCTL_BINARY" net add --name test-block-svc \
267 + --ip 10.0.0.99 > /dev/null 2>&1
268 + "$WGCTL_BINARY" net add --name test-block-svc:web \
269 + --port 9999:tcp > /dev/null 2>&1
270 + cmd::test::run_cmd "block peer --service (ip)" "blocked" \
271 + block --name phone-testunit --service test-block-svc
272 + cmd::test::run_cmd "block already blocked service" "already" \
273 + block --name phone-testunit --service test-block-svc
274 + cmd::test::run_cmd "unblock peer --service (ip)" "unblocked" \
275 + unblock --name phone-testunit --service test-block-svc
276 + cmd::test::run_cmd "unblock not blocked service" "not blocked" \
277 + unblock --name phone-testunit --service test-block-svc
278 + cmd::test::run_cmd "block peer --service (port)" "blocked" \
279 + block --name phone-testunit --service test-block-svc:web
280 + cmd::test::run_cmd "unblock peer --service (port)" "unblocked" \
281 + unblock --name phone-testunit --service test-block-svc:web
282 + "$WGCTL_BINARY" net rm --name test-block-svc --force > /dev/null 2>&1 || true
283 +
284 + # ── Rule assign/unassign ───────────────────
285 + cmd::test::run_cmd "rule assign" "Assigned" \
286 + rule assign --name user --peer phone-testunit
287 + cmd::test::run_cmd "rule unassign" "Unassigned" \
288 + rule unassign --peer phone-testunit
289 + "$WGCTL_BINARY" rule assign --name user --peer phone-testunit \
290 + > /dev/null 2>&1 || true
291 +
292 + # ── Group basic operations ─────────────────
293 + cmd::test::run_cmd "group add" "created" \
294 + group add --name testgroup --desc "Test group"
295 + cmd::test::run_cmd "group peer add" "Added" \
296 + group peer add --name testgroup --peer phone-testunit
297 + cmd::test::run_cmd "group block" "blocked" \
298 + group block --name testgroup
299 + cmd::test::run_cmd "group unblock" "unblocked" \
300 + group unblock --name testgroup
301 +
302 + # ── M:N group block tracking ───────────────
303 + "$WGCTL_BINARY" group add --name testgroup2 \
304 + --desc "Test group 2" > /dev/null 2>&1
305 + "$WGCTL_BINARY" group peer add --name testgroup2 \
306 + --peer phone-testunit > /dev/null 2>&1
307 +
308 + cmd::test::run_cmd "group block first group" "blocked" \
309 + group block --name testgroup
310 + cmd::test::run_cmd "group block second group" "blocked" \
311 + group block --name testgroup2
312 +
313 + "$WGCTL_BINARY" group unblock --name testgroup > /dev/null 2>&1
314 + cmd::test::run_cmd "peer stays blocked after partial unblock" "blocked" \
315 + list --blocked
316 +
317 + "$WGCTL_BINARY" group unblock --name testgroup2 > /dev/null 2>&1
318 + cmd::test::run_cmd "peer unblocked after all groups unblock" "phone-testunit" \
319 + list --allowed
320 +
321 + # ── Direct block overrides group block ─────
322 + "$WGCTL_BINARY" group block --name testgroup > /dev/null 2>&1
323 + cmd::test::run_cmd "direct unblock overrides group block" "unblocked" \
324 + unblock --name phone-testunit
325 +
326 + # ── Cleanup ────────────────────────────────
327 + cmd::test::run_cmd "group remove" "removed" \
328 + group remove --name testgroup --force
329 + "$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
330 +
331 + cmd::test::run_cmd "remove phone peer" "removed" \
332 + remove --name phone-testunit --force
333 + }
334 +
335 + # ============================================
336 + # Function Blocks
337 + # ============================================
338 +
339 + function cmd::test::fn_block() {
340 + test::section "cmd::block::run"
341 +
342 + # Setup
343 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
344 + "$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
345 +
346 + # Tests
347 + cmd::test::run_cmd "block peer" "blocked" block --name phone-testunit
348 + cmd::test::run_cmd "block already blocked" "already" block --name phone-testunit
349 +
350 + "$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
351 + cmd::test::run_cmd "block with --type" "blocked" block --name testunit --type phone
352 +
353 + cmd::test::run_cmd_fails "block nonexistent" block --name truly-nonexistent-xyz
354 +
355 + # Cleanup
356 + "$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
357 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
358 + }
359 +
360 + function cmd::test::fn_remove() {
361 + test::section "cmd::remove::run"
362 +
363 + # Setup
364 + "$WGCTL_BINARY" remove --name phone-testunit --force \
365 + > /dev/null 2>&1 || true
366 + "$WGCTL_BINARY" add --name testunit --type phone \
367 + > /dev/null 2>&1
368 +
369 + # Tests
370 + # Skip the interactive prompt test — it hangs waiting for input
371 + # cmd::test::run_cmd_fails "remove without --force" \
372 + # remove --name phone-testunit
373 + cmd::test::run_cmd "remove with --force" "removed" \
374 + remove --name phone-testunit --force
375 + cmd::test::run_cmd_fails "remove nonexistent" \
376 + remove --name nonexistent-peer --force
377 + cmd::test::run_cmd_fails "remove missing --name" \
378 + remove --force
379 +
380 + # Cleanup already done by tests
381 + }
382 +
383 + function cmd::test::fn_rename() {
384 + test::section "cmd::rename::run"
385 +
386 + # Setup
387 + "$WGCTL_BINARY" remove --name phone-testunit --force \
388 + > /dev/null 2>&1 || true
389 + "$WGCTL_BINARY" remove --name phone-testunit2 --force \
390 + > /dev/null 2>&1 || true
391 + "$WGCTL_BINARY" add --name testunit --type phone \
392 + > /dev/null 2>&1
393 +
394 + # Tests
395 + cmd::test::run_cmd "rename peer" "renamed" \
396 + rename --name phone-testunit --new-name phone-testunit2
397 + cmd::test::run_cmd_fails "rename to existing" \
398 + rename --name phone-testunit2 --new-name phone-nuno
399 + cmd::test::run_cmd_fails "rename nonexistent" \
400 + rename --name phone-nonexistent --new-name phone-testunit
401 + cmd::test::run_cmd_fails "rename missing --new-name" \
402 + rename --name phone-testunit2
403 +
404 + # Cleanup
405 + "$WGCTL_BINARY" remove --name phone-testunit2 --force \
406 + > /dev/null 2>&1 || true
407 + }
408 +
409 + function cmd::test::fn_unblock() {
410 + test::section "cmd::unblock::run"
411 +
412 + # Setup — add and block a peer
413 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
414 + "$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
415 + "$WGCTL_BINARY" block --name phone-testunit > /dev/null 2>&1
416 +
417 + # Tests
418 + cmd::test::run_cmd "unblock peer" "unblocked" unblock --name phone-testunit
419 + cmd::test::run_cmd "unblock not blocked" "not blocked" unblock --name phone-testunit
420 + cmd::test::run_cmd_fails "unblock nonexistent" unblock --name nonexistent-peer
421 + cmd::test::run_cmd_fails "unblock missing --name" unblock
422 +
423 + # Cleanup
424 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
425 + }
426 +
427 + function cmd::test::fn_rule_assign() {
428 + test::section "cmd::rule::assign"
429 +
430 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
431 + "$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
432 +
433 + cmd::test::run_cmd "rule assign" "Assigned" \
434 + rule assign --name admin --peer phone-testunit
435 +
436 + "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
437 + }
438 +
439 + # ============================================
440 + # Run
441 + # ============================================
442 +
443 + function cmd::test::run() {
444 + local destructive=false section=""
445 + local fn=""
446 +
447 + while [[ $# -gt 0 ]]; do
448 + case "$1" in
449 + --destructive) destructive=true; shift ;;
450 + --section)
451 + util::require_flag "--section" "${2:-}" || return 1
452 + section="$2"; shift 2
453 + ;;
454 + --fn|--function) fn="$2"; shift 2 ;;
455 + --verbose|-v) WGCTL_TEST_VERBOSE=true; shift ;;
456 + --help) cmd::test::help; return ;;
457 + *)
458 + log::error "Unknown flag: $1"
459 + return 1
460 + ;;
461 + esac
462 + done
463 +
464 + # After flag parsing:
465 + if [[ -n "$fn" ]]; then
466 + cmd::test::run_function "$fn"
467 + return
468 + fi
469 +
470 + test::reset
471 + log::section "wgctl Test Suite"
472 +
473 + if [[ -n "$section" ]]; then
474 + case "$section" in
475 + list) cmd::test::section_list ;;
476 + inspect) cmd::test::section_inspect ;;
477 + config) cmd::test::section_config ;;
478 + rules) cmd::test::section_rules ;;
479 + groups) cmd::test::section_groups ;;
480 + audit) cmd::test::section_audit ;;
481 + logs) cmd::test::section_logs ;;
482 + fw) cmd::test::section_fw ;;
483 + net) cmd::test::section_net ;;
484 + destructive) cmd::test::section_destructive ;;
485 + *)
486 + log::error "Unknown section: $section"
487 + return 1
488 + ;;
489 + esac
490 + else
491 + cmd::test::section_list
492 + cmd::test::section_inspect
493 + cmd::test::section_config
494 + cmd::test::section_rules
495 + cmd::test::section_groups
496 + cmd::test::section_audit
497 + cmd::test::section_logs
498 + cmd::test::section_fw
499 + fi
500 +
501 + if $destructive; then
502 + cmd::test::section_destructive
503 + fi
504 +
505 + test::summary
506 + }
Daha yeni Daha eski