- commands/group/: 17 files, all subcommands migrated - helpers.sh: real implementations, no invented functions - set_main: uses peers::set_main_group - rename: json::set + mv - peer add/remove: group::add_peer, group::remove_peer - block/unblock: block::add_group, block::remove_group - purge-stale: inline stale detection via group::peers - audit: no invented helper functions - logs: command::load_subcmd logs show for direct function access - logs/helpers.sh: extracted shared functions (follow, show_fw, show_wg, show_merged) - group rule unassign: stub (not yet implemented) - notes: group watch pending, monitor module refactor pending
545 lines
No EOL
23 KiB
Bash
545 lines
No EOL
23 KiB
Bash
#!/usr/bin/env bash
|
|
# test/integration.sh — integration test sections
|
|
# Tests run against the live wgctl binary.
|
|
# Sourced by test.command.sh — do not execute directly.
|
|
|
|
WGCTL_BINARY="$(command -v wgctl)"
|
|
|
|
# ============================================
|
|
# Helpers
|
|
# ============================================
|
|
|
|
function cmd::test::_strip_ansi() {
|
|
sed 's/\x1b\[[0-9;]*m//g'
|
|
}
|
|
|
|
function cmd::test::run_cmd() {
|
|
local desc="$1" expected="${2:-}"
|
|
shift 2
|
|
|
|
local tmp exit_code
|
|
tmp=$(mktemp)
|
|
|
|
set +e
|
|
timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1
|
|
exit_code=$?
|
|
set -e
|
|
|
|
# Reset terminal color in case command output left ANSI state dirty
|
|
printf "\033[0m" >&2
|
|
|
|
if [[ $exit_code -eq 124 ]]; then
|
|
test::warn "${desc} (timed out after 30s)"
|
|
rm -f "$tmp"
|
|
return 1
|
|
fi
|
|
|
|
local clean
|
|
clean=$(cmd::test::_strip_ansi < "$tmp")
|
|
|
|
if [[ $exit_code -ne 0 ]]; then
|
|
local msg="${desc}"
|
|
[[ -n "$expected" ]] && msg="${desc} (expected '${expected}', command failed)"
|
|
test::fail "$msg"
|
|
if [[ "${WGCTL_TEST_VERBOSE:-false}" == "true" ]]; then
|
|
printf " Output: %s\n" "$(echo "$clean" | head -3 | tr '\n' ' ')"
|
|
fi
|
|
rm -f "$tmp"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -n "$expected" ]] && ! echo "$clean" | grep -qF "$expected"; then
|
|
local actual
|
|
actual=$(echo "$clean" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100)
|
|
test::fail "${desc} (expected '${expected}', got: '${actual}')"
|
|
rm -f "$tmp"
|
|
return 1
|
|
fi
|
|
|
|
test::pass "$desc"
|
|
rm -f "$tmp"
|
|
}
|
|
|
|
function cmd::test::run_cmd_any() {
|
|
local desc="$1" expected="${2:-}"
|
|
shift 2
|
|
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
|
|
set +e
|
|
timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1
|
|
set -e
|
|
|
|
printf "\033[0m" >&2
|
|
|
|
local clean
|
|
clean=$(cmd::test::_strip_ansi < "$tmp")
|
|
|
|
if [[ -n "$expected" ]] && ! echo "$clean" | grep -qF "$expected"; then
|
|
local actual
|
|
actual=$(echo "$clean" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100)
|
|
test::fail "${desc} (expected '${expected}', got: '${actual}')"
|
|
rm -f "$tmp"
|
|
return 1
|
|
fi
|
|
|
|
test::pass "$desc"
|
|
rm -f "$tmp"
|
|
}
|
|
|
|
function cmd::test::run_cmd_fails() {
|
|
local desc="$1"
|
|
shift
|
|
|
|
local tmp exit_code
|
|
tmp=$(mktemp)
|
|
|
|
set +e
|
|
timeout 10 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1
|
|
exit_code=$?
|
|
set -e
|
|
|
|
printf "\033[0m" >&2
|
|
rm -f "$tmp"
|
|
|
|
if [[ $exit_code -eq 124 ]]; then
|
|
test::warn "${desc} (timed out)"
|
|
return 1
|
|
fi
|
|
|
|
if [[ $exit_code -eq 0 ]]; then
|
|
test::fail "${desc} (expected failure but succeeded)"
|
|
return 1
|
|
fi
|
|
|
|
test::pass "$desc"
|
|
}
|
|
|
|
# ============================================
|
|
# Sections
|
|
# ============================================
|
|
|
|
function cmd::test::run_all_integration_sections() {
|
|
cmd::test::section_list
|
|
cmd::test::section_inspect
|
|
cmd::test::section_config
|
|
cmd::test::section_rules
|
|
cmd::test::section_groups
|
|
cmd::test::section_block_unblock
|
|
cmd::test::section_audit
|
|
cmd::test::section_logs
|
|
cmd::test::section_fw
|
|
cmd::test::section_net
|
|
cmd::test::section_subnet
|
|
cmd::test::section_identity
|
|
cmd::test::section_activity
|
|
cmd::test::section_policy
|
|
cmd::test::section_hosts
|
|
cmd::test::section_peer_cmd
|
|
cmd::test::section_group_purge
|
|
cmd::test::section_logs_clean
|
|
cmd::test::section_display
|
|
cmd::test::section_export
|
|
}
|
|
|
|
function cmd::test::section_list() {
|
|
test::section "List"
|
|
cmd::test::run_cmd "list" "rule:" list
|
|
cmd::test::run_cmd "list --online" "" list --online
|
|
cmd::test::run_cmd "list --offline" "" list --offline
|
|
cmd::test::run_cmd "list --blocked" "" list --blocked
|
|
cmd::test::run_cmd "list --type phone" "phone" list --type phone
|
|
cmd::test::run_cmd "list --detailed" "rule:" list --detailed
|
|
cmd::test::run_cmd "list --name phone-nuno" "phone-nuno" list --name phone-nuno
|
|
cmd::test::run_cmd "list --json" '"ok":true' list --json
|
|
cmd::test::run_cmd "list --json has peers" '"peers":' list --json
|
|
cmd::test::run_cmd "list --json has meta" '"meta":' list --json
|
|
cmd::test::run_cmd "list --json peer name" '"name":' list --json
|
|
cmd::test::run_cmd "list --json peer ip" '"ip":' list --json
|
|
cmd::test::run_cmd "list --json peer status" '"status":' list --json
|
|
}
|
|
|
|
function cmd::test::section_inspect() {
|
|
test::section "Inspect"
|
|
cmd::test::run_cmd "inspect --name phone-nuno" "IP:" inspect --name phone-nuno
|
|
cmd::test::run_cmd "inspect --name nuno --type phone" "IP:" inspect --name nuno --type phone
|
|
cmd::test::run_cmd "inspect --name phone-nuno --config" "PrivateKey" inspect --name phone-nuno --config
|
|
cmd::test::run_cmd_fails "inspect nonexistent" inspect --name nonexistent-peer
|
|
cmd::test::run_cmd "inspect --json" '"ok":true' inspect --name phone-nuno --json
|
|
cmd::test::run_cmd "inspect --json rule" '"rule":' inspect --name phone-nuno --json
|
|
cmd::test::run_cmd "inspect --json identity" '"identity":' inspect --name phone-nuno --json
|
|
cmd::test::run_cmd "inspect --json groups" '"groups":' inspect --name phone-nuno --json
|
|
}
|
|
|
|
function cmd::test::section_config() {
|
|
test::section "Config & QR"
|
|
cmd::test::run_cmd "config --name phone-nuno" "PrivateKey" config --name phone-nuno
|
|
cmd::test::run_cmd "config --name nuno --type phone" "PrivateKey" config --name nuno --type phone
|
|
cmd::test::run_cmd "qr --name phone-nuno" "" qr --name phone-nuno
|
|
cmd::test::run_cmd "config migrate --dry-run" "" config migrate --dry-run
|
|
cmd::test::run_cmd_fails "config missing --name" config
|
|
}
|
|
|
|
function cmd::test::section_rules() {
|
|
test::section "Rules"
|
|
cmd::test::run_cmd "rule list" "user" rule list
|
|
cmd::test::run_cmd "rule show --name guest" "Description" rule show --name guest
|
|
cmd::test::run_cmd "rule show --name user" "Description" rule show --name user
|
|
cmd::test::run_cmd "rule show --name admin" "Description" rule show --name admin
|
|
cmd::test::run_cmd "rule list --json" '"rules":' rule list --json
|
|
cmd::test::run_cmd "rule list --json" '"rules":' rule list --json
|
|
cmd::test::run_cmd "rule --json is_base" '"is_base":' rule list --json
|
|
cmd::test::run_cmd "rule --json extends" '"extends":' rule list --json
|
|
cmd::test::run_cmd "rule --json allows" '"allows":' rule list --json
|
|
cmd::test::run_cmd_fails "rule show nonexistent" rule show --name nonexistent
|
|
}
|
|
|
|
function cmd::test::section_groups() {
|
|
test::section "Groups"
|
|
cmd::test::run_cmd "group list" "Groups" group list
|
|
cmd::test::run_cmd "group show --name family" "Peers:" group show --name family
|
|
cmd::test::run_cmd "group list --json" '"name":' group list --json
|
|
cmd::test::run_cmd "group list --json" '"command":"groups"' group list --json
|
|
cmd::test::run_cmd_fails "group show nonexistent" group show --name nonexistent
|
|
}
|
|
|
|
# function cmd::test::section_blocks() {
|
|
# test::section "Blocks"
|
|
# cmd::test::run_cmd "block --reason records history" "block-history" block --name guest-test --reason "test block" --force
|
|
# cmd::test::run_cmd_succeeds "unblock clears history" unblock --name guest-test --force
|
|
# }
|
|
|
|
function cmd::test::section_block_unblock() {
|
|
test::section "Block / Unblock"
|
|
|
|
# ── Setup fixture ──
|
|
local fixture="phone-testblock"
|
|
wgctl unblock --name "$fixture" --force >/dev/null 2>&1 || true
|
|
wgctl remove --name "$fixture" --force >/dev/null 2>&1 || true
|
|
wgctl add --name testblock --type phone >/dev/null 2>&1 || true
|
|
|
|
local history_file
|
|
history_file="$(ctx::block_history)/${fixture}.json"
|
|
|
|
# ── Block ──
|
|
echo "DEBUG about to run: $WGCTL_BINARY block --name $fixture --force" >&2
|
|
cmd::test::run_cmd "block peer" "blocked" block --name "$fixture" --force
|
|
cmd::test::run_cmd "block already blocked" "already" block --name "$fixture" --force
|
|
|
|
wgctl unblock --name "$fixture" --force >/dev/null 2>&1 || true
|
|
cmd::test::run_cmd "block with reason" "blocked" block --name "$fixture" --force \
|
|
--reason "test reason"
|
|
|
|
# ── Block history file created ──
|
|
[[ -f "$history_file" ]] && test::pass "block history file created" \
|
|
|| test::fail "block history file not created"
|
|
|
|
# ── Block history fields ──
|
|
if [[ -f "$history_file" ]]; then
|
|
local has_id has_blocked_at has_endpoint has_reason
|
|
has_id=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if d['history'] and 'id' in d['history'][-1] else 'no')
|
|
" 2>/dev/null)
|
|
has_blocked_at=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if d['history'] and d['history'][-1].get('blocked_at') else 'no')
|
|
" 2>/dev/null)
|
|
has_endpoint=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if 'endpoint_at_block' in d['history'][-1] else 'no')
|
|
" 2>/dev/null)
|
|
has_reason=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if d['history'][-1].get('reason') == 'test reason' else 'no')
|
|
" 2>/dev/null)
|
|
cmd::test::assert "history has id" "$has_id" "yes"
|
|
cmd::test::assert "history has blocked_at" "$has_blocked_at" "yes"
|
|
cmd::test::assert "history has endpoint" "$has_endpoint" "yes"
|
|
cmd::test::assert "history has reason" "$has_reason" "yes"
|
|
fi
|
|
|
|
# ── Unblock ──
|
|
cmd::test::run_cmd "unblock peer" "unblocked" unblock --name "$fixture" --force \
|
|
--reason "test cleanup"
|
|
cmd::test::run_cmd "unblock not blocked" "not blocked" unblock --name "$fixture" --force
|
|
|
|
# ── Unblock history updated ──
|
|
if [[ -f "$history_file" ]]; then
|
|
local has_unblocked has_unblock_reason
|
|
has_unblocked=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if d['history'] and d['history'][-1].get('unblocked_at') else 'no')
|
|
" 2>/dev/null)
|
|
has_unblock_reason=$(python3 -c "
|
|
import json
|
|
d=json.load(open('$history_file'))
|
|
print('yes' if d['history'][-1].get('unblock_reason') == 'test cleanup' else 'no')
|
|
" 2>/dev/null)
|
|
cmd::test::assert "history has unblocked_at" "$has_unblocked" "yes"
|
|
cmd::test::assert "history has unblock_reason" "$has_unblock_reason" "yes"
|
|
fi
|
|
|
|
# ── Teardown fixture ──
|
|
wgctl remove --name "$fixture" --force >/dev/null 2>&1 || true
|
|
rm -f "$history_file"
|
|
}
|
|
function cmd::test::section_audit() {
|
|
test::section "Audit"
|
|
cmd::test::run_cmd_any "audit" "passed" audit
|
|
cmd::test::run_cmd_any "audit --peer phone-nuno" "passed" audit --peer phone-nuno
|
|
cmd::test::run_cmd_any "audit --type phone" "passed" audit --type phone
|
|
}
|
|
|
|
function cmd::test::section_logs() {
|
|
test::section "Logs"
|
|
cmd::test::run_cmd "logs" "Activity" logs
|
|
cmd::test::run_cmd "logs --name phone-nuno" "Activity" logs --name phone-nuno
|
|
cmd::test::run_cmd "logs --fw" "Firewall Drops" logs --fw
|
|
cmd::test::run_cmd "logs --wg" "WireGuard Events" logs --wg
|
|
cmd::test::run_cmd "logs --since 2099-01-01" "No logs" logs --since "2099-01-01"
|
|
cmd::test::run_cmd "logs --wg --since 2099-01-01" "No logs" logs --wg --since "2099-01-01"
|
|
cmd::test::run_cmd "logs --fw --since 2099-01-01" "No logs" logs --fw --since "2099-01-01"
|
|
cmd::test::run_cmd "logs --wg --event attempt" "" logs --wg --event attempt
|
|
cmd::test::run_cmd "logs --detailed" "" logs --detailed
|
|
cmd::test::run_cmd "logs --resolved" "" logs --resolved
|
|
cmd::test::run_cmd "logs --ascending" "" logs --ascending
|
|
cmd::test::run_cmd "logs --descending" "" logs --descending
|
|
cmd::test::run_cmd "logs --wg --ascending" "" logs --wg --ascending
|
|
}
|
|
|
|
function cmd::test::section_fw() {
|
|
test::section "Firewall"
|
|
cmd::test::run_cmd "fw list" "FORWARD" fw list
|
|
cmd::test::run_cmd "fw list --peer phone-nuno" "" fw list --peer phone-nuno
|
|
cmd::test::run_cmd "fw list --no-nflog" "" fw list --no-nflog
|
|
cmd::test::run_cmd "fw list --no-accept" "" fw list --no-accept
|
|
cmd::test::run_cmd "fw list --no-drop" "" fw list --no-drop
|
|
cmd::test::run_cmd "fw nat" "PREROUTING" fw nat
|
|
cmd::test::run_cmd "fw count" "TOTAL" fw count
|
|
}
|
|
|
|
function cmd::test::section_net() {
|
|
test::section "Net"
|
|
"$WGCTL_BINARY" net rm --name test-svc --force > /dev/null 2>&1 || true
|
|
|
|
cmd::test::run_cmd "net add service" "added" net add --name test-svc --ip 10.0.0.99 --desc "Test service"
|
|
cmd::test::run_cmd "net add port" "Added" net add --name test-svc:web --port 9999:tcp
|
|
cmd::test::run_cmd "net list" "test-svc" net list
|
|
cmd::test::run_cmd "net list --detailed" "web" net list --detailed
|
|
cmd::test::run_cmd "net show" "9999" net show --name test-svc
|
|
cmd::test::run_cmd "net rm port" "Removed" net rm --name test-svc:web --force
|
|
cmd::test::run_cmd "net add port again" "Added" net add --name test-svc:web --port 9999:tcp
|
|
cmd::test::run_cmd "net rm all ports" "Removed" net rm --name test-svc:ports --force
|
|
cmd::test::run_cmd "net rm service" "Removed" net rm --name test-svc --force
|
|
cmd::test::run_cmd "net list --json" '"services":' net list --json
|
|
cmd::test::run_cmd "net --json has tags" '"tags":' net list --json
|
|
cmd::test::run_cmd "net --json port_count" '"port_count":' net list --json
|
|
cmd::test::run_cmd_fails "net show nonexistent" net show --name nonexistent-svc
|
|
cmd::test::run_cmd_fails "net add port no service" net add --name nonexistent:web --port 80:tcp
|
|
}
|
|
|
|
function cmd::test::section_subnet() {
|
|
test::section "Subnet"
|
|
"$WGCTL_BINARY" subnet rm --name test-subnet-2 > /dev/null 2>&1 || true
|
|
"$WGCTL_BINARY" subnet rm --name test-subnet > /dev/null 2>&1 || true
|
|
|
|
cmd::test::run_cmd "subnet list" "desktop" subnet list
|
|
cmd::test::run_cmd "subnet show desktop" "tunnel:" subnet show --name desktop
|
|
cmd::test::run_cmd "subnet show guests group" "guests" subnet show --name guests
|
|
cmd::test::run_cmd_fails "subnet show nonexistent" subnet show --name nonexistent
|
|
cmd::test::run_cmd "subnet add" "added" subnet add --name test-subnet --subnet 10.1.250.0/24 --type iot --desc "Test"
|
|
cmd::test::run_cmd "subnet list shows new" "test-subnet" subnet list
|
|
cmd::test::run_cmd_fails "subnet rename in-use (desktop)" subnet rename --name desktop --new-name workstation
|
|
cmd::test::run_cmd "subnet rename unused" "renamed" subnet rename --name test-subnet --new-name test-subnet-2
|
|
cmd::test::run_cmd "subnet rm" "removed" subnet rm --name test-subnet-2
|
|
cmd::test::run_cmd "subnet list --json" '"subnets":' subnet list --json
|
|
cmd::test::run_cmd "subnet --json has cidr" '"cidr":' subnet list --json
|
|
cmd::test::run_cmd "subnet --json is_group" '"is_group":' subnet list --json
|
|
cmd::test::run_cmd_fails "subnet rm nonexistent" subnet rm --name nonexistent-subnet
|
|
}
|
|
|
|
function cmd::test::section_identity() {
|
|
test::section "Identity"
|
|
cmd::test::run_cmd "identity list" "" identity list
|
|
cmd::test::run_cmd "identity migrate --dry-run" "Dry run" identity migrate --dry-run
|
|
cmd::test::run_cmd "identity show nuno" "nuno" identity show --name nuno
|
|
cmd::test::run_cmd "identity list --json" '"identities":' identity list --json
|
|
cmd::test::run_cmd "identity --json types array" '"types":[' identity list --json
|
|
cmd::test::run_cmd "identity --json rules array" '"rules":[' identity list --json
|
|
cmd::test::run_cmd_fails "identity show nonexistent" identity show --name nonexistent
|
|
}
|
|
|
|
function cmd::test::section_activity() {
|
|
test::section "Activity"
|
|
cmd::test::run_cmd "activity" "Activity" activity
|
|
cmd::test::run_cmd "activity --json" '"command":"activity"' activity --json
|
|
cmd::test::run_cmd "activity --json has data" '"data":' activity --json
|
|
cmd::test::run_cmd "activity --json has rx" '"rx":' activity --json
|
|
}
|
|
|
|
function cmd::test::section_policy() {
|
|
test::section "Policy"
|
|
cmd::test::run_cmd "policy list --json" '"policies":' policy list --json
|
|
cmd::test::run_cmd "policy --json has tunnel_mode" '"tunnel_mode":' policy list --json
|
|
cmd::test::run_cmd "policy --json strict_rule bool" '"strict_rule":false' policy list --json
|
|
}
|
|
|
|
function cmd::test::section_hosts() {
|
|
test::section "Hosts"
|
|
|
|
# Cleanup
|
|
"$WGCTL_BINARY" hosts rm --ip 192.0.2.1 --force > /dev/null 2>&1 || true
|
|
"$WGCTL_BINARY" hosts rm --port 9999 --force > /dev/null 2>&1 || true
|
|
|
|
cmd::test::run_cmd "hosts list" "Hosts" hosts list
|
|
cmd::test::run_cmd "hosts add --ip" "Added" hosts add --ip 192.0.2.1 --name test-host --desc "Test" --tags test,unit
|
|
cmd::test::run_cmd "hosts list shows new" "test-host" hosts list
|
|
cmd::test::run_cmd "hosts show --ip" "Name" hosts show --ip 192.0.2.1
|
|
cmd::test::run_cmd "hosts add --port" "Added" hosts add --port 9999 --name test-port
|
|
cmd::test::run_cmd "hosts list shows port" "test-port" hosts list
|
|
cmd::test::run_cmd "hosts rm --ip" "Removed" hosts rm --ip 192.0.2.1 --force
|
|
cmd::test::run_cmd "hosts rm --port" "Removed" hosts rm --port 9999 --force
|
|
cmd::test::run_cmd "hosts list --json" '"hosts":' hosts list --json
|
|
cmd::test::run_cmd "hosts --json has type" '"type":' hosts list --json
|
|
cmd::test::run_cmd "hosts --json has tags" '"tags":' hosts list --json
|
|
cmd::test::run_cmd_fails "hosts show nonexistent" hosts show --ip 192.0.2.99
|
|
cmd::test::run_cmd_fails "hosts add missing --name" hosts add --ip 192.0.2.1
|
|
}
|
|
|
|
function cmd::test::section_peer_cmd() {
|
|
test::section "Peer command"
|
|
|
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
|
"$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
|
|
|
|
# update-dns
|
|
cmd::test::run_cmd "peer update-dns --name" "Updated DNS" peer update-dns --name phone-testunit
|
|
cmd::test::run_cmd "peer update-dns applies" "10.0.0.103" config --name phone-testunit
|
|
cmd::test::run_cmd "peer update-dns --all" "peer(s)" peer update-dns --all
|
|
|
|
# update-tunnel
|
|
cmd::test::run_cmd "peer update-tunnel split" "split" peer update-tunnel --name phone-testunit --mode split
|
|
cmd::test::run_cmd "peer update-tunnel full" "Updated" peer update-tunnel --name phone-testunit --mode full
|
|
cmd::test::run_cmd_fails "peer update-tunnel bad mode" peer update-tunnel --name phone-testunit --mode invalid
|
|
cmd::test::run_cmd_fails "peer update-tunnel missing --mode" peer update-tunnel --name phone-testunit
|
|
cmd::test::run_cmd_fails "peer update-tunnel missing --name" peer update-tunnel --mode split
|
|
|
|
# Restore split tunnel
|
|
"$WGCTL_BINARY" peer update-tunnel --name phone-testunit --mode split > /dev/null 2>&1 || true
|
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
|
}
|
|
|
|
function cmd::test::section_group_purge() {
|
|
test::section "Group: purge-stale"
|
|
|
|
# dry-run should not modify anything
|
|
cmd::test::run_cmd "purge-stale --all --dry-run" \
|
|
"[dry-run]" \
|
|
group purge-stale --all --dry-run --force
|
|
|
|
# single group dry-run
|
|
cmd::test::run_cmd "purge-stale --name family --dry-run" \
|
|
"[dry-run]" \
|
|
group purge-stale --name family --dry-run --force
|
|
}
|
|
|
|
function cmd::test::section_logs_clean() {
|
|
test::section "Logs: clean"
|
|
|
|
cmd::test::run_cmd "logs clean --force" \
|
|
"keepalive" \
|
|
logs clean --force
|
|
}
|
|
|
|
function cmd::test::section_export() {
|
|
test::section "Export"
|
|
|
|
# Single peer export
|
|
cmd::test::run_cmd "export --peer" '"export_type":"peer"' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer has name" '"name":"phone-nuno"' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer has conf" '"conf":' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer has identity" '"identity":"nuno"' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer has groups" '"groups":' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer has blocks" '"blocks":' export --peer phone-nuno
|
|
cmd::test::run_cmd "export --peer conf-only" '"export_type":"peer_conf"' export --peer phone-nuno --conf-only
|
|
cmd::test::run_cmd "export --peer meta-only" '"export_type":"peer_meta"' export --peer phone-nuno --meta-only
|
|
cmd::test::run_cmd_fails "export missing flag" export
|
|
# Identity export
|
|
cmd::test::run_cmd "export --identity" '"export_type":"identity"' export --identity nuno
|
|
|
|
# Full backup
|
|
cmd::test::run_cmd "export --all" '"export_type"' export --all
|
|
cmd::test::run_cmd "export --all is full" '"full"' export --all
|
|
cmd::test::run_cmd "export --all has peers" '"peers"' export --all
|
|
cmd::test::run_cmd "export --all has rules" '"rules"' export --all
|
|
cmd::test::run_cmd "export --all has identities" '"identities"' export --all
|
|
cmd::test::run_cmd "export --all has config" '"config"' export --all
|
|
cmd::test::run_cmd "export --all no-config" '"peers"' export --all --no-config
|
|
# --no-config should NOT have config section
|
|
local no_config_out
|
|
no_config_out=$(wgctl export --all --no-config 2>/dev/null)
|
|
if echo "$no_config_out" | grep -qF '"config":'; then
|
|
test::fail "export --all --no-config should not have config section"
|
|
else
|
|
test::pass "export --all --no-config has no config section"
|
|
fi
|
|
|
|
# Export to file
|
|
local tmp_file="/tmp/wgctl_test_export_$$.json"
|
|
cmd::test::run_cmd "export --peer --out file" "Exported to" export --peer phone-nuno --out "$tmp_file"
|
|
[[ -f "$tmp_file" ]] && test::pass "export --out file exists" \
|
|
|| test::fail "export --out file not created"
|
|
rm -f "$tmp_file"
|
|
|
|
# Version in export
|
|
cmd::test::run_cmd "export has version" '"wgctl_version":' export --peer phone-nuno
|
|
}
|
|
|
|
function cmd::test::section_display() {
|
|
test::section "Display config"
|
|
|
|
cmd::test::run_cmd "display config exists" "" \
|
|
config show --name phone-nuno # just check wgctl works, not display directly
|
|
|
|
# Test style via unit tests (see unit section)
|
|
}
|
|
|
|
# ============================================
|
|
# Helpers
|
|
# ============================================
|
|
|
|
function cmd::test::assert() {
|
|
local desc="${1:-}" result="${2:-}" expected="${3:-}"
|
|
if [[ "$result" == "$expected" ]]; then
|
|
test::pass "$desc"
|
|
else
|
|
test::fail "${desc} (expected '${expected}', got '${result}')"
|
|
fi
|
|
}
|
|
|
|
function cmd::test::assert_true() {
|
|
local desc="${1:-}"
|
|
shift
|
|
if "$@" 2>/dev/null; then
|
|
test::pass "$desc"
|
|
else
|
|
test::fail "$desc (expected true, got false)"
|
|
fi
|
|
}
|
|
|
|
function cmd::test::assert_false() {
|
|
local desc="${1:-}"
|
|
shift
|
|
if ! "$@" 2>/dev/null; then
|
|
test::pass "$desc"
|
|
else
|
|
test::fail "$desc (expected false, got true)"
|
|
fi
|
|
} |