nuno revisó este gist 1 month ago. Ir a la revisión
1 file changed, 252 insertions
integration.sh(archivo creado)
| @@ -0,0 +1,252 @@ | |||
| 1 | + | #!/usr/bin/env bash | |
| 2 | + | # test/integration.sh — integration test sections | |
| 3 | + | # Tests run against the live wgctl binary. | |
| 4 | + | # Sourced by test.command.sh — do not execute directly. | |
| 5 | + | ||
| 6 | + | WGCTL_BINARY="$(command -v wgctl)" | |
| 7 | + | ||
| 8 | + | # ============================================ | |
| 9 | + | # Helpers | |
| 10 | + | # ============================================ | |
| 11 | + | ||
| 12 | + | function cmd::test::_strip_ansi() { | |
| 13 | + | sed 's/\x1b\[[0-9;]*m//g' | |
| 14 | + | } | |
| 15 | + | ||
| 16 | + | function cmd::test::run_cmd() { | |
| 17 | + | local desc="$1" expected="${2:-}" | |
| 18 | + | shift 2 | |
| 19 | + | ||
| 20 | + | local tmp exit_code | |
| 21 | + | tmp=$(mktemp) | |
| 22 | + | ||
| 23 | + | set +e | |
| 24 | + | timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1 | |
| 25 | + | exit_code=$? | |
| 26 | + | set -e | |
| 27 | + | ||
| 28 | + | # Reset terminal color in case command output left ANSI state dirty | |
| 29 | + | printf "\033[0m" >&2 | |
| 30 | + | ||
| 31 | + | if [[ $exit_code -eq 124 ]]; then | |
| 32 | + | test::warn "${desc} (timed out after 30s)" | |
| 33 | + | rm -f "$tmp" | |
| 34 | + | return 1 | |
| 35 | + | fi | |
| 36 | + | ||
| 37 | + | local clean | |
| 38 | + | clean=$(cmd::test::_strip_ansi < "$tmp") | |
| 39 | + | ||
| 40 | + | if [[ $exit_code -ne 0 ]]; then | |
| 41 | + | local msg="${desc}" | |
| 42 | + | [[ -n "$expected" ]] && msg="${desc} (expected '${expected}', command failed)" | |
| 43 | + | test::fail "$msg" | |
| 44 | + | if [[ "${WGCTL_TEST_VERBOSE:-false}" == "true" ]]; then | |
| 45 | + | printf " Output: %s\n" "$(echo "$clean" | head -3 | tr '\n' ' ')" | |
| 46 | + | fi | |
| 47 | + | rm -f "$tmp" | |
| 48 | + | return 1 | |
| 49 | + | fi | |
| 50 | + | ||
| 51 | + | if [[ -n "$expected" ]] && ! echo "$clean" | grep -qF "$expected"; then | |
| 52 | + | local actual | |
| 53 | + | actual=$(echo "$clean" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100) | |
| 54 | + | test::fail "${desc} (expected '${expected}', got: '${actual}')" | |
| 55 | + | rm -f "$tmp" | |
| 56 | + | return 1 | |
| 57 | + | fi | |
| 58 | + | ||
| 59 | + | test::pass "$desc" | |
| 60 | + | rm -f "$tmp" | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | function cmd::test::run_cmd_any() { | |
| 64 | + | local desc="$1" expected="${2:-}" | |
| 65 | + | shift 2 | |
| 66 | + | ||
| 67 | + | local tmp | |
| 68 | + | tmp=$(mktemp) | |
| 69 | + | ||
| 70 | + | set +e | |
| 71 | + | timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1 | |
| 72 | + | set -e | |
| 73 | + | ||
| 74 | + | printf "\033[0m" >&2 | |
| 75 | + | ||
| 76 | + | local clean | |
| 77 | + | clean=$(cmd::test::_strip_ansi < "$tmp") | |
| 78 | + | ||
| 79 | + | if [[ -n "$expected" ]] && ! echo "$clean" | grep -qF "$expected"; then | |
| 80 | + | local actual | |
| 81 | + | actual=$(echo "$clean" | head -3 | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100) | |
| 82 | + | test::fail "${desc} (expected '${expected}', got: '${actual}')" | |
| 83 | + | rm -f "$tmp" | |
| 84 | + | return 1 | |
| 85 | + | fi | |
| 86 | + | ||
| 87 | + | test::pass "$desc" | |
| 88 | + | rm -f "$tmp" | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | function cmd::test::run_cmd_fails() { | |
| 92 | + | local desc="$1" | |
| 93 | + | shift | |
| 94 | + | ||
| 95 | + | local tmp exit_code | |
| 96 | + | tmp=$(mktemp) | |
| 97 | + | ||
| 98 | + | set +e | |
| 99 | + | timeout 10 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1 | |
| 100 | + | exit_code=$? | |
| 101 | + | set -e | |
| 102 | + | ||
| 103 | + | printf "\033[0m" >&2 | |
| 104 | + | rm -f "$tmp" | |
| 105 | + | ||
| 106 | + | if [[ $exit_code -eq 124 ]]; then | |
| 107 | + | test::warn "${desc} (timed out)" | |
| 108 | + | return 1 | |
| 109 | + | fi | |
| 110 | + | ||
| 111 | + | if [[ $exit_code -eq 0 ]]; then | |
| 112 | + | test::fail "${desc} (expected failure but succeeded)" | |
| 113 | + | return 1 | |
| 114 | + | fi | |
| 115 | + | ||
| 116 | + | test::pass "$desc" | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | # ============================================ | |
| 120 | + | # Sections | |
| 121 | + | # ============================================ | |
| 122 | + | ||
| 123 | + | function cmd::test::run_all_integration_sections() { | |
| 124 | + | cmd::test::section_list | |
| 125 | + | cmd::test::section_inspect | |
| 126 | + | cmd::test::section_config | |
| 127 | + | cmd::test::section_rules | |
| 128 | + | cmd::test::section_groups | |
| 129 | + | cmd::test::section_audit | |
| 130 | + | cmd::test::section_logs | |
| 131 | + | cmd::test::section_fw | |
| 132 | + | cmd::test::section_net | |
| 133 | + | cmd::test::section_subnet | |
| 134 | + | cmd::test::section_identity | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | function cmd::test::section_list() { | |
| 138 | + | test::section "List" | |
| 139 | + | cmd::test::run_cmd "list" "rule:" list | |
| 140 | + | cmd::test::run_cmd "list --online" "" list --online | |
| 141 | + | cmd::test::run_cmd "list --offline" "" list --offline | |
| 142 | + | cmd::test::run_cmd "list --blocked" "" list --blocked | |
| 143 | + | cmd::test::run_cmd "list --type phone" "phone" list --type phone | |
| 144 | + | cmd::test::run_cmd "list --detailed" "rule:" list --detailed | |
| 145 | + | cmd::test::run_cmd "list --name phone-nuno" "phone-nuno" list --name phone-nuno | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | function cmd::test::section_inspect() { | |
| 149 | + | test::section "Inspect" | |
| 150 | + | cmd::test::run_cmd "inspect --name phone-nuno" "IP:" inspect --name phone-nuno | |
| 151 | + | cmd::test::run_cmd "inspect --name nuno --type phone" "IP:" inspect --name nuno --type phone | |
| 152 | + | cmd::test::run_cmd "inspect --name phone-nuno --config" "PrivateKey" inspect --name phone-nuno --config | |
| 153 | + | cmd::test::run_cmd_fails "inspect nonexistent" inspect --name nonexistent-peer | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | function cmd::test::section_config() { | |
| 157 | + | test::section "Config & QR" | |
| 158 | + | cmd::test::run_cmd "config --name phone-nuno" "PrivateKey" config --name phone-nuno | |
| 159 | + | cmd::test::run_cmd "config --name nuno --type phone" "PrivateKey" config --name nuno --type phone | |
| 160 | + | cmd::test::run_cmd "qr --name phone-nuno" "" qr --name phone-nuno | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | function cmd::test::section_rules() { | |
| 164 | + | test::section "Rules" | |
| 165 | + | cmd::test::run_cmd "rule list" "user" rule list | |
| 166 | + | cmd::test::run_cmd "rule show --name guest" "Description" rule show --name guest | |
| 167 | + | cmd::test::run_cmd "rule show --name user" "Description" rule show --name user | |
| 168 | + | cmd::test::run_cmd "rule show --name admin" "Description" rule show --name admin | |
| 169 | + | cmd::test::run_cmd_fails "rule show nonexistent" rule show --name nonexistent | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | function cmd::test::section_groups() { | |
| 173 | + | test::section "Groups" | |
| 174 | + | cmd::test::run_cmd "group list" "Groups" group list | |
| 175 | + | cmd::test::run_cmd "group show --name family" "Peers:" group show --name family | |
| 176 | + | cmd::test::run_cmd_fails "group show nonexistent" group show --name nonexistent | |
| 177 | + | } | |
| 178 | + | ||
| 179 | + | function cmd::test::section_audit() { | |
| 180 | + | test::section "Audit" | |
| 181 | + | cmd::test::run_cmd_any "audit" "passed" audit | |
| 182 | + | cmd::test::run_cmd_any "audit --peer phone-nuno" "passed" audit --peer phone-nuno | |
| 183 | + | cmd::test::run_cmd_any "audit --type phone" "passed" audit --type phone | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | function cmd::test::section_logs() { | |
| 187 | + | test::section "Logs" | |
| 188 | + | cmd::test::run_cmd "logs" "Activity" logs | |
| 189 | + | cmd::test::run_cmd "logs --name phone-nuno" "Activity" logs --name phone-nuno | |
| 190 | + | cmd::test::run_cmd "logs --fw" "Firewall Drops" logs --fw | |
| 191 | + | cmd::test::run_cmd "logs --wg" "WireGuard Events" logs --wg | |
| 192 | + | } | |
| 193 | + | ||
| 194 | + | function cmd::test::section_fw() { | |
| 195 | + | test::section "Firewall" | |
| 196 | + | cmd::test::run_cmd "fw list" "FORWARD" fw list | |
| 197 | + | cmd::test::run_cmd "fw list --peer phone-nuno" "" fw list --peer phone-nuno | |
| 198 | + | cmd::test::run_cmd "fw list --no-nflog" "" fw list --no-nflog | |
| 199 | + | cmd::test::run_cmd "fw list --no-accept" "" fw list --no-accept | |
| 200 | + | cmd::test::run_cmd "fw list --no-drop" "" fw list --no-drop | |
| 201 | + | cmd::test::run_cmd "fw nat" "PREROUTING" fw nat | |
| 202 | + | cmd::test::run_cmd "fw count" "TOTAL" fw count | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | function cmd::test::section_net() { | |
| 206 | + | test::section "Net" | |
| 207 | + | "$WGCTL_BINARY" net rm --name test-svc --force > /dev/null 2>&1 || true | |
| 208 | + | ||
| 209 | + | cmd::test::run_cmd "net add service" "added" net add --name test-svc --ip 10.0.0.99 --desc "Test service" | |
| 210 | + | cmd::test::run_cmd "net add port" "Added" net add --name test-svc:web --port 9999:tcp | |
| 211 | + | cmd::test::run_cmd "net list" "test-svc" net list | |
| 212 | + | cmd::test::run_cmd "net list --detailed" "web" net list --detailed | |
| 213 | + | cmd::test::run_cmd "net show" "9999" net show --name test-svc | |
| 214 | + | cmd::test::run_cmd "net rm port" "Removed" net rm --name test-svc:web --force | |
| 215 | + | cmd::test::run_cmd "net add port again" "Added" net add --name test-svc:web --port 9999:tcp | |
| 216 | + | cmd::test::run_cmd "net rm all ports" "Removed" net rm --name test-svc:ports --force | |
| 217 | + | cmd::test::run_cmd "net rm service" "Removed" net rm --name test-svc --force | |
| 218 | + | cmd::test::run_cmd_fails "net show nonexistent" net show --name nonexistent-svc | |
| 219 | + | cmd::test::run_cmd_fails "net add port no service" net add --name nonexistent:web --port 80:tcp | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | function cmd::test::section_subnet() { | |
| 223 | + | test::section "Subnet" | |
| 224 | + | "$WGCTL_BINARY" subnet rm --name test-subnet-2 > /dev/null 2>&1 || true | |
| 225 | + | "$WGCTL_BINARY" subnet rm --name test-subnet > /dev/null 2>&1 || true | |
| 226 | + | ||
| 227 | + | cmd::test::run_cmd "subnet list" "desktop" subnet list | |
| 228 | + | cmd::test::run_cmd "subnet show desktop" "tunnel:" subnet show --name desktop | |
| 229 | + | cmd::test::run_cmd "subnet show guests group" "guests" subnet show --name guests | |
| 230 | + | cmd::test::run_cmd_fails "subnet show nonexistent" subnet show --name nonexistent | |
| 231 | + | ||
| 232 | + | cmd::test::run_cmd "subnet add" "added" \ | |
| 233 | + | subnet add --name test-subnet --subnet 10.1.250.0/24 --type iot --desc "Test" | |
| 234 | + | cmd::test::run_cmd "subnet list shows new" "test-subnet" \ | |
| 235 | + | subnet list | |
| 236 | + | cmd::test::run_cmd_fails "subnet rename in-use (desktop)" \ | |
| 237 | + | subnet rename --name desktop --new-name workstation | |
| 238 | + | cmd::test::run_cmd "subnet rename unused" "renamed" \ | |
| 239 | + | subnet rename --name test-subnet --new-name test-subnet-2 | |
| 240 | + | cmd::test::run_cmd "subnet rm" "removed" \ | |
| 241 | + | subnet rm --name test-subnet-2 | |
| 242 | + | cmd::test::run_cmd_fails "subnet rm nonexistent" \ | |
| 243 | + | subnet rm --name nonexistent-subnet | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | function cmd::test::section_identity() { | |
| 247 | + | test::section "Identity" | |
| 248 | + | cmd::test::run_cmd "identity list" "" identity list | |
| 249 | + | cmd::test::run_cmd "identity migrate --dry-run" "Dry run" identity migrate --dry-run | |
| 250 | + | cmd::test::run_cmd "identity show nuno" "nuno" identity show --name nuno | |
| 251 | + | cmd::test::run_cmd_fails "identity show nonexistent" identity show --name nonexistent | |
| 252 | + | } | |
Siguiente
Anterior