From 046a10d692d1ac22de4daf783ee4fe025c4eb6ec Mon Sep 17 00:00:00 2001 From: Kirill Isakov Date: Mon, 19 Jul 2021 14:32:13 +0600 Subject: [PATCH] Rewrite the test suite for better compat and stability Keeps all of the previous checks, but uses tinc scripts instead of sleep(1) delays. Improves and/or adds compatibility with: - Windows (Msys2); - FreeBSD; - NetBSD; - OpenBSD. --- configure.ac | 1 + test/Makefile.am | 18 +- test/algorithms.test | 52 +++--- test/basic.test | 28 +-- test/commandline.test | 67 ++++--- test/executables.test | 14 +- test/import-export.test | 65 +++---- test/invite-join.test | 46 ++--- test/invite-offline.test | 48 ++--- test/invite-tinc-up.test | 70 ++++--- test/legacy-protocol.test | 102 +++++----- test/ns-ping.test | 85 +++++---- test/scripts.test | 164 +++++++++-------- test/security.test | 148 +++++++++------ test/sptps-basic.test | 51 +++-- test/testlib.sh.in | 378 +++++++++++++++++++++++++++++++++++--- test/variables.test | 119 ++++++------ 17 files changed, 933 insertions(+), 523 deletions(-) diff --git a/configure.ac b/configure.ac index 6d850ed4..f278e3c7 100644 --- a/configure.ac +++ b/configure.ac @@ -131,6 +131,7 @@ AM_CONDITIONAL(UML, test "$uml" = true) AM_CONDITIONAL(VDE, test "$vde" = true) AM_CONDITIONAL(TUNEMU, test "$tunemu" = true) AM_CONDITIONAL(WITH_SYSTEMD, test "$systemd" = true) +AM_CONDITIONAL(WITH_LEGACY_PROTOCOL, test "x$enable_legacy_protocol" != "xno") AC_CACHE_SAVE diff --git a/test/Makefile.am b/test/Makefile.am index dae30dcf..8c8d08fe 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,17 +1,25 @@ TESTS = \ basic.test \ - commandline.test \ executables.test \ + commandline.test \ import-export.test \ invite-join.test \ invite-offline.test \ invite-tinc-up.test \ - legacy-protocol.test \ - ns-ping.test \ + variables.test \ scripts.test \ security.test \ - sptps-basic.test \ - variables.test + sptps-basic.test + +if WITH_LEGACY_PROTOCOL +TESTS += \ + legacy-protocol.test \ + algorithms.test +endif + +if LINUX +TESTS += ns-ping.test +endif dist_check_SCRIPTS = $(TESTS) diff --git a/test/algorithms.test b/test/algorithms.test index c506a5d1..04d91310 100755 --- a/test/algorithms.test +++ b/test/algorithms.test @@ -1,46 +1,56 @@ #!/bin/sh +# shellcheck source=testlib.sh . "${0%/*}/testlib.sh" -# Initialize two nodes +echo [STEP] Initialize two nodes -$tinc $c1 <$d1/tinc-up <$d1/tinc-up.cmd <$d1/invitation-created <\$INVITATION_FILE -echo Ifconfig = 93.184.216.34/24 >>\$INVITATION_FILE -echo Route = 2606:2800:220:1::/64 2606:2800:220:1:248:1893:25c8:1946 >>\$INVITATION_FILE -echo Route = 1.2.3.4 1234:: >>\$INVITATION_FILE -$tinc $c1 export >>\$INVITATION_FILE -EOF - -cat >$d1/invitation-created.cmd <%INVITATION_FILE% -echo Ifconfig = 93.184.216.34/24 >>%INVITATION_FILE% -echo Route = 2606:2800:220:1::/64 2606:2800:220:1:248:1893:25c8:1946 >>%INVITATION_FILE% -echo Route = 1.2.3.4 1234:: >>%INVITATION_FILE% -$tinc $c1 export >>%INVITATION_FILE% -EOF - -chmod u+x $d1/invitation-created +# shellcheck disable=SC2016 +create_script foo invitation-created ' +cat >"$INVITATION_FILE" <$d1/tinc-up <$d2/tinc-up <$d1/$script << EOF -#!/bin/sh -echo $script \$NETNAME,\$NAME,\$DEVICE,\$IFACE,\$NODE,\$REMOTEADDRESS,\$REMOTEPORT,\$SUBNET,\$WEIGHT,\$INVITATION_FILE,\$INVITATION_URL,\$DEBUG >>$OUT +echo [STEP] Setting up scripts + +OUT=$DIR_FOO/scripts.out +rm -f "$OUT" + +for script in \ + tinc-up tinc-down \ + host-up host-down \ + subnet-up subnet-down \ + hosts/foo-up hosts/foo-down \ + hosts/bar-up hosts/bar-down \ + invitation-created invitation-accepted; do + + commands=$( + cat <>'$OUT' "$script" "$TINC_SCRIPT_VARS" EOF -chmod u+x $d1/$script + ) -cat >$d1/$script.cmd << EOF -echo $script %NETNAME%,%NAME%,%DEVICE%,%IFACE%,%NODE%,%REMOTEADDRESS%,%REMOTEPORT%,%SUBNET%,%WEIGHT%,%INVITATION_FILE%,%INVITATION_URL%,%DEBUG% >>$OUT -EOF + create_script foo "$script" "$commands" done -# Start server node - -echo Starting server node... - -$tinc $c1 -n netname start $r1 +echo [STEP] Starting server node -echo foo-started >>$OUT +start_tinc foo -n netname +wait_script foo subnet-up 2 +echo foo-started >>"$OUT" -# Invite client node +echo [STEP] Inviting client node -echo Inviting client node... +url=$(tinc foo -n netname2 invite bar) +file=$(basename "$(find "$DIR_FOO/invitations" -type f ! -name ed25519_key.priv)") -url=`$tinc $c1 -n netname2 invite bar | tr -d '\r'` -file=`cd $d1/invitations; ls | grep -v ed25519_key.priv` -echo bar-invited >>$OUT +if is_windows; then + file=$(cygpath --unix -- "$file") +fi -echo Joining client node... +wait_script foo invitation-created +echo bar-invited >>"$OUT" -$tinc $c2 -n netname3 join $url -echo bar-joined >>$OUT +echo [STEP] Joining client node -# Start and stop client node +tinc bar -n netname3 join "$url" +wait_script foo invitation-accepted +echo bar-joined >>"$OUT" -echo Starting client node... +echo [STEP] Starting client node -$tinc $c2 << EOF +tinc bar <>"$OUT" -echo bar-started >>$OUT +tinc foo debug 4 +tinc bar stop +wait_script foo subnet-down 2 +echo bar-stopped >>"$OUT" -$tinc $c1 debug 4 -$tinc $c2 stop +tinc foo debug 5 +start_tinc bar +wait_script foo subnet-up 2 +echo bar-started-2 >>"$OUT" -sleep 1 +echo [STEP] Stop server node -echo bar-stopped >>$OUT +tinc foo stop +tinc bar stop +wait_script foo tinc-down -$tinc $c1 debug 5 -$tinc $c2 start $r2 +echo [STEP] Check if the script output is what is expected -sleep 1 - -echo bar-started >>$OUT - -# Stop server node - -$tinc $c1 stop -sleep 1 -$tinc $c2 stop - -# Check if the script output is what is expected - -cat >$OUT.expected << EOF +cat >"$OUT.expected" <$OUT.actual - -cmp $OUT.actual $OUT.expected +diff -w "$OUT" "$OUT.expected" diff --git a/test/security.test b/test/security.test index 6c15bdab..91a5da52 100755 --- a/test/security.test +++ b/test/security.test @@ -1,103 +1,129 @@ #!/bin/sh +# shellcheck source=testlib.sh . "${0%/*}/testlib.sh" -# Skip this test if tools are missing +echo [STEP] Skip this test if tools are missing -which nc >/dev/null || exit 77 +which nc >/dev/null || exit $EXIT_SKIP_TEST +which timeout >/dev/null || exit $EXIT_SKIP_TEST -if [ "$(uname)" = "Darwin" ]; then - alias timeout=gtimeout -fi +foo_port=30050 +bar_port=30051 -which timeout >/dev/null || exit 77 +# usage: splice protocol_version +splice() { + ./splice foo localhost $foo_port bar localhost $bar_port "$1" & + sleep 10 +} -# Initialize two nodes +# usage: send_with_timeout "data to send" "data expected to receive" +send_with_timeout() { + data=$1 + expected=$3 -$tinc $c1 <$d1/out1 -cmp $d1/out1 Makefile +echo [STEP] Test transfer of a simple file -$sptps_test -4 -q $d1/server.priv $d1/client.pub 32750 $d1/out2 -cmp $d1/out2 Makefile +reference=sptps-basic.test -# Datagram mode +( + sleep 3 + $SPTPS_TEST -4 -q "$client_priv" "$server_pub" localhost $port <"$reference" +) & -$sptps_test -4 -dq $d1/server.priv $d1/client.pub 32750 $d1/out3 -cmp $d1/out3 Makefile +$SPTPS_TEST -4 "$server_priv" "$client_pub" $port >"$DIR_FOO/out1" +diff -w "$DIR_FOO/out1" "$reference" + +$SPTPS_TEST -4 -q "$server_priv" "$client_pub" $port <"$reference" & +sleep 3 +$SPTPS_TEST -4 "$client_priv" "$server_pub" localhost $port >"$DIR_FOO/out2" +diff -w "$DIR_FOO/out2" "$reference" + +echo [STEP] Datagram mode + +$SPTPS_TEST -4 -dq "$server_priv" "$client_pub" $port <"$reference" & +sleep 3 +sleep 3 | $SPTPS_TEST -4 -dq "$client_priv" "$server_pub" localhost $port >"$DIR_FOO/out3" +diff -w "$DIR_FOO/out3" "$reference" diff --git a/test/testlib.sh.in b/test/testlib.sh.in index 6a091cff..185aec0b 100644 --- a/test/testlib.sh.in +++ b/test/testlib.sh.in @@ -1,46 +1,368 @@ #!/bin/sh -# Paths to executables +set -ex + +echo [STEP] Initialize test library + +# Paths to compiled executables + +# realpath on FreeBSD fails if the path does not exist. +realdir() { + [ -e "$1" ] || mkdir -p "$1" + if type realpath >/dev/null; then + realpath "$1" + else + readlink -f "$1" + fi +} + +tincd_path=$(realdir "../src/tincd@EXEEXT@") +tinc_path=$(realdir "../src/tinc@EXEEXT@") + +SPTPS_TEST=$(realdir "../src/sptps_test@EXEEXT@") +SPTPS_KEYPAIR=$(realdir "../src/sptps_keypair@EXEEXT@") + +# Exit status list +EXIT_SKIP_TEST=77 -tincd=../src/tincd@EXEEXT@ -tinc=../src/tinc@EXEEXT@ -sptps_test=../src/sptps_test@EXEEXT@ -sptps_keypair=../src/sptps_keypair@EXEEXT@ +# The list of the environment variables that tinc injects into the scripts it calls. +# shellcheck disable=SC2016 +TINC_SCRIPT_VARS='$NETNAME,$NAME,$DEVICE,$IFACE,$NODE,$REMOTEADDRESS,$REMOTEPORT,$SUBNET,$WEIGHT,$INVITATION_FILE,$INVITATION_URL,$DEBUG' # Test directories -scriptname=`basename $0` +# Reuse script name if it was passed in an env var (when imported from tinc scripts). +if [ -z "$SCRIPTNAME" ]; then + SCRIPTNAME=$(basename "$0") +fi -n1=$scriptname.1 -n2=$scriptname.2 -n3=$scriptname.3 +# Network names for tincd daemons. +net1=$SCRIPTNAME.1 +net2=$SCRIPTNAME.2 +net3=$SCRIPTNAME.3 -d1=$PWD/$n1 -d2=$PWD/$n2 -d3=$PWD/$n3 +# Configuration/pidfile directories for tincd daemons. +DIR_FOO=$(realdir "$PWD/$net1") +DIR_BAR=$(realdir "$PWD/$net2") +DIR_BAZ=$(realdir "$PWD/$net3") -# Default arguments for both tinc and tincd +# Register helper functions -c1="-n $n1 --config=$d1 --pidfile=$d1/pid" -c2="-n $n2 --config=$d2 --pidfile=$d2/pid" -c3="-n $n3 --config=$d3 --pidfile=$d3/pid" +# Alias gtimeout to timeout if it exists. +if type gtimeout >/dev/null; then + timeout() { gtimeout "$@"; } +fi -# Arguments when running tincd +# Are the shell tools provided by busybox? +is_busybox() { + timeout --help 2>&1 | grep -q -i busybox +} -r1="--logfile=$d1/log -d5" -r2="--logfile=$d2/log -d5" -r3="--logfile=$d3/log -d5" +# busybox timeout returns 128 + signal number (which is TERM by default) +if is_busybox; then + EXIT_TIMEOUT=$((128 + 15)) +else + EXIT_TIMEOUT=124 +fi -# Check for leftover tinc daemons +# Is this msys2? +is_windows() { + test "$(uname -o)" = Msys +} -[ -f $d1/pid ] && $tinc $c1 stop -[ -f $d2/pid ] && $tinc $c2 stop -[ -f $d3/pid ] && $tinc $c3 stop +# Are we running on a CI server? +is_ci() { + test "$CI" +} -# Remove test directories +# Dump error message and exit with an error. +bail() { + echo >&2 "$@" + exit 1 +} -rm -rf $d1 $d2 $d3 +# Remove carriage returns to normalize strings on Windows for easier comparisons. +rm_cr() { + tr -d '\r' +} -# Exit on errors, log all commands being executed +# Executes whatever is passed to it, checking that the resulting exit code is non-zero. +must_fail() { + if "$@"; then + bail "expected a non-zero exit code" + fi +} -set -ex +# Runs its arguments with timeout(1) or gtimeout(1) if either are installed. +# Usage: try_limit_time 10 command --with --args +if type timeout >/dev/null; then + if is_busybox; then + # busybox does not support --foreground + try_limit_time() { + time=$1 + shift + timeout "$time" "$@" + } + else + # BSD and GNU timeout do not require special handling + try_limit_time() { + time=$1 + shift + timeout --foreground "$time" "$@" + } + fi +else + try_limit_time() { + echo >&2 "timeout was not found, running without time limits!" + shift + "$@" + } +fi + +# wc -l on mac prints whitespace before the actual number. +# This is simplest cross-platform alternative without that behavior. +count_lines() { + awk 'END{ print NR }' +} + +# Calls compiled tinc, passing any supplied arguments. +# Usage: tinc { foo | bar | baz } --arg1 val1 "$args" +tinc() { + peer=$1 + shift + + case "$peer" in + foo) try_limit_time 30 "$tinc_path" -n "$net1" --config="$DIR_FOO" --pidfile="$DIR_FOO/pid" "$@" ;; + bar) try_limit_time 30 "$tinc_path" -n "$net2" --config="$DIR_BAR" --pidfile="$DIR_BAR/pid" "$@" ;; + baz) try_limit_time 30 "$tinc_path" -n "$net3" --config="$DIR_BAZ" --pidfile="$DIR_BAZ/pid" "$@" ;; + *) bail "invalid command [[$peer $*]]" ;; + esac +} + +# Calls compiled tincd, passing any supplied arguments. +# Usage: tincd { foo | bar | baz } --arg1 val1 "$args" +tincd() { + peer=$1 + shift + + case "$peer" in + foo) try_limit_time 30 "$tincd_path" -n "$net1" --config="$DIR_FOO" --pidfile="$DIR_FOO/pid" --logfile="$DIR_FOO/log" -d5 "$@" ;; + bar) try_limit_time 30 "$tincd_path" -n "$net2" --config="$DIR_BAR" --pidfile="$DIR_BAR/pid" --logfile="$DIR_BAR/log" -d5 "$@" ;; + baz) try_limit_time 30 "$tincd_path" -n "$net3" --config="$DIR_BAZ" --pidfile="$DIR_BAZ/pid" --logfile="$DIR_BAZ/log" -d5 "$@" ;; + *) bail "invalid command [[$peer $*]]" ;; + esac +} + +# Start the specified tinc daemon. +# usage: start_tinc { foo | bar | baz } +start_tinc() { + peer=$1 + shift + + case "$peer" in + foo) tinc "$peer" start --logfile="$DIR_FOO/log" -d5 "$@" ;; + bar) tinc "$peer" start --logfile="$DIR_BAR/log" -d5 "$@" ;; + baz) tinc "$peer" start --logfile="$DIR_BAZ/log" -d5 "$@" ;; + *) bail "invalid peer $peer" ;; + esac +} + +# Stop all tinc clients. +stop_all_tincs() { + ( + # In case these pid files are mangled. + set +e + [ -f "$DIR_FOO/pid" ] && tinc foo stop + [ -f "$DIR_BAR/pid" ] && tinc bar stop + [ -f "$DIR_BAZ/pid" ] && tinc baz stop + true + ) +} + +# Checks that the number of reachable nodes matches what is expected. +# usage: require_nodes node_name expected_number +require_nodes() { + echo >&2 "Check that we're able to reach tincd" + test "$(tinc "$1" pid | count_lines)" = 1 + + echo >&2 "Check the number of reachable nodes for $1 (expecting $2)" + actual="$(tinc "$1" dump reachable nodes | count_lines)" + + if [ "$actual" != "$2" ]; then + echo >&2 "tinc $1: expected $2 reachable nodes, got $actual" + exit 1 + fi +} + +peer_directory() { + case "$peer" in + foo) echo "$DIR_FOO" ;; + bar) echo "$DIR_BAR" ;; + baz) echo "$DIR_BAZ" ;; + *) bail "invalid peer $peer" ;; + esac +} + +# This is an append-only log of all scripts executed by all peers. +script_runs_log() { + echo "$(peer_directory "$1")/script-runs.log" +} + +# Create tincd script. If it fails, it kills the test script with SIGTERM. +# usage: create_script { foo | bar | baz } { tinc-up | host-down | ... } 'script content' +create_script() { + peer=$1 + script=$2 + shift 2 + + # This is the line that we should start from when reading the script execution log while waiting + # for $script from $peer. It is a poor man's hash map to avoid polluting tinc's home directory with + # "last seen" files. There seem to be no good solutions to this that are compatible with all shells. + line_var=$(next_line_var "$peer" "$script") + + # We must reassign it here in case the script is recreated. + # shellcheck disable=SC2229 + read -r "$line_var" <"$script_log" + + # Script output is redirected into /dev/null. Otherwise, it ends up + # in tinc's output and breaks things like 'tinc invite'. + cat >"$script_path" <>"$script_log" +) >/dev/null 2>&1 || kill -TERM $$ +EOF + + chmod u+x "$script_path" + + if is_windows; then + echo "@$MINGW_SHELL '$script_path'" >"$script_path.cmd" + fi +} + +# Returns the name of the variable that contains the line number +# we should read next when waiting on $script from $peer. +# usage: next_line_var foo host-up +next_line_var() { + peer=$1 + script=$(echo "$2" | sed 's/[^a-zA-Z0-9]/_/g') + printf "%s" "next_line_${peer}_${script}" +} + +# Waits for `peer`'s script `script` to finish `count` number of times. +# usage: wait_script { foo | bar | baz } { tinc-up | host-up | ... } [count=1] +wait_script() { + peer=$1 + script=$2 + count=$3 + + if [ -z "$count" ] || [ "$count" -lt 1 ]; then + count=1 + fi + + # Find out the location of the log and how many lines we should skip + # (because we've already seen them in previous invocations of wait_script + # for current $peer and $script). + line_var=$(next_line_var "$peer" "$script") + + # eval is the only solution supported by POSIX shells. + # https://github.com/koalaman/shellcheck/wiki/SC3053 + # 1. $line_var expands into 'next_line_foo_hosts_bar_up' + # 2. the name is substituted and the command becomes 'echo "$next_line_foo_hosts_bar_up"' + # 3. the command is evaluated and the line number is assigned to $line + line=$(eval "echo \"\$$line_var\"") + + # This is the file that we monitor for script execution records. + script_log=$(script_runs_log "$peer") + + # Starting from $line, read until $count matches are found. + # Print the number of the last matching line and exit. + # GNU tail 2.82 and newer terminates by itself when the pipe breaks. + # To support other tails we do an explicit `kill`. + # FIFO is useful here because otherwise it's difficult to determine + # which tail process should be killed. We could stick them in a process + # group by enabling job control, but this results in weird behavior when + # running tests in parallel on some interactive shells + # (e.g. when /bin/sh is symlinked to dash). + new_line=$( + try_limit_time 60 sh -c " + fifo=\$$.fifo + cleanup() { rm -f \$fifo; } + cleanup && trap cleanup EXIT + + mkfifo \$$.fifo + tail -n '+$line' -f '$script_log' >\$fifo & + grep -n -m '$count' '^$script,' <\$fifo + kill \$! + " | awk -F: 'END { print $1 }' + ) + + # Remember the next line number for future reference. We'll use it if + # wait_script is called again with same $peer and $script. + read -r "${line_var?}" <&2 "CI server detected, performing aggressive cleanup" + kill_processes TERM tinc tincd + kill_processes KILL tinc tincd + fi + ) || true +} + +# Generate path to current shell which can be used from Windows applications. +if is_windows; then + MINGW_SHELL=$(cygpath --mixed -- "$SHELL") +fi + +# This was called from a tincd script. Skip executing commands with side effects. +[ -n "$NAME" ] && return + +echo [STEP] Check for leftover tinc daemons and test directories + +# Cleanup leftovers from previous runs. +stop_all_tincs + +# On Windows this can actually fail. We don't want to suppress possible failure with -f. +if [ -d "$DIR_FOO" ]; then rm -r "$DIR_FOO"; fi +if [ -d "$DIR_BAR" ]; then rm -r "$DIR_BAR"; fi +if [ -d "$DIR_BAZ" ]; then rm -r "$DIR_BAZ"; fi + +# Register cleanup function so we don't have to call it everywhere +# (and failed scripts do not leave stray tincd running). +trap cleanup EXIT INT TERM diff --git a/test/variables.test b/test/variables.test index d9494b4f..d4c606fe 100755 --- a/test/variables.test +++ b/test/variables.test @@ -1,86 +1,93 @@ #!/bin/sh +# shellcheck source=testlib.sh . "${0%/*}/testlib.sh" -# Initialize one node +echo [STEP] Initialize one node -$tinc $c1 init foo -test "`$tinc $c1 get Name | tr -d '\r'`" = "foo" +tinc foo init foo +test "$(tinc foo get Name)" = "foo" -# Test case sensitivity +echo [STEP] Test case sensitivity -$tinc $c1 set Mode switch -test "`$tinc $c1 get Mode | tr -d '\r'`" = "switch" -test "`$tinc $c1 get mode | tr -d '\r'`" = "switch" -$tinc $c1 set mode router -test "`$tinc $c1 get Mode | tr -d '\r'`" = "router" -test "`$tinc $c1 get mode | tr -d '\r'`" = "router" -$tinc $c1 set Mode Switch -test "`$tinc $c1 get Mode | tr -d '\r'`" = "Switch" +tinc foo set Mode switch +test "$(tinc foo get Mode)" = "switch" +test "$(tinc foo get mode)" = "switch" -# Test deletion +tinc foo set mode router +test "$(tinc foo get Mode)" = "router" +test "$(tinc foo get mode)" = "router" -$tinc $c1 del Mode hub && exit 1 || true -$tinc $c1 del Mode switch -test -z "`$tinc $c1 get Mode`" +tinc foo set Mode Switch +test "$(tinc foo get Mode)" = "Switch" -# There can only be one Mode variable +echo [STEP] Test deletion -$tinc $c1 add Mode switch -$tinc $c1 add Mode hub -test "`$tinc $c1 get Mode | tr -d '\r'`" = "hub" +must_fail tinc foo del Mode hub +tinc foo del Mode switch +test -z "$(tinc foo get Mode)" -# Test addition/deletion of multivalued variables +echo [STEP] There can only be one Mode variable -$tinc $c1 add Subnet 1 -$tinc $c1 add Subnet 2 -$tinc $c1 add Subnet 2 -$tinc $c1 add Subnet 3 -test "`$tinc $c1 get Subnet | tr -d '\r'`" = "1 +tinc foo add Mode switch +tinc foo add Mode hub +test "$(tinc foo get Mode)" = "hub" + +echo [STEP] Test addition/deletion of multivalued variables + +tinc foo add Subnet 1 +tinc foo add Subnet 2 +tinc foo add Subnet 2 +tinc foo add Subnet 3 +test "$(tinc foo get Subnet | rm_cr)" = "1 2 3" -$tinc $c1 del Subnet 2 -test "`$tinc $c1 get Subnet | tr -d '\r'`" = "1 + +tinc foo del Subnet 2 +test "$(tinc foo get Subnet | rm_cr)" = "1 3" -$tinc $c1 del Subnet -test -z "`$tinc $c1 get Subnet`" -# We should not be able to get/set server variables using node.variable syntax +tinc foo del Subnet +test -z "$(tinc foo get Subnet)" -test -z "`$tinc $c1 get foo.Name`" -$tinc $c1 set foo.Name bar && exit 1 || true +echo [STEP] We should not be able to get/set server variables using node.variable syntax -# Test getting/setting host variables for other nodes +test -z "$(tinc foo get foo.Name)" +must_fail tinc foo set foo.Name bar -touch $d1/hosts/bar +echo [STEP] Test getting/setting host variables for other nodes -$tinc $c1 add bar.PMTU 1 -$tinc $c1 add bar.PMTU 2 -test "`$tinc $c1 get bar.PMTU | tr -d '\r'`" = "2" +touch "$DIR_FOO/hosts/bar" -$tinc $c1 add bar.Subnet 1 -$tinc $c1 add bar.Subnet 2 -$tinc $c1 add bar.Subnet 2 -$tinc $c1 add bar.Subnet 3 -test "`$tinc $c1 get bar.Subnet | tr -d '\r'`" = "1 +tinc foo add bar.PMTU 1 +tinc foo add bar.PMTU 2 +test "$(tinc foo get bar.PMTU)" = "2" + +tinc foo add bar.Subnet 1 +tinc foo add bar.Subnet 2 +tinc foo add bar.Subnet 2 +tinc foo add bar.Subnet 3 +test "$(tinc foo get bar.Subnet | rm_cr)" = "1 2 3" -$tinc $c1 del bar.Subnet 2 -test "`$tinc $c1 get bar.Subnet | tr -d '\r'`" = "1 + +tinc foo del bar.Subnet 2 +test "$(tinc foo get bar.Subnet | rm_cr)" = "1 3" -$tinc $c1 del bar.Subnet -test -z "`$tinc $c1 get bar.Subnet`" -# We should not be able to get/set for nodes with invalid names +tinc foo del bar.Subnet +test -z "$(tinc foo get bar.Subnet)" + +echo [STEP] We should not be able to get/set for nodes with invalid names -touch $d1/hosts/qu-ux +touch "$DIR_FOO/hosts/qu-ux" +must_fail tinc foo set qu-ux.Subnet 1 -$tinc $c1 set qu-ux.Subnet 1 && exit 1 || true +echo [STEP] We should not be able to set obsolete variables unless forced -# We should not be able to set obsolete variables unless forced +must_fail tinc foo set PrivateKey 12345 +tinc foo --force set PrivateKey 12345 +test "$(tinc foo get PrivateKey)" = "12345" -$tinc $c1 set PrivateKey 12345 && exit 1 || true -$tinc $c1 --force set PrivateKey 12345 -test "`$tinc $c1 get PrivateKey | tr -d '\r'`" = "12345" -$tinc $c1 del PrivateKey -test -z "`$tinc $c1 get PrivateKey`" +tinc foo del PrivateKey +test -z "$(tinc foo get PrivateKey)" -- 2.20.1