Files
infix/test/env
T
Tobias WaldekranzandJoachim Wiberg a2906acdf7 test: Optionally use deterministic topology mappings
Due to the salting being applied to Python's `hash()` (see [1]), the
hash of an object is not stable across different Python processes. As
a result, neither are the topology mappings generated by networkx.

The upside of this is randomness that we get better test coverage over
time, especially on physical devices where the underlying hardware
could differ between ports, for example.

On the other hand, it can be very frustrating to track down a bug when
locial nodes are suffled around between phyical nodes on each
invocation of a test case.

Therefore, use a random seed by default, but allow the user to specify
a fixed value if they so choose. We then add a meta test that logs the
seed being used for the current suite - which means we can simply
copy&paste that value to rerun the suite (or single test) with the
same topology mappings.

[1]: https://docs.python.org/3/reference/datamodel.html#object.__hash__
2024-05-03 14:44:54 +02:00

202 lines
4.2 KiB
Bash
Executable File

#!/bin/sh
set -e
testdir=$(dirname "$(readlink -f "$0")")
. "$testdir/.env"
usage()
{
cat <<EOF
usage: test/env [<OPTS>] -f <IMAGE> -q <QENETH-DIR> <COMMAND> [<ARGS>...]
test/env [<OPTS>] -C -t <TOPOLOGY> <COMMAND> [<ARGS>...]
Run <COMMAND> in a pre-packaged container with all the packages
required for running the test suite installed.
Options:
-c
Clean up cruft, lingering images, old containers, unused volumes.
Used by GitHub action to prevent issues with runnign tests.
-C
Don't containerize the command, run it directly in the current
namespaces
-f <IMAGE>
Specify images required for test, squashfs image is required
if testing with kernel. bios and disk image is required if
testing with bios.
-h
Show this help message
-K
Even if /dev/kvm is usable, do not map it the container. This is
useful to see how tests will run in a CI setting, where KVM is
typically not available
-p <BUNDLE>
Infix RAUC bundle to use for upgrade tests.
-q <QENETH-DIR>
Directory containing a topology.dot.in, suitable for consumption
by qeneth. A copy of this network is created, and launched. The
resulting topology is used as the default physical topology when
running tests
-t <TOPOLOGY>
Rather than starting a qeneth network, attach to this existing
topology. Mostly useful together with -C
EOF
}
start_topology()
{
qenethdir="$1"
files="$*"
[ "$files" ] || { true && return; }
[ "$qenethdir" ] || { true && return; }
rm -rf "$envdir/qeneth"
cp -a "$qenethdir" "$envdir/qeneth"
# Map files in to qeneth
for f in $files; do
filename="$(basename "$f")"
file=$(readlink -f "$f")
ln -sf "$file" "$envdir/qeneth/$filename"
done
(cd "$envdir/qeneth/" && $qeneth generate && $qeneth start)
INFAMY_ARGS="$INFAMY_ARGS $envdir/qeneth/topology.dot"
cat <<EOF >"$envdir/bin/qeneth"
#!/bin/sh
set -x
cd $envdir/qeneth && exec $testdir/qeneth/qeneth "\$@"
EOF
chmod +x "$envdir/bin/qeneth"
}
name()
{
nm=infamy
id=0
names=$($(runner) ps -f name='infamy.*' --format '{{.Names}}')
while true; do
name="$nm$id"
unset hit
for n in $names; do
if [ "$name" = "$n" ]; then
hit=true
break;
fi
done
if [ -n "$hit" ]; then
id=$((id + 1))
continue
fi
break;
done
echo "$name"
}
# Global options
containerize=yes
[ -c /dev/kvm ] && kvm="--device=/dev/kvm"
files=
while getopts "cCf:hiKp:q:t:" opt; do
case ${opt} in
c)
$(runner) image prune -af
$(runner) volume prune -f
$(runner) container prune -f
exit 0
;;
C)
containerize=
;;
f)
files="$files $OPTARG"
;;
h)
usage && exit 0
;;
i)
interactive="--interactive"
;;
K)
kvm=
;;
p)
INFAMY_ARGS="$INFAMY_ARGS -p $OPTARG"
;;
q)
qenethdir="$OPTARG"
;;
t)
topology="$OPTARG"
;;
*)
>&2 echo "Unknown option -$opt"
usage
exit 1
;;
esac
done
if [ "$containerize" ]; then
# shellcheck disable=SC2016
exec $(runner) run \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
--device=/dev/net/tun \
--env PYTHONHASHSEED=${PYTHONHASHSEED:-$(shuf -i 0-$(((1 << 32) - 1)) -n 1)} \
--env VIRTUAL_ENV_DISABLE_PROMPT=yes \
--env PROMPT_DIRTRIM="$ixdir" \
--env PS1='\e[1m$(date "+%H:%M:%S") \h\e[0m:\W # ' \
--expose 9001-9010 --publish-all \
--hostname "$(name)" \
--name "$(name)" \
$interactive \
--rm \
--security-opt seccomp=unconfined \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
--tty \
--volume "$ixdir":"$ixdir" \
--workdir "$ixdir/test" \
$kvm \
$INFIX_TEST \
"$0" -C "$@"
else
if [ ! -f ~/.9pm.rc ]; then
cat <<-EOF >~/.9pm.rc
# Generated by Infix env
SSH_OPTS: "-o StrictHostKeyChecking=no"
LOG_PATH: "$logdir"
EOF
fi
fi
shift $((OPTIND - 1))
if [ $# -lt 1 ]; then
usage && exit 1
fi
# shellcheck disable=SC1091
. "$envdir/bin/activate"
export PYTHONPATH="$testdir"
INFAMY_ARGS="$INFAMY_ARGS -y $envdir/yangdir"
start_topology "$qenethdir" "$files"
[ "$topology" ] && INFAMY_ARGS="$INFAMY_ARGS $topology"
export INFAMY_ARGS
exec "$@"