Files
Alexandru Ardelean f6e2e2815a miniupnpd: add test script
Add a CI test.sh covering both firewall variants. It verifies the daemon
binary links and prints its usage banner, that the procd init script, UCI
config and iface hotplug files are installed, and that the variant-specific
firewall assets ship: fw3 include for iptables, nft fragments for nftables.
It also drives the config-file parser, which runs before firewall setup,
with an invalid and a valid config to confirm both paths behave.

Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
2026-10-07 09:35:48 +03:00

94 lines
3.4 KiB
Bash
Executable File

#!/bin/sh
# Functional tests for the miniupnpd IGD/NAT-PMP daemon variants. The package
# version is checked by the build framework, so it is not tested here.
bin=/usr/sbin/miniupnpd
# Binary, runtime linking and the OpenWrt integration files common to both
# firewall variants. "miniupnpd -h" exits non-zero but must print the usage
# banner, which also proves every shared-library dep resolves at runtime.
common_checks() {
[ -x "$bin" ] || { echo "FAIL: $bin missing or not executable"; exit 1; }
"$bin" -h 2>&1 | grep -q "^Usage:" \
|| { echo "FAIL: 'miniupnpd -h' printed no usage banner"; exit 1; }
[ -x /etc/init.d/miniupnpd ] || { echo "FAIL: init script missing"; exit 1; }
grep -q "USE_PROCD=1" /etc/init.d/miniupnpd \
|| { echo "FAIL: init script is not a procd service"; exit 1; }
grep -q "config upnpd" /etc/config/upnpd \
|| { echo "FAIL: /etc/config/upnpd is not valid UCI"; exit 1; }
[ -f /etc/hotplug.d/iface/50-miniupnpd ] \
|| { echo "FAIL: iface hotplug script missing"; exit 1; }
}
# The config-file parser runs before any firewall or socket setup, so it can be
# exercised inside the CI container. A bogus option must be rejected non-zero
# and a minimal valid config must be accepted without a parse error.
config_checks() {
good="/tmp/miniupnpd-good.$$.conf"
bad="/tmp/miniupnpd-bad.$$.conf"
log="/tmp/miniupnpd.$$.log"
cat > "$good" <<-EOF
ext_ifname=lo
listening_ip=127.0.0.1
port=5000
enable_natpmp=yes
enable_upnp=yes
notify_interval=60
uuid=00000000-0000-0000-0000-000000000000
EOF
echo "not_a_real_option=1" > "$bad"
if "$bin" -f "$bad" -d > "$log" 2>&1; then
echo "FAIL: invalid config option was accepted"
rm -f "$good" "$bad" "$log"; exit 1
fi
grep -qiE "invalid option|Error reading configuration" "$log" \
|| { echo "FAIL: no parse error reported for bad config"
rm -f "$good" "$bad" "$log"; exit 1; }
# A valid config: launch briefly and confirm the parser accepted it. The
# daemon may later stop at firewall/socket setup in the container; that is
# past the parser and irrelevant to this check.
"$bin" -f "$good" -d > "$log" 2>&1 &
mpid=$!
sleep 2
kill "$mpid" 2>/dev/null
wait "$mpid" 2>/dev/null
if grep -qiE "invalid option|Error reading configuration" "$log"; then
echo "FAIL: valid config was rejected by the parser"
rm -f "$good" "$bad" "$log"; exit 1
fi
rm -f "$good" "$bad" "$log"
}
case "$1" in
miniupnpd-iptables)
# iptables variant ships the fw3 shell include. Its uci-defaults seeder
# is not checked here: the postinst sources /etc/uci-defaults/* and
# deletes each script that succeeds, so it is gone by now.
common_checks
[ -f /usr/share/miniupnpd/firewall.include ] || { echo "FAIL: firewall.include missing"; exit 1; }
sh -n /usr/share/miniupnpd/firewall.include \
|| { echo "FAIL: firewall.include has a shell syntax error"; exit 1; }
config_checks
echo "miniupnpd-iptables: all functional tests passed"
;;
miniupnpd-nftables)
# nftables variant ships the nft rule fragments consumed by fw4.
common_checks
for f in table-post/20-miniupnpd.nft \
chain-post/dstnat/20-miniupnpd.nft \
chain-post/forward/20-miniupnpd.nft \
chain-post/srcnat/20-miniupnpd.nft; do
[ -s "/usr/share/nftables.d/$f" ] \
|| { echo "FAIL: nft fragment $f missing or empty"; exit 1; }
done
config_checks
echo "miniupnpd-nftables: all functional tests passed"
;;
*)
echo "Untested package: $1" >&2
exit 1
;;
esac