summaryrefslogtreecommitdiff
path: root/.github/workflows
diff options
context:
space:
mode:
authorJoseph Henry <[email protected]>2023-05-01 09:07:03 -0700
committerGitHub <[email protected]>2023-05-01 09:07:03 -0700
commite6802690b854a5ddf8a042f5b3f29ceb6358d447 (patch)
tree1f6f5888f3db41bb66596c92e3be186127bf26a0 /.github/workflows
parent595e033776db24ee308b1841f4c00e49f7790a3c (diff)
Add short-term validation test workflow (#1974)
Add short-term validation test workflow
Diffstat (limited to '.github/workflows')
-rwxr-xr-x.github/workflows/report.sh15
-rwxr-xr-x.github/workflows/validate-1m-linux.sh401
-rw-r--r--.github/workflows/validate.yml57
3 files changed, 473 insertions, 0 deletions
diff --git a/.github/workflows/report.sh b/.github/workflows/report.sh
new file mode 100755
index 00000000..cc671621
--- /dev/null
+++ b/.github/workflows/report.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+################################################################################
+# Set exit code depending on tool reports #
+################################################################################
+
+DEFINITELY_LOST=$(cat *test-results/*summary.json | jq .num_definite_bytes_lost)
+
+cat *test-results/*summary.json
+
+echo -e "\nBytes of memory definitely lost: $DEFINITELY_LOST"
+
+if [[ "$DEFINITELY_LOST" -gt 0 ]]; then
+ exit 1
+fi
diff --git a/.github/workflows/validate-1m-linux.sh b/.github/workflows/validate-1m-linux.sh
new file mode 100755
index 00000000..0a8dbf4d
--- /dev/null
+++ b/.github/workflows/validate-1m-linux.sh
@@ -0,0 +1,401 @@
+#!/bin/bash
+
+# This test script joins Earth and pokes some stuff
+
+TEST_NETWORK=8056c2e21c000001
+RUN_LENGTH=10
+TEST_FINISHED=false
+ZTO_VER=$(git describe --tags $(git rev-list --tags --max-count=1))
+ZTO_COMMIT=$(git rev-parse HEAD)
+ZTO_COMMIT_SHORT=$(git rev-parse --short HEAD)
+TEST_DIR_PREFIX="$ZTO_VER-$ZTO_COMMIT_SHORT-test-results"
+echo "Performing test on: $ZTO_VER-$ZTO_COMMIT_SHORT"
+TEST_FILEPATH_PREFIX="$TEST_DIR_PREFIX/$ZTO_COMMIT_SHORT"
+mkdir $TEST_DIR_PREFIX
+
+################################################################################
+# Multi-node connectivity and performance test #
+################################################################################
+
+NS1="ip netns exec ns1"
+NS2="ip netns exec ns2"
+
+ZT1="$NS1 ./zerotier-cli -D$(pwd)/node1"
+ZT2="$NS2 ./zerotier-cli -D$(pwd)/node2"
+
+echo -e "Setting up network namespaces..."
+echo "Setting up ns1"
+
+ip netns add ns1
+$NS1 ip link set dev lo up
+ip link add veth0 type veth peer name veth1
+ip link set veth1 netns ns1
+ip addr add 192.168.0.1/24 dev veth0
+ip link set dev veth0 up
+
+$NS1 ip addr add 192.168.0.2/24 dev veth1
+$NS1 ip link set dev veth1 up
+
+# Add default route
+$NS1 ip route add default via 192.168.0.1
+
+iptables -t nat -A POSTROUTING -s 192.168.0.0/255.255.255.0 \
+ -o eth0 -j MASQUERADE
+iptables -A FORWARD -i eth0 -o veth0 -j ACCEPT
+iptables -A FORWARD -o eth0 -i veth0 -j ACCEPT
+
+echo "Setting up ns2"
+ip netns add ns2
+$NS2 ip link set dev lo up
+ip link add veth2 type veth peer name veth3
+ip link set veth3 netns ns2
+ip addr add 192.168.1.1/24 dev veth2
+ip link set dev veth2 up
+
+$NS2 ip addr add 192.168.1.2/24 dev veth3
+$NS2 ip link set dev veth3 up
+$NS2 ip route add default via 192.168.1.1
+
+iptables -t nat -A POSTROUTING -s 192.168.1.0/255.255.255.0 \
+ -o eth0 -j MASQUERADE
+iptables -A FORWARD -i eth0 -o veth2 -j ACCEPT
+iptables -A FORWARD -o eth0 -i veth2 -j ACCEPT
+
+# Allow forwarding
+sysctl -w net.ipv4.ip_forward=1
+
+echo -e "\nPing from host to namespaces"
+
+#ping -c 4 192.168.0.1
+#ping -c 4 192.168.1.1
+
+echo -e "\nPing from namespace to host"
+
+#$NS1 ping -c 4 192.168.0.1
+#$NS1 ping -c 4 192.168.0.1
+#$NS2 ping -c 4 192.168.0.2
+#$NS2 ping -c 4 192.168.0.2
+
+echo -e "\nPing from ns1 to ns2"
+
+#$NS1 ping -c 4 192.168.0.1
+
+echo -e "\nPing from ns2 to ns1"
+
+#$NS2 ping -c 4 192.168.0.1
+
+################################################################################
+# Memory Leak Check #
+################################################################################
+
+FILENAME_MEMORY_LOG="$TEST_FILEPATH_PREFIX-memory.log"
+
+echo -e "\nStarting a ZeroTier instance in each namespace..."
+
+time_test_start=`date +%s`
+
+echo "Starting memory leak check"
+$NS1 sudo valgrind --demangle=yes --exit-on-first-error=yes \
+ --error-exitcode=1 \
+ --xml=yes \
+ --xml-file=$FILENAME_MEMORY_LOG \
+ --leak-check=full \
+ ./zerotier-one node1 >>node_1.log 2>&1 &
+
+# Second instance, not run in memory profiler
+$NS2 ./zerotier-one node2 >>node_2.log 2>&1 &
+
+################################################################################
+# Online Check #
+################################################################################
+
+echo "Waiting for ZeroTier to come online before attempting test..."
+MAX_WAIT_SECS="${MAX_WAIT_SECS:-120}"
+node1_online=false
+node2_online=false
+both_instances_online=false
+time_zt_node1_start=`date +%s`
+time_zt_node2_start=`date +%s`
+
+for ((s=0; s<=MAX_WAIT_SECS; s++))
+do
+ node1_online="$($ZT1 -j info | jq '.online' 2>/dev/null)"
+ node2_online="$($ZT2 -j info | jq '.online' 2>/dev/null)"
+ if [[ "$node1_online" == "true" ]]
+ then
+ time_zt_node1_online=`date +%s`
+ fi
+ if [[ "$node2_online" == "true" ]]
+ then
+ time_zt_node2_online=`date +%s`
+ fi
+ if [[ "$node2_online" == "true" && "$node1_online" == "true" ]]
+ then
+ both_instances_online=true
+ break
+ fi
+ sleep 1
+done
+
+if [[ "$both_instances_online" != "true" ]]
+then
+ echo "One or more instances of ZeroTier failed to come online. Aborting test." >&2
+ exit 1
+fi
+
+echo -e "\nChecking status of each instance:"
+
+$ZT1 status
+$ZT2 status
+
+echo -e "\nJoining networks"
+
+$ZT1 join $TEST_NETWORK
+$ZT2 join $TEST_NETWORK
+
+sleep 10
+
+node1_ip4=$($ZT1 get $TEST_NETWORK ip4)
+node2_ip4=$($ZT2 get $TEST_NETWORK ip4)
+
+echo "node1_ip4=$node1_ip4"
+echo "node2_ip4=$node2_ip4"
+
+echo -e "\nPinging each node"
+
+PING12_FILENAME="$TEST_FILEPATH_PREFIX-ping-1-to-2.txt"
+PING21_FILENAME="$TEST_FILEPATH_PREFIX-ping-2-to-1.txt"
+
+$NS1 ping -c 16 $node2_ip4 > $PING12_FILENAME
+$NS2 ping -c 16 $node1_ip4 > $PING21_FILENAME
+
+# Parse ping statistics
+ping_loss_percent_1_to_2="${ping_loss_percent_1_to_2:-100.0}"
+ping_loss_percent_2_to_1="${ping_loss_percent_2_to_1:-100.0}"
+
+ping_loss_percent_1_to_2=$(cat $PING12_FILENAME | \
+ grep "packet loss" | awk '{print $6}' | sed 's/%//')
+ping_loss_percent_2_to_1=$(cat $PING21_FILENAME | \
+ grep "packet loss" | awk '{print $6}' | sed 's/%//')
+
+# Normalize loss value
+ping_loss_percent_1_to_2=$(echo "scale=2; $ping_loss_percent_1_to_2/100.0" | bc)
+ping_loss_percent_2_to_1=$(echo "scale=2; $ping_loss_percent_2_to_1/100.0" | bc)
+
+################################################################################
+# CLI Check #
+################################################################################
+
+echo "Testing basic CLI functionality..."
+
+# Rapidly spam the CLI with joins/leaves
+
+SPAM_TRIES=128
+
+for ((s=0; s<=SPAM_TRIES; s++))
+do
+ $ZT1 join $TEST_NETWORK
+done
+
+for ((s=0; s<=SPAM_TRIES; s++))
+do
+ $ZT1 leave $TEST_NETWORK
+done
+
+for ((s=0; s<=SPAM_TRIES; s++))
+do
+ $ZT1 leave $TEST_NETWORK
+ $ZT1 join $TEST_NETWORK
+done
+
+$ZT1 join $TEST_NETWORK
+
+$ZT1 -h
+$ZT1 -v
+$ZT1 status
+$ZT1 info
+$ZT1 listnetworks
+$ZT1 peers
+$ZT1 listpeers
+
+$ZT1 -j status
+$ZT1 -j info
+$ZT1 -j listnetworks
+$ZT1 -j peers
+$ZT1 -j listpeers
+
+$ZT1 dump
+
+$ZT1 get $TEST_NETWORK allowDNS
+$ZT1 get $TEST_NETWORK allowDefault
+$ZT1 get $TEST_NETWORK allowGlobal
+$ZT1 get $TEST_NETWORK allowManaged
+$ZT1 get $TEST_NETWORK bridge
+$ZT1 get $TEST_NETWORK broadcastEnabled
+$ZT1 get $TEST_NETWORK dhcp
+$ZT1 get $TEST_NETWORK id
+$ZT1 get $TEST_NETWORK mac
+$ZT1 get $TEST_NETWORK mtu
+$ZT1 get $TEST_NETWORK name
+$ZT1 get $TEST_NETWORK netconfRevision
+$ZT1 get $TEST_NETWORK nwid
+$ZT1 get $TEST_NETWORK portDeviceName
+$ZT1 get $TEST_NETWORK portError
+$ZT1 get $TEST_NETWORK status
+$ZT1 get $TEST_NETWORK type
+
+# Test an invalid command
+$ZT1 get $TEST_NETWORK derpderp
+
+# TODO: Validate JSON
+
+################################################################################
+# Performance Test #
+################################################################################
+
+FILENAME_PERF_JSON="$TEST_FILEPATH_PREFIX-iperf.json"
+
+echo -e "\nBeginning performance test:"
+
+echo -e "\nStarting server:"
+
+echo "$NS1 iperf3 -s &"
+sleep 1
+
+echo -e "\nStarting client:"
+sleep 1
+
+echo "$NS2 iperf3 --json -c $node1_ip4 > $FILENAME_PERF_JSON"
+
+cat $FILENAME_PERF_JSON
+
+################################################################################
+# Collect ZeroTier dump files #
+################################################################################
+
+echo -e "\nCollecting ZeroTier dump files"
+
+node1_id=$($ZT1 -j status | jq -r .address)
+node2_id=$($ZT2 -j status | jq -r .address)
+
+$ZT1 dump
+mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node1_id.txt"
+
+$ZT2 dump
+mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node2_id.txt"
+
+################################################################################
+# Let ZeroTier idle long enough for various timers #
+################################################################################
+
+echo -e "\nIdling ZeroTier for $RUN_LENGTH seconds..."
+sleep $RUN_LENGTH
+
+echo -e "\nLeaving networks"
+
+$ZT1 leave $TEST_NETWORK
+$ZT2 leave $TEST_NETWORK
+
+sleep 5
+
+################################################################################
+# Stop test #
+################################################################################
+
+echo -e "\nStopping memory check..."
+sudo pkill -15 -f valgrind
+sleep 10
+
+time_test_end=`date +%s`
+
+################################################################################
+# Rename ZeroTier stdout/stderr logs #
+################################################################################
+
+mv node_1.log "$TEST_FILEPATH_PREFIX-node-log-$node1_id.txt"
+mv node_2.log "$TEST_FILEPATH_PREFIX-node-log-$node2_id.txt"
+
+################################################################################
+# Generate report #
+################################################################################
+
+cat $FILENAME_MEMORY_LOG
+
+DEFINITELY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \
+ $FILENAME_MEMORY_LOG | grep "definitely" | awk '{print $1;}')
+POSSIBLY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \
+ $FILENAME_MEMORY_LOG | grep "possibly" | awk '{print $1;}')
+
+################################################################################
+# Generate coverage report artifact and summary #
+################################################################################
+
+FILENAME_COVERAGE_JSON="$TEST_FILEPATH_PREFIX-coverage.json"
+FILENAME_COVERAGE_HTML="$TEST_FILEPATH_PREFIX-coverage.html"
+
+echo -e "\nGenerating coverage test report..."
+
+gcovr -r . --exclude ext --json-summary $FILENAME_COVERAGE_JSON \
+ --html > $FILENAME_COVERAGE_HTML
+
+cat $FILENAME_COVERAGE_JSON
+
+COVERAGE_LINE_COVERED=$(cat $FILENAME_COVERAGE_JSON | jq .line_covered)
+COVERAGE_LINE_TOTAL=$(cat $FILENAME_COVERAGE_JSON | jq .line_total)
+COVERAGE_LINE_PERCENT=$(cat $FILENAME_COVERAGE_JSON | jq .line_percent)
+
+COVERAGE_LINE_COVERED="${COVERAGE_LINE_COVERED:-0}"
+COVERAGE_LINE_TOTAL="${COVERAGE_LINE_TOTAL:-0}"
+COVERAGE_LINE_PERCENT="${COVERAGE_LINE_PERCENT:-0}"
+
+################################################################################
+# Default values #
+################################################################################
+
+DEFINITELY_LOST="${DEFINITELY_LOST:-0}"
+POSSIBLY_LOST="${POSSIBLY_LOST:-0}"
+
+################################################################################
+# Summarize and emit json for trend reporting #
+################################################################################
+
+FILENAME_SUMMARY="$TEST_FILEPATH_PREFIX-summary.json"
+
+time_length_test=$((time_test_end-time_test_start))
+time_length_zt_node1_online=$((time_zt_node1_online-time_zt_start))
+time_length_zt_node2_online=$((time_zt_node2_online-time_zt_start))
+#time_length_zt_join=$((time_zt_join_end-time_zt_join_start))
+#time_length_zt_leave=$((time_zt_leave_end-time_zt_leave_start))
+#time_length_zt_can_still_ping=$((time_zt_can_still_ping-time_zt_leave_start))
+
+summary=$(cat <<EOF
+{
+ "version":"$ZTO_VER",
+ "commit":"$ZTO_COMMIT",
+ "arch_m":"$(uname -m)",
+ "arch_a":"$(uname -a)",
+ "time_length_test":$time_length_test,
+ "time_length_zt_node1_online":$time_length_zt_node1_online,
+ "time_length_zt_node2_online":$time_length_zt_node2_online,
+ "num_possible_bytes_lost": $POSSIBLY_LOST,
+ "num_definite_bytes_lost": $DEFINITELY_LOST,
+ "num_incorrect_settings": $POSSIBLY_LOST,
+ "num_bad_formattings": $POSSIBLY_LOST,
+ "percent_coverage_branches": $POSSIBLY_LOST,
+ "coverage_lines_covered": $COVERAGE_LINE_COVERED,
+ "coverage_lines_total": $COVERAGE_LINE_TOTAL,
+ "coverage_lines_percent": $COVERAGE_LINE_PERCENT,
+ "ping_loss_percent_1_to_2": $ping_loss_percent_1_to_2,
+ "ping_loss_percent_2_to_1": $ping_loss_percent_2_to_1,
+ "mean_latency_ping_random": $POSSIBLY_LOST,
+ "mean_latency_ping_netns": $POSSIBLY_LOST,
+ "mean_pdv_random": $POSSIBLY_LOST,
+ "mean_pdv_netns": $POSSIBLY_LOST,
+ "mean_perf_netns": $POSSIBLY_LOST
+}
+EOF
+)
+
+echo $summary > $FILENAME_SUMMARY
+cat $FILENAME_SUMMARY
+
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
new file mode 100644
index 00000000..665c3494
--- /dev/null
+++ b/.github/workflows/validate.yml
@@ -0,0 +1,57 @@
+on: [ push ]
+
+jobs:
+ build_ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - name: gitconfig
+ run: |
+ git config --global core.autocrlf input
+
+ - name: checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ target: x86_64-unknown-linux-gnu
+ override: true
+ components: rustfmt, clippy
+
+ - name: Set up cargo cache
+ uses: actions/cache@v3
+ continue-on-error: false
+ with:
+ path: |
+ ~/.cargo/bin/
+ ~/.cargo/registry/index/
+ ~/.cargo/registry/cache/
+ ~/.cargo/git/db/
+ **/target/
+ key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
+ restore-keys: ${{ runner.os }}-cargo-
+
+ - name: validate-1m-linux
+ env:
+ CC: 'gcc'
+ CXX: 'g++'
+ BRANCH: ${{ github.ref_name }}
+ run: |
+ sudo apt install -y valgrind xmlstarlet gcovr iperf3
+ make one ZT_COVERAGE=1 ZT_TRACE=1
+ sudo chmod +x ./.github/workflows/validate-1m-linux.sh
+ sudo ./.github/workflows/validate-1m-linux.sh
+
+ - name: Archive test results
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{github.sha}}-test-results
+ path: "*test-results*"
+
+ - name: final-report
+ run: |
+ sudo chmod +x ./.github/workflows/report.sh
+ sudo ./.github/workflows/report.sh