#!/usr/bin/env bash
# tests/netem-link/run-tests.sh -- guard for opentofu/modules/netem-link
# (D-100 netem mechanism; local-mode amendment 2026-07-21 per D-128: the
# outer root runs ON vcloud, so empty vcloud_host_ssh_target = bare local
# `sudo tc`, non-empty = the original Office1-era SSH hop). Static shape
# assertions + a tofu-validate fixture when tofu is available.
# Exit: 0 all pass | 1 any failed. ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MOD="$(cd "$HERE/../.." && pwd)/opentofu/modules/netem-link"
FRAG="$(cd "$HERE/../.." && pwd)/scripts/sudoers.d/netem-tc"
PASS=0; FAIL=0
ok(){ echo " PASS $1"; PASS=$((PASS+1)); }
no(){ echo " FAIL $1"; FAIL=$((FAIL+1)); }
# T1: module files present
for f in main.tf variables.tf outputs.tf; do
[ -f "$MOD/$f" ] || { no "T1 module files present ($f missing)"; echo; echo "netem-link: $PASS passed, $((FAIL)) failed"; exit 1; }
done
ok "T1 module files present"
# T2: terraform_data, not null_resource (OpenTofu's own recommendation)
grep -q 'resource "terraform_data" "netem"' "$MOD/main.tf" \
&& ! grep -v '^ *#' "$MOD/main.tf" | grep -q 'null_resource' \
&& ok "T2 terraform_data used (no null_resource)" \
|| no "T2 terraform_data used (no null_resource)"
# T3: re-apply triggers on bridge + args
grep -q 'triggers_replace = \[var.bridge_name, var.netem_args\]' "$MOD/main.tf" \
&& ok "T3 triggers_replace covers bridge_name + netem_args" \
|| no "T3 triggers_replace covers bridge_name + netem_args"
# T4: destroy-time values stashed in input (DOCFIX-194 pattern)
grep -q 'ssh_target *= *var.vcloud_host_ssh_target' "$MOD/main.tf" \
&& grep -q 'bridge_name *= *var.bridge_name' "$MOD/main.tf" \
&& ok "T4 input stash present for destroy provisioner" \
|| no "T4 input stash present for destroy provisioner"
# T5: destroy provisioner references ONLY self.* (var.* there is an INIT-time
# error -- the DOCFIX-194 class); assert no var. between 'when = destroy' and
# the end of that provisioner block
DESTROY_BLOCK="$(awk '/when *= *destroy/,/^ }/' "$MOD/main.tf")"
[ -n "$DESTROY_BLOCK" ] && ! grep -q 'var\.' <<<"$DESTROY_BLOCK" \
&& ok "T5 destroy provisioner references self.* only" \
|| no "T5 destroy provisioner references self.* only"
# T6: local mode -- empty target runs bare sudo tc in BOTH provisioners
grep -q 'var.vcloud_host_ssh_target != "" ?' "$MOD/main.tf" \
&& grep -q 'self.input.ssh_target != "" ?' "$MOD/main.tf" \
&& ok "T6 empty-target conditional present in apply + destroy" \
|| no "T6 empty-target conditional present in apply + destroy"
# T7: ssh mode retained (non-empty target still hops)
grep -q "ssh \${var.vcloud_host_ssh_target} 'sudo tc qdisc replace" "$MOD/main.tf" \
&& grep -q "ssh \${self.input.ssh_target} 'sudo tc qdisc del" "$MOD/main.tf" \
&& ok "T7 ssh hop retained for non-empty target" \
|| no "T7 ssh hop retained for non-empty target"
# T8: vcloud_host_ssh_target defaults to "" (local mode is the default)
awk '/variable "vcloud_host_ssh_target"/,/^}/' "$MOD/variables.tf" | grep -q 'default *= *""' \
&& ok "T8 vcloud_host_ssh_target default is empty (local)" \
|| no "T8 vcloud_host_ssh_target default is empty (local)"
# T9: idempotent verbs -- replace on apply, del || true on destroy
grep -q 'tc qdisc replace dev' "$MOD/main.tf" && grep -q "tc qdisc del dev" "$MOD/main.tf" \
&& grep -q '|| true' "$MOD/main.tf" \
&& ok "T9 replace on apply, del||true on destroy" \
|| no "T9 replace on apply, del||true on destroy"
# T10: no hardcoded virbrN in the module (bridge is a measured input)
grep -q 'virbr[0-9]' "$MOD"/*.tf \
&& no "T10 no virbrN literal in module sources" \
|| ok "T10 no virbrN literal in module sources"
# T11: module verbs stay inside the sudoers fragment's granted shapes
if [ -f "$FRAG" ]; then
grep -q 'qdisc replace dev virbr[0-9]* root netem \*' "$FRAG" \
&& grep -q 'qdisc del dev virbr[0-9]* root$' "$FRAG" \
&& ok "T11 module verbs covered by netem-tc fragment shapes" \
|| no "T11 module verbs covered by netem-tc fragment shapes"
else
echo " SKIP T11 sudoers fragment not present"
fi
# T12: tofu validate on a throwaway fixture instantiating BOTH modes
if command -v tofu >/dev/null 2>&1; then
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
cat >"$TMP/main.tf" <<EOF
module "local_mode" {
source = "$MOD"
link_name = "t-local"
bridge_name = "tbr0"
netem_args = "delay 1ms"
}
module "ssh_mode" {
source = "$MOD"
link_name = "t-ssh"
bridge_name = "tbr1"
vcloud_host_ssh_target = "user@host"
netem_args = "delay 1ms"
}
EOF
if (cd "$TMP" && tofu init -backend=false >/dev/null 2>&1 && tofu validate >/dev/null 2>&1); then
ok "T12 tofu validate passes (both modes instantiated)"
else
no "T12 tofu validate passes (both modes instantiated)"
fi
else
echo " SKIP T12 tofu not available"
fi
echo; echo "netem-link: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]