Files
archy/tests/regression/tollgate-nds-guard.py
T

98 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""Exercise the shipped router scripts with a disposable router filesystem."""
import os
import re
from pathlib import Path
import subprocess
import tempfile
REPO = Path(__file__).resolve().parents[2]
SCRIPTS = REPO / "core/openwrt/src/tollgate"
def run(scenario, prepare=False):
with tempfile.TemporaryDirectory(prefix="archy-nds-") as directory:
root = Path(directory)
for name in ("etc/config", "etc/init.d", "lib/functions", "tmp/etc", "proc", "bin"):
(root / name).mkdir(parents=True)
def write(name, content):
path = root / name
path.write_text(content)
path.chmod(0o755)
# Shell paths alone are redirected; guard logic is the production file.
def redirect(script):
return re.sub(r"/(?:etc|lib|tmp|proc|usr/bin)/", lambda m: str(root) + m[0], script)
write("lib/functions.sh", '''
config_load() { :; }
config_foreach() {
if [ "$SCENARIO" = prepare ]; then "$1" stock; "$1" custom;
elif [ "$SCENARIO" = extra ]; then "$1" rogue;
else "$1" main; fi
}
config_get_bool() { enabled=1; }
''')
write("lib/functions/network.sh", "# fixture network functions\n")
write("bin/uci", '''#!/bin/sh
echo "uci $*" >> "$FIXTURE/log"
case "$*" in
'get nodogsplash.main.enabled') echo 1;;
'get nodogsplash.main.gatewayinterface') echo br-tollgate;;
esac
''')
write("bin/sleep", "#!/bin/sh\nexit 0\n")
write("etc/init.d/nodogsplash", redirect('''#!/bin/sh
generate_uci_config() {
case "$SCENARIO" in
bad) echo 'GatewayInterface br-lan';;
duplicate) printf 'GatewayInterface br-tollgate\\nGatewayInterface br-lan\\n';;
matching-duplicate) printf 'GatewayInterface br-tollgate\\ngatewayinterface br-tollgate\\n';;
conflicting-lowercase) printf 'GatewayInterface br-tollgate\\ngatewayinterface br-lan\\n';;
missing) echo '# no gateway';;
*) echo 'GatewayInterface br-tollgate';;
esac > /tmp/etc/nodogsplash_main.conf
}
case "${1:-}" in
restart)
echo restart >> "$FIXTURE/log"
if [ "$SCENARIO" != absent ]; then
mkdir -p /proc/42
ln -s /usr/bin/nodogsplash /proc/42/exe
if [ "$SCENARIO" = wrongpath ]; then conf=/tmp/etc/other.conf
else conf=/tmp/etc/nodogsplash_main.conf; fi
printf '/usr/bin/nodogsplash\\000-c\\000%s\\000-f\\000' "$conf" > /proc/42/cmdline
fi;;
stop|disable|enable) echo "$1" >> "$FIXTURE/log";;
esac
'''))
previous = "preserve existing router configuration\n"
(root / "etc/config/nodogsplash").write_text(previous)
source = SCRIPTS / ("nds-prepare.sh" if prepare else "nds-restart.sh")
write("guard.sh", redirect(source.read_text()))
env = dict(os.environ, SCENARIO=scenario, FIXTURE=str(root),
PATH=str(root / "bin") + ":/usr/bin:/bin")
result = subprocess.run(["/bin/sh", str(root / "guard.sh")], env=env,
capture_output=True, text=True, timeout=5)
log = (root / "log").read_text() if (root / "log").exists() else ""
if prepare:
assert result.returncode == 0, result.stderr
backups = list((root / "etc/config").glob(".archy-nodogsplash-backup.*"))
assert len(backups) == 1 and backups[0].read_text() == previous
for section in ("stock", "custom", "main"):
assert f"uci set nodogsplash.{section}.enabled=0" in log
assert log.index("uci commit nodogsplash") < log.index("\nstop")
elif scenario in ("good", "matching-duplicate"):
assert result.returncode == 0, result.stderr
assert log.endswith("restart\nenable\n"), log
else:
assert result.returncode != 0, scenario
assert log.endswith("stop\ndisable\n"), log
assert "\nenable\n" not in log
if scenario in ("bad", "duplicate", "conflicting-lowercase", "missing", "extra"):
assert "restart\n" not in log, log
run("prepare", prepare=True)
for case in ("good", "matching-duplicate", "bad", "duplicate", "conflicting-lowercase", "missing", "extra", "wrongpath", "absent"):
run(case)
print("PASS: disabled install defaults, preserved configuration, render/start guards and failure cleanup")