diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/compilation/001-features | 4 | ||||
-rwxr-xr-x | test/compilation/003-sanitizers | 87 | ||||
-rwxr-xr-x | test/simulation/101-poll | 4 | ||||
-rwxr-xr-x | test/simulation/106-refclock | 15 | ||||
-rwxr-xr-x | test/simulation/108-peer | 21 | ||||
-rwxr-xr-x | test/simulation/110-chronyc | 74 | ||||
-rwxr-xr-x | test/simulation/121-orphan | 1 | ||||
-rwxr-xr-x | test/simulation/126-burst | 16 | ||||
-rwxr-xr-x | test/simulation/127-filter | 19 | ||||
-rwxr-xr-x | test/simulation/128-nocontrol | 25 | ||||
-rwxr-xr-x | test/simulation/129-reload | 25 | ||||
-rwxr-xr-x | test/simulation/130-quit | 23 | ||||
-rwxr-xr-x | test/simulation/131-maxchange | 20 | ||||
-rwxr-xr-x | test/simulation/132-logchange | 21 | ||||
-rwxr-xr-x | test/simulation/133-hwtimestamp | 32 | ||||
-rw-r--r-- | test/simulation/test.common | 44 | ||||
-rw-r--r-- | test/unit/clientlog.c | 4 | ||||
-rw-r--r-- | test/unit/hash.c | 2 | ||||
-rw-r--r-- | test/unit/hwclock.c | 82 | ||||
-rw-r--r-- | test/unit/ntp_core.c | 55 | ||||
-rw-r--r-- | test/unit/ntp_core.keys | 6 | ||||
-rw-r--r-- | test/unit/samplefilt.c | 113 | ||||
-rw-r--r-- | test/unit/sources.c | 31 | ||||
-rw-r--r-- | test/unit/test.c | 10 | ||||
-rw-r--r-- | test/unit/test.h | 3 | ||||
-rw-r--r-- | test/unit/util.c | 70 |
26 files changed, 717 insertions, 90 deletions
diff --git a/test/compilation/001-features b/test/compilation/001-features index d61c07f..125ed31 100755 --- a/test/compilation/001-features +++ b/test/compilation/001-features @@ -4,6 +4,8 @@ cd ../.. +export CFLAGS="-O2 -Werror -Wpointer-arith -Wformat-signedness -Wno-unknown-warning-option -D_FORTIFY_SOURCE=2" + for opts in \ "--enable-debug" \ "--enable-ntp-signd" \ @@ -23,6 +25,6 @@ for opts in \ "--disable-cmdmon --disable-refclock" \ "--disable-cmdmon --disable-ntp --disable-refclock" do - ./configure $opts + ./configure $opts || exit 1 make "$@" || exit 1 done diff --git a/test/compilation/003-sanitizers b/test/compilation/003-sanitizers new file mode 100755 index 0000000..54f0a87 --- /dev/null +++ b/test/compilation/003-sanitizers @@ -0,0 +1,87 @@ +#!/bin/bash +# Run the unit and simulation tests with different compiler sanitizers +# and under valgrind + +cd ../.. + +if [ "$(uname -sm)" != "Linux x86_64" ]; then + echo Test supported on Linux x86_64 only + exit 1 +fi + +[ -f /etc/os-release ] && . /etc/os-release + +if [ "$ID" = "fedora" ]; then + echo Checking test dependencies: + rpm -q {valgrind,gcc,clang}.x86_64 {libgcc,clang-libs}.{x86_64,i686} || exit 1 + rpm -q {libseccomp,nettle,nss-softokn-freebl,libtomcrypt}-devel.{x86_64,i686} || exit 1 + echo +fi + +touch Makefile + +for CC in gcc clang; do + export CC + + for arch_opts in "-m32" ""; do + pushd test/simulation/clknetsim || exit 1 + make clean > /dev/null 2>&1 + CFLAGS="$arch_opts -DCLKNETSIM_DISABLE_SYSCALL" make "$@" || exit 1 + echo + + popd + + for extra_config_opts in \ + "--all-privops" \ + "--disable-scfilter" \ + "--without-nettle" \ + "--without-nettle --without-nss" \ + "--without-nettle --without-nss --without-tomcrypt"; \ + do + for san_options in "" "-fsanitize=address" "-fsanitize=memory"; do + export CFLAGS="-O2 -g -fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize-recover=undefined,float-divide-by-zero $san_options $arch_opts" + + # clang msan doesn't work on i686 and otherwise requires patches + echo $CFLAGS | grep -q 'sanitize=memory' && continue + + # build fails with clang ubsan on i686 (Fedora only?) + [ "$arch_opts" = "-m32" -a "$CC" = "clang" ] && continue + + [ "$CC" = "gcc" ] && echo $CFLAGS | grep -q 'sanitize=address' && CFLAGS="$CFLAGS -static-libasan" + + config_opts="--with-user=chrony --enable-debug --enable-scfilter --enable-ntp-signd $extra_config_opts" + + echo ----------------------------------------------------------------------------- + echo CC=\"$CC\" CFLAGS=\"$CFLAGS\" ./configure $config_opts + + make distclean > /dev/null 2>&1 + + ./configure $config_opts || exit 1 + + if echo "$config_opts" | grep -q all-privops; then + for op in ADJUSTTIME ADJUSTTIMEX SETTIME BINDSOCKET; do + echo "#define PRIVOPS_$op 1" >> config.h + done + fi + + make "$@" || exit 1 + + [ -n "$BUILD_TEST_ONLY" ] && continue + + echo + pushd test/unit || exit 1 + if [ "$san_options" = "" ]; then + make check TEST_WRAPPER="valgrind --error-exitcode=1" || exit 1 + else + make check || exit 1 + fi + popd + + echo + pushd test/simulation || exit 1 + CLKNETSIM_RANDOM_SEED=101 ./run -i 1 || exit 1 + popd + done + done + done +done diff --git a/test/simulation/101-poll b/test/simulation/101-poll index f350777..cb3647f 100755 --- a/test/simulation/101-poll +++ b/test/simulation/101-poll @@ -12,11 +12,13 @@ time_rms_limit=5e-6 freq_rms_limit=5e-6 client_conf="makestep 1e-2 1" -for poll in $(seq 2 14); do +for poll in $(seq 1 14); do client_server_options="minpoll $poll maxpoll $poll" limit=$[2**$poll * 10] min_sync_time=$[2**$poll * 2] max_sync_time=$[2**$poll * 21 / 10 + 1] + client_max_min_out_interval=$(awk "BEGIN {print 2^$poll * 1.1}") + client_min_mean_out_interval=$(awk "BEGIN {print 2^$poll * 0.99}") run_test || test_fail check_chronyd_exit || test_fail diff --git a/test/simulation/106-refclock b/test/simulation/106-refclock index c22cd42..5c5794c 100755 --- a/test/simulation/106-refclock +++ b/test/simulation/106-refclock @@ -9,19 +9,22 @@ refclock_jitter=$jitter min_sync_time=45 max_sync_time=70 chronyc_start=70 -client_conf="refclock SHM 0 stratum 3 delay 1e-3 refid GPS" chronyc_conf="tracking" -run_test || test_fail -check_chronyd_exit || test_fail -check_source_selection || test_fail -check_sync || test_fail -check_chronyc_output "^Reference ID.*47505300 \(GPS\) +for refclock in "SHM 0" "PHC /dev/ptp0"; do + client_conf="refclock $refclock stratum 3 delay 1e-3 refid GPS" + + run_test || test_fail + check_chronyd_exit || test_fail + check_source_selection || test_fail + check_sync || test_fail + check_chronyc_output "^Reference ID.*47505300 \(GPS\) Stratum.*: 4 .* Root delay : 0.001000000 seconds .* Update interval : 16\.. seconds .*$" || test_fail +done test_pass diff --git a/test/simulation/108-peer b/test/simulation/108-peer index 0679f6e..20e2254 100755 --- a/test/simulation/108-peer +++ b/test/simulation/108-peer @@ -30,4 +30,25 @@ check_chronyd_exit || test_fail check_source_selection || test_fail check_sync || test_fail +base_delay="(+ 1e-4 (* -1 (equal 0.1 from 3) (equal 0.1 to 1)))" +client_peer_options="" + +while read lminpoll lmaxpoll rminpoll rmaxpoll max_sync_time; do + client_lpeer_options="minpoll $lminpoll maxpoll $lmaxpoll" + client_rpeer_options="minpoll $rminpoll maxpoll $rmaxpoll" + limit=$[$max_sync_time * 10] + + run_test || test_fail + check_chronyd_exit || test_fail + check_sync || test_fail +done <<-EOF + 3 6 3 6 400 + 3 3 6 6 450 + 6 6 3 3 450 + 3 6 6 6 450 + 6 6 3 6 450 + -2 -2 2 2 220 + 2 2 -2 -2 220 +EOF + test_pass diff --git a/test/simulation/110-chronyc b/test/simulation/110-chronyc index d56e724..944cf3f 100755 --- a/test/simulation/110-chronyc +++ b/test/simulation/110-chronyc @@ -63,4 +63,78 @@ try: 1, refid: C0A87B01, correction: 0\.000......, skew: .\.... 513 RTC driver not running$" \ || test_fail +server_strata=0 +chronyc_start=0 +client_conf="" +limit=1 + +for chronyc_conf in \ + "accheck 1.2.3.4" \ + "add peer 10.0.0.0 minpoll 2 maxpoll 6" \ + "add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 mindelay 1e-4 asymmetry 0.5 offset 1e-5 minsamples 6 maxsamples 6 filter 3 offline auto_offline prefer noselect trust require xleave polltarget 20 port 123 presend 7 minstratum 3 version 4" \ + "allow 1.2.3.4" \ + "allow 1.2" \ + "allow 3.4.5" \ + "allow 6.7.8/22" \ + "allow 6.7.8.9/22" \ + "allow 2001:db8::/32" \ + "allow 0/0" \ + "allow ::/0" \ + "allow" \ + "allow all 10/24" \ + "burst 5/10" \ + "burst 3/5 255.255.255.0/1.2.3.0" \ + "burst 1/2 1.2.3.0/24" \ + "clients" \ + "cmdaccheck 1.2.3.4" \ + "cmdallow 1.2.3.4" \ + "cmdallow all 1.2.3.0/24" \ + "cmddeny 1.2.3.4" \ + "cmddeny all 1.2.3.0/24" \ + "cyclelogs" \ + "delete 10.0.0.0" \ + "deny 1.2.3.4" \ + "deny all 1.2.3.0/24" \ + "dump" \ + "local stratum 5 distance 1.0 orphan" \ + "local off" \ + "makestep 10.0 3" \ + "makestep" \ + "manual delete 0" \ + "manual off" \ + "manual on" \ + "manual reset" \ + "maxdelay 1.2.3.4 1e-2" \ + "maxdelaydevratio 1.2.3.4 5.0" \ + "maxdelayratio 1.2.3.4 3.0" \ + "maxpoll 1.2.3.4 5" \ + "maxupdateskew 1.2.3.4 10.0" \ + "minpoll 1.2.3.4 3" \ + "minstratum 1.2.3.4 1" \ + "ntpdata 1.2.3.4" \ + "offline" \ + "offline 255.255.255.0/1.2.3.0" \ + "offline 1.2.3.0/24" \ + "online" \ + "online 1.2.3.0/24" \ + "onoffline" \ + "polltarget 1.2.3.4 10" \ + "refresh" \ + "rekey" \ + "reselect" \ + "reselectdist 1e-3" \ + "settime 16:30" \ + "settime 16:30:05" \ + "settime Nov 21, 2015 16:30:05" \ + "shutdown" \ + "smoothtime reset" \ + "smoothtime activate" \ + "trimrtc" \ + "writertc" +do + run_test || test_fail + check_chronyd_exit || test_fail + check_chronyc_output "501 Not authorised" || test_fail +done + test_pass diff --git a/test/simulation/121-orphan b/test/simulation/121-orphan index ed92153..1b47f76 100755 --- a/test/simulation/121-orphan +++ b/test/simulation/121-orphan @@ -10,6 +10,7 @@ server 192.168.123.1 server 192.168.123.2 server 192.168.123.3" max_sync_time=500 +client_start=140 chronyc_start=300 chronyc_conf="tracking" time_rms_limit=5e-4 diff --git a/test/simulation/126-burst b/test/simulation/126-burst index 3173c78..d63f290 100755 --- a/test/simulation/126-burst +++ b/test/simulation/126-burst @@ -26,4 +26,20 @@ check_source_selection || test_fail check_packet_interval || test_fail check_sync || test_fail +# Add a significant delay to 70% of packets on the 2->1 path after 6th packet +base_delay=$(cat <<-EOF | tr -d '\n' + (+ 1e-4 + (* 0.15 + (equal 0.1 from 2) + (equal 0.1 to 1) + (equal 0.1 (min (sum 1) 7) 7) + (equal 0.7 (uniform) 0.0))) +EOF +) + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail + test_pass diff --git a/test/simulation/127-filter b/test/simulation/127-filter new file mode 100755 index 0000000..737d1f9 --- /dev/null +++ b/test/simulation/127-filter @@ -0,0 +1,19 @@ +#!/bin/bash + +. ./test.common + +test_start "filter option" + +client_server_options="minpoll 4 maxpoll 4 filter 15" +min_sync_time=710 +max_sync_time=720 +client_max_min_out_interval=16.1 +client_min_mean_out_interval=15.9 + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +test_pass diff --git a/test/simulation/128-nocontrol b/test/simulation/128-nocontrol new file mode 100755 index 0000000..0a98cd7 --- /dev/null +++ b/test/simulation/128-nocontrol @@ -0,0 +1,25 @@ +#!/bin/bash + +. ./test.common + +test_start "-x option" + +wander=0.0 +time_offset=0.0 +freq_offset=0.0 +time_max_limit=1e-6 +freq_max_limit=1e-9 +min_sync_time=0 +max_sync_time=0 +client_chronyd_options="-x" +chronyc_start=300 +chronyc_conf="tracking" + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail +check_chronyc_output "^.*Stratum *: 2.*$" || test_fail + +test_pass diff --git a/test/simulation/129-reload b/test/simulation/129-reload new file mode 100755 index 0000000..9c4e985 --- /dev/null +++ b/test/simulation/129-reload @@ -0,0 +1,25 @@ +#!/bin/bash + +. ./test.common + +test_start "-r option" + +wander=0.0 +limit=100 +min_sync_time=100 +max_sync_time=104 +client_chronyd_options="-r" +client_conf="dumpdir tmp" + +run_test || test_fail + +client_start=$limit +limit=1000 + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +test_pass diff --git a/test/simulation/130-quit b/test/simulation/130-quit new file mode 100755 index 0000000..0183885 --- /dev/null +++ b/test/simulation/130-quit @@ -0,0 +1,23 @@ +#!/bin/bash + +. ./test.common + +test_start "-q/-Q option" + +wander=0.0 +freq_offset=0.0 +min_sync_time=5 +max_sync_time=10 +client_chronyd_options="-q" +client_server_options="iburst" + +run_test || test_fail +check_chronyd_exit || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +client_chronyd_options="-Q" +run_test || test_fail +check_sync && test_fail + +test_pass diff --git a/test/simulation/131-maxchange b/test/simulation/131-maxchange new file mode 100755 index 0000000..969f71f --- /dev/null +++ b/test/simulation/131-maxchange @@ -0,0 +1,20 @@ +#!/bin/bash + +. ./test.common + +test_start "maxchange directive" + +time_offset=2 +max_sync_time=5000 +client_conf="maxchange 0.1 1 3" +client_step="(* $step (equal 0.1 (sum 1.0) 300))" + +run_test || test_fail +check_chronyd_exit && test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync && test_fail +check_log_messages "seconds exceeds.*ignored" 3 3 || test_fail +check_log_messages "seconds exceeds.*exiting" 1 1 || test_fail + +test_pass diff --git a/test/simulation/132-logchange b/test/simulation/132-logchange new file mode 100755 index 0000000..ca6244e --- /dev/null +++ b/test/simulation/132-logchange @@ -0,0 +1,21 @@ +#!/bin/bash + +. ./test.common + +test_start "logchange directive" + +time_offset=2 +min_sync_time=600 +max_sync_time=700 +client_server_options="maxsamples 6" +client_conf="logchange 0.1" +client_step="(* $step (equal 0.1 (sum 1.0) 300))" + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail +check_log_messages "clock wrong by" 4 8 || test_fail + +test_pass diff --git a/test/simulation/133-hwtimestamp b/test/simulation/133-hwtimestamp new file mode 100755 index 0000000..1448c21 --- /dev/null +++ b/test/simulation/133-hwtimestamp @@ -0,0 +1,32 @@ +#!/bin/bash + +. ./test.common + +test_start "hwtimestamp directive" + +export CLKNETSIM_TIMESTAMPING=2 + +refclock_jitter=1e-8 +refclock_offset=10.0 +min_sync_time=4 +max_sync_time=20 +limit=200 +client_conf="hwtimestamp eth0" +client_server_options="minpoll 0 maxpoll 0 minsamples 32" +client_chronyd_options="-d" + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_sync || test_fail + +if grep -q 'FEAT_DEBUG 1' ../../config.h; then + check_log_messages "HW clock samples" 190 200 || test_fail + check_log_messages "HW clock reset" 0 0 || test_fail + check_log_messages "Received.*tss=1" 1 1 || test_fail + check_log_messages "Received.*tss=2" 390 400 || test_fail + check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail + check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail +fi + +test_pass diff --git a/test/simulation/test.common b/test/simulation/test.common index 0cd0fce..c5758c6 100644 --- a/test/simulation/test.common +++ b/test/simulation/test.common @@ -62,7 +62,8 @@ default_client_rpeer_options="" default_server_conf="" default_client_conf="" default_chronyc_conf="" -default_chronyd_options="" +default_server_chronyd_options="" +default_client_chronyd_options="" default_time_max_limit=1e-3 default_freq_max_limit=5e-4 @@ -75,10 +76,9 @@ default_client_min_mean_out_interval=0.0 default_client_max_min_out_interval=inf # Initialize test settings from their defaults -for defopt in $(declare | grep '^default_'); do - defoptname=${defopt%%=*} +for defoptname in ${!default_*}; do optname=${defoptname#default_} - eval "[ -z \"\${$optname:+a}\" ] && $optname=\"\$$defoptname\"" + [ -z "${!optname}" ] && declare "$optname"="${!defoptname}" done test_start() { @@ -253,7 +253,7 @@ check_chronyd_exit() { for i in $(seq 1 $(get_chronyd_nodes)); do test_message 3 0 "node $i:" - tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \ + grep -q 'chronyd exiting' tmp/log.$i && \ ! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \ test_ok || test_bad [ $? -eq 0 ] || ret=1 @@ -337,6 +337,24 @@ check_chronyc_output() { return $ret } +# Check the number of messages matching a matter in the client logs +check_log_messages() { + local i count ret=0 pattern=$1 min=$2 max=$3 + + test_message 2 1 "checking number of messages \"$pattern\":" + + for i in $(seq $[$servers * $server_strata + 1] $(get_chronyd_nodes)); do + count=$(grep "$pattern" tmp/log.$i | wc -l) + test_message 3 0 "node $i: $count" + + [ "$min" -le "$count" ] && [ "$count" -le "$max" ] && \ + test_ok || test_bad + [ $? -eq 0 ] || ret=1 + done + + return $ret +} + # Check if only NTP port (123) was used check_packet_port() { local i ret=0 port=123 @@ -358,14 +376,13 @@ check_packet_port() { # Print test settings which differ from default value print_nondefaults() { - local defopt defoptname optname + local defoptname optname test_message 2 1 "non-default settings:" - declare | grep '^default_*' | while read defopt; do - defoptname=${defopt%%=*} + for defoptname in ${!default_*}; do optname=${defoptname#default_} - eval "[ \"\$$optname\" = \"\$$defoptname\" ]" || \ - test_message 3 1 $(eval "echo $optname=\$$optname") + [ "${!defoptname}" = "${!optname}" ] || \ + test_message 3 1 $optname=${!optname} done } @@ -382,7 +399,7 @@ run_simulation() { } run_test() { - local i j n stratum node nodes step start freq offset conf + local i j n stratum node nodes step start freq offset conf options test_message 1 1 "network with $servers*$server_strata servers and $clients clients:" print_nondefaults @@ -411,16 +428,19 @@ run_test() { start=$server_start freq="" [ $i -le $falsetickers ] && offset=$i.0 || offset=0.0 + options=$server_chronyd_options elif [ $stratum -le $server_strata ]; then step=$server_step start=$server_start freq=$(get_wander_expr) offset=0.0 + options=$server_chronyd_options else step=$client_step start=$client_start freq=$(get_wander_expr) offset=$time_offset + options=$client_chronyd_options fi conf=$(get_chronyd_conf $stratum $i $n) @@ -431,7 +451,7 @@ run_test() { echo "node${node}_refclock = $(get_refclock_expr)" >> tmp/conf echo "node${node}_offset = $offset" >> tmp/conf echo "node${node}_start = $start" >> tmp/conf - start_client $node chronyd "$conf" "" "$chronyd_options" && \ + start_client $node chronyd "$conf" "" "$options" && \ test_ok || test_error [ $? -ne 0 ] && return 1 diff --git a/test/unit/clientlog.c b/test/unit/clientlog.c index 515ad1a..a412b69 100644 --- a/test/unit/clientlog.c +++ b/test/unit/clientlog.c @@ -65,7 +65,7 @@ test_unit(void) } } - DEBUG_LOG("records %d", ARR_GetSize(records)); + DEBUG_LOG("records %u", ARR_GetSize(records)); TEST_CHECK(ARR_GetSize(records) == 64); for (i = j = 0; i < 10000; i++) { @@ -76,7 +76,7 @@ test_unit(void) j++; } - DEBUG_LOG("requests %u responses %u", i, j); + DEBUG_LOG("requests %d responses %d", i, j); TEST_CHECK(j * 4 < i && j * 6 > i); CLG_Finalise(); diff --git a/test/unit/hash.c b/test/unit/hash.c index 8aab74f..5cde039 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -106,7 +106,7 @@ test_unit(void) if (j >= tests[i].length) TEST_CHECK(length == tests[i].length); else - TEST_CHECK(length == 0 || length == j); + TEST_CHECK(length == j); TEST_CHECK(!memcmp(out, tests[i].out, length)); } diff --git a/test/unit/hwclock.c b/test/unit/hwclock.c index 804e600..216dbfb 100644 --- a/test/unit/hwclock.c +++ b/test/unit/hwclock.c @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) Miroslav Lichvar 2016 + * Copyright (C) Miroslav Lichvar 2016-2017 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -27,56 +27,58 @@ test_unit(void) struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts; HCL_Instance clock; double freq, jitter, interval, dj, sum; - int i, j, count; + int i, j, k, count; LCL_Initialise(); - clock = HCL_CreateInstance(1.0); - - for (i = 0, count = 0, sum = 0.0; i < 2000; i++) { - UTI_ZeroTimespec(&start_hw_ts); - UTI_ZeroTimespec(&start_local_ts); - UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts); - UTI_AddDoubleToTimespec(&start_local_ts, TST_GetRandomDouble(0.0, 1e9), &start_local_ts); - - DEBUG_LOG("iteration %d", i); - - freq = TST_GetRandomDouble(0.9, 1.1); - jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9); - interval = TST_GetRandomDouble(0.1, 10.0); - - clock->n_samples = 0; - clock->valid_coefs = 0; - - for (j = 0; j < 100; j++) { - UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq, &hw_ts); - UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts); - if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) { - dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter); - DEBUG_LOG("delta/jitter %f", dj); - if (clock->n_samples >= 8) - sum += dj, count++; - TEST_CHECK(clock->n_samples < 4 || dj <= 4.0); - TEST_CHECK(clock->n_samples < 8 || dj <= 3.0); - } + for (i = 1; i <= 8; i++) { + clock = HCL_CreateInstance(random() % (1 << i), 1 << i, 1.0); + + for (j = 0, count = 0, sum = 0.0; j < 100; j++) { + UTI_ZeroTimespec(&start_hw_ts); + UTI_ZeroTimespec(&start_local_ts); + UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts); + UTI_AddDoubleToTimespec(&start_local_ts, TST_GetRandomDouble(0.0, 1e9), &start_local_ts); + + DEBUG_LOG("iteration %d", j); + + freq = TST_GetRandomDouble(0.9, 1.1); + jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9); + interval = TST_GetRandomDouble(0.1, 10.0); + + clock->n_samples = 0; + clock->valid_coefs = 0; - UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts); + for (k = 0; k < 100; k++) { + UTI_AddDoubleToTimespec(&start_hw_ts, k * interval * freq, &hw_ts); + UTI_AddDoubleToTimespec(&start_local_ts, k * interval, &local_ts); + if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) { + dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter); + DEBUG_LOG("delta/jitter %f", dj); + if (clock->n_samples >= clock->max_samples / 2) + sum += dj, count++; + TEST_CHECK(clock->n_samples < 4 || dj <= 4.0); + TEST_CHECK(clock->n_samples < 8 || dj <= 3.0); + } - if (HCL_NeedsNewSample(clock, &local_ts)) - HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter); + UTI_AddDoubleToTimespec(&start_hw_ts, k * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts); - TEST_CHECK(clock->valid_coefs || clock->n_samples < 2); + if (HCL_NeedsNewSample(clock, &local_ts)) + HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter); - if (!clock->valid_coefs) - continue; + TEST_CHECK(clock->valid_coefs || clock->n_samples < 2); - TEST_CHECK(fabs(clock->offset) <= 2.0 * jitter); + if (!clock->valid_coefs) + continue; + + TEST_CHECK(fabs(clock->offset) <= 2.0 * jitter); + } } - } - TEST_CHECK(sum / count < 0.4); + TEST_CHECK(sum / count < 2.4 / sqrt(clock->max_samples)); - HCL_DestroyInstance(clock); + HCL_DestroyInstance(clock); + } LCL_Finalise(); } diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c index 9587306..5e519e5 100644 --- a/test/unit/ntp_core.c +++ b/test/unit/ntp_core.c @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) Miroslav Lichvar 2017 + * Copyright (C) Miroslav Lichvar 2017-2018 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -63,6 +63,18 @@ advance_time(double x) UTI_AddDoubleToTimespec(¤t_time, x, ¤t_time); } +static uint32_t +get_random_key_id(void) +{ + uint32_t id; + + do { + id = random() % 6 + 2; + } while (!KEY_KeyKnown(id)); + + return id; +} + static void send_request(NCR_Instance inst) { @@ -122,6 +134,7 @@ static void send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth) { NTP_Packet *req, *res; + int auth_len = 0; req = &req_buffer.ntp_pkt; res = &res_buffer.ntp_pkt; @@ -168,24 +181,41 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts } if (authenticated) { - res->auth_keyid = req->auth_keyid; - KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH, - res->auth_data, 16); - res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16; + res->auth_keyid = req->auth_keyid ? req->auth_keyid : htonl(get_random_key_id()); + auth_len = KEY_GetAuthLength(ntohl(res->auth_keyid)); + assert(auth_len); + if (NTP_LVM_TO_VERSION(res->lvm) == 4 && random() % 2) + auth_len = MIN(auth_len, NTP_MAX_V4_MAC_LENGTH - 4); + + if (KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, + NTP_NORMAL_PACKET_LENGTH, res->auth_data, auth_len) != auth_len) + assert(0); + res_length = NTP_NORMAL_PACKET_LENGTH + 4 + auth_len; } else { res_length = NTP_NORMAL_PACKET_LENGTH; } - if (!valid_auth) { - switch (random() % 3) { + if (!valid_auth && authenticated) { + assert(auth_len); + + switch (random() % 4) { case 0: - res->auth_keyid++; + res->auth_keyid = htonl(ntohl(res->auth_keyid) + 1); break; case 1: - res->auth_data[random() % 16]++; + res->auth_keyid = htonl(ntohl(res->auth_keyid) ^ 1); + if (KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, + NTP_NORMAL_PACKET_LENGTH, res->auth_data, auth_len) != auth_len) + assert(0); break; case 2: - res_length = NTP_NORMAL_PACKET_LENGTH; + res->auth_data[random() % auth_len]++; + break; + case 3: + res_length = NTP_NORMAL_PACKET_LENGTH + 4 * (random() % ((4 + auth_len) / 4)); + if (NTP_LVM_TO_VERSION(res->lvm) == 4 && + res_length == NTP_NORMAL_PACKET_LENGTH + NTP_MAX_V4_MAC_LENGTH) + res_length -= 4; break; default: assert(0); @@ -292,7 +322,10 @@ test_unit(void) NIO_Initialise(IPADDR_UNSPEC); NCR_Initialise(); REF_Initialise(); + + TST_SuspendLogging(); KEY_Initialise(); + TST_ResumeLogging(); CNF_SetupAccessRestrictions(); @@ -302,7 +335,7 @@ test_unit(void) if (random() % 2) source.params.interleaved = 1; if (random() % 2) - source.params.authkey = 1; + source.params.authkey = get_random_key_id(); source.params.version = random() % 4 + 1; UTI_ZeroTimespec(¤t_time); diff --git a/test/unit/ntp_core.keys b/test/unit/ntp_core.keys index 7a70e52..f06237f 100644 --- a/test/unit/ntp_core.keys +++ b/test/unit/ntp_core.keys @@ -1,2 +1,6 @@ -1 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579 2 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579 +3 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579 +4 SHA1 HEX:B71744EA01FBF01CA30D173ECDDF901952AE356A +5 SHA1 HEX:B71744EA01FBF01CA30D173ECDDF901952AE356A +6 SHA512 HEX:DE027482F22B201FC20863F58C74095E7906089F +7 SHA512 HEX:DE027482F22B201FC20863F58C74095E7906089F diff --git a/test/unit/samplefilt.c b/test/unit/samplefilt.c new file mode 100644 index 0000000..294a9bf --- /dev/null +++ b/test/unit/samplefilt.c @@ -0,0 +1,113 @@ +/* + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2018 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + */ + +#include <samplefilt.c> +#include "test.h" + +void +test_unit(void) +{ + NTP_Sample sample_in, sample_out; + SPF_Instance filter; + int i, j, k, sum_count, min_samples, max_samples; + double mean, combine_ratio, sum_err; + + LCL_Initialise(); + + for (i = 0; i <= 100; i++) { + max_samples = random() % 20 + 1; + min_samples = random() % (max_samples) + 1; + combine_ratio = TST_GetRandomDouble(0.0, 1.0); + + filter = SPF_CreateInstance(min_samples, max_samples, 2.0, combine_ratio); + + for (j = 0, sum_count = 0, sum_err = 0.0; j < 100; j++) { + DEBUG_LOG("iteration %d/%d", i, j); + + mean = TST_GetRandomDouble(-1.0e3, 1.0e3); + UTI_ZeroTimespec(&sample_in.time); + + for (k = 0; k < 100; k++) { + UTI_AddDoubleToTimespec(&sample_in.time, TST_GetRandomDouble(1.0e-1, 1.0e2), + &sample_in.time); + sample_in.offset = mean + TST_GetRandomDouble(-1.0, 1.0); + sample_in.peer_dispersion = TST_GetRandomDouble(1.0e-4, 2.0e-4); + sample_in.root_dispersion = TST_GetRandomDouble(1.0e-3, 2.0e-3); + sample_in.peer_delay = TST_GetRandomDouble(1.0e-2, 2.0e-2); + sample_in.root_delay = TST_GetRandomDouble(1.0e-1, 2.0e-1); + sample_in.stratum = random() % 16; + sample_in.leap = random() % 4; + + TEST_CHECK(SPF_AccumulateSample(filter, &sample_in)); + TEST_CHECK(!SPF_AccumulateSample(filter, &sample_in)); + + TEST_CHECK(SPF_GetNumberOfSamples(filter) == MIN(k + 1, max_samples)); + + SPF_GetLastSample(filter, &sample_out); + TEST_CHECK(!memcmp(&sample_in, &sample_out, sizeof (sample_in))); + + SPF_SlewSamples(filter, &sample_in.time, 0.0, 0.0); + SPF_AddDispersion(filter, 0.0); + + if (k + 1 < min_samples) + TEST_CHECK(!SPF_GetFilteredSample(filter, &sample_out)); + + TEST_CHECK(SPF_GetNumberOfSamples(filter) == MIN(k + 1, max_samples)); + } + + if (random() % 10) { + TEST_CHECK(SPF_GetFilteredSample(filter, &sample_out)); + + TEST_CHECK(SPF_GetAvgSampleDispersion(filter) <= 2.0); + + sum_err += sample_out.offset - mean; + sum_count++; + + TEST_CHECK(UTI_CompareTimespecs(&sample_out.time, &sample_in.time) <= 0 && + sample_out.time.tv_sec >= 0); + TEST_CHECK(fabs(sample_out.offset - mean) <= 1.0); + TEST_CHECK(sample_out.peer_dispersion >= 1.0e-4 && + (sample_out.peer_dispersion <= 2.0e-4 || filter->max_samples > 1)); + TEST_CHECK(sample_out.root_dispersion >= 1.0e-3 && + (sample_out.root_dispersion <= 2.0e-3 || filter->max_samples > 1)); + TEST_CHECK(sample_out.peer_delay >= 1.0e-2 && + sample_out.peer_delay <= 2.0e-2); + TEST_CHECK(sample_out.root_delay >= 1.0e-1 && + sample_out.root_delay <= 2.0e-1); + TEST_CHECK(sample_out.leap >= 0 && sample_out.leap <= 3); + TEST_CHECK(sample_out.stratum >= 0 && sample_out.stratum <= 15); + + if (max_samples == 1) + TEST_CHECK(!memcmp(&sample_in, &sample_out, sizeof (sample_in))); + + } else { + SPF_DropSamples(filter); + } + + TEST_CHECK(SPF_GetNumberOfSamples(filter) == 0); + } + + TEST_CHECK(fabs(sum_err / sum_count) < 0.3); + + SPF_DestroyInstance(filter); + } + + LCL_Finalise(); +} diff --git a/test/unit/sources.c b/test/unit/sources.c index 341e22e..b81f808 100644 --- a/test/unit/sources.c +++ b/test/unit/sources.c @@ -26,10 +26,9 @@ test_unit(void) { SRC_Instance srcs[16]; RPT_SourceReport report; + NTP_Sample sample; IPAddr addr; int i, j, k, l, samples, sel_options; - double offset, delay, disp; - struct timespec ts; CNF_Initialise(0, 0); LCL_Initialise(); @@ -59,21 +58,25 @@ test_unit(void) samples = (i + j) % 5 + 3; - offset = TST_GetRandomDouble(-1.0, 1.0); + sample.offset = TST_GetRandomDouble(-1.0, 1.0); for (k = 0; k < samples; k++) { - SCH_GetLastEventTime(&ts, NULL, NULL); - UTI_AddDoubleToTimespec(&ts, TST_GetRandomDouble(k - samples, k - samples + 1), &ts); - - offset += TST_GetRandomDouble(-1.0e-2, 1.0e-2); - delay = TST_GetRandomDouble(1.0e-6, 1.0e-1); - disp = TST_GetRandomDouble(1.0e-6, 1.0e-1); + SCH_GetLastEventTime(&sample.time, NULL, NULL); + UTI_AddDoubleToTimespec(&sample.time, TST_GetRandomDouble(k - samples, k - samples + 1), + &sample.time); + + sample.offset += TST_GetRandomDouble(-1.0e-2, 1.0e-2); + sample.peer_delay = TST_GetRandomDouble(1.0e-6, 1.0e-1); + sample.peer_dispersion = TST_GetRandomDouble(1.0e-6, 1.0e-1); + sample.root_delay = sample.peer_delay; + sample.root_dispersion = sample.peer_dispersion; + sample.stratum = 1; + sample.leap = LEAP_Normal; DEBUG_LOG("source %d sample %d offset %f delay %f disp %f", j, k, - offset, delay, disp); + sample.offset, sample.peer_delay, sample.peer_dispersion); - SRC_AccumulateSample(srcs[j], &ts, offset, delay, disp, delay, disp, - 1, LEAP_Normal); + SRC_AccumulateSample(srcs[j], &sample); } for (k = 0; k <= j; k++) { @@ -82,7 +85,7 @@ test_unit(void) double passed_lo = DBL_MAX, passed_hi = DBL_MIN; SRC_SelectSource(srcs[k]); - DEBUG_LOG("source %d status %d", k, sources[k]->status); + DEBUG_LOG("source %d status %u", k, sources[k]->status); for (l = 0; l <= j; l++) { TEST_CHECK(sources[l]->status > SRC_OK && sources[l]->status <= SRC_SELECTED); @@ -125,7 +128,7 @@ test_unit(void) } for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) { - SRC_ReportSource(j, &report, &ts); + SRC_ReportSource(j, &report, &sample.time); SRC_DestroyInstance(srcs[j]); } } diff --git a/test/unit/test.c b/test/unit/test.c index 67f7678..3a9ec74 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -75,6 +75,16 @@ main(int argc, char **argv) return 0; } +void TST_SuspendLogging(void) +{ + LOG_OpenFileLog("/dev/null"); +} + +void TST_ResumeLogging(void) +{ + LOG_OpenFileLog(NULL); +} + double TST_GetRandomDouble(double min, double max) { diff --git a/test/unit/test.h b/test/unit/test.h index d96f3af..f409252 100644 --- a/test/unit/test.h +++ b/test/unit/test.h @@ -35,6 +35,9 @@ extern void test_unit(void); extern void TST_Fail(int line); +extern void TST_SuspendLogging(void); +extern void TST_ResumeLogging(void); + extern double TST_GetRandomDouble(double min, double max); extern void TST_GetRandomAddress(IPAddr *ip, int family, int bits); extern void TST_SwapAddressBit(IPAddr *ip, unsigned int b); diff --git a/test/unit/util.c b/test/unit/util.c index 5f1a653..6ce6f90 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -3,13 +3,17 @@ void test_unit(void) { NTP_int64 ntp_ts, ntp_fuzz; + NTP_int32 ntp32_ts; struct timespec ts, ts2; struct timeval tv; struct sockaddr_un sun; - double x, y; + double x, y, nan, inf; + Timespec tspec; Float f; int i, j, c; char buf[16], *s; + uid_t uid; + gid_t gid; for (i = -31; i < 31; i++) { x = pow(2.0, i); @@ -33,6 +37,11 @@ void test_unit(void) { TEST_CHECK(x > 0.0 || x <= 0.0); } + for (i = 0; i < 100000; i++) { + UTI_GetRandomBytes(&ntp32_ts, sizeof (ntp32_ts)); + TEST_CHECK(UTI_DoubleToNtp32(UTI_Ntp32ToDouble(ntp32_ts)) == ntp32_ts); + } + TEST_CHECK(UTI_DoubleToNtp32(1.0) == htonl(65536)); TEST_CHECK(UTI_DoubleToNtp32(0.0) == htonl(0)); TEST_CHECK(UTI_DoubleToNtp32(1.0 / (65536.0)) == htonl(1)); @@ -175,6 +184,23 @@ void test_unit(void) { TEST_CHECK(c > 400 && c < 600); } + ts.tv_nsec = 0; + + ts.tv_sec = 10; + TEST_CHECK(!UTI_IsTimeOffsetSane(&ts, -20.0)); + +#ifdef HAVE_LONG_TIME_T + ts.tv_sec = NTP_ERA_SPLIT + (1LL << 32); +#else + ts.tv_sec = 0x7fffffff - MIN_ENDOFTIME_DISTANCE; +#endif + TEST_CHECK(!UTI_IsTimeOffsetSane(&ts, 10.0)); + TEST_CHECK(UTI_IsTimeOffsetSane(&ts, -20.0)); + + UTI_TimespecHostToNetwork(&ts, &tspec); + UTI_TimespecNetworkToHost(&tspec, &ts2); + TEST_CHECK(!UTI_CompareTimespecs(&ts, &ts2)); + for (i = c = 0; i < 100000; i++) { j = random() % (sizeof (buf) + 1); UTI_GetRandomBytes(buf, j); @@ -196,4 +222,46 @@ void test_unit(void) { TEST_CHECK(s[BUFFER_LENGTH - 2] == '>'); } } + + s = UTI_PathToDir("/aaa/bbb/ccc/ddd"); + TEST_CHECK(!strcmp(s, "/aaa/bbb/ccc")); + Free(s); + s = UTI_PathToDir("aaa"); + TEST_CHECK(!strcmp(s, ".")); + Free(s); + s = UTI_PathToDir("/aaaa"); + TEST_CHECK(!strcmp(s, "/")); + Free(s); + + nan = strtod("nan", NULL); + inf = strtod("inf", NULL); + + TEST_CHECK(MIN(2.0, -1.0) == -1.0); + TEST_CHECK(MIN(-1.0, 2.0) == -1.0); + TEST_CHECK(MIN(inf, 2.0) == 2.0); + + TEST_CHECK(MAX(2.0, -1.0) == 2.0); + TEST_CHECK(MAX(-1.0, 2.0) == 2.0); + TEST_CHECK(MAX(inf, 2.0) == inf); + + TEST_CHECK(CLAMP(1.0, -1.0, 2.0) == 1.0); + TEST_CHECK(CLAMP(1.0, 3.0, 2.0) == 2.0); + TEST_CHECK(CLAMP(1.0, inf, 2.0) == 2.0); + TEST_CHECK(CLAMP(1.0, nan, 2.0) == 2.0); + + TEST_CHECK(SQUARE(3.0) == 3.0 * 3.0); + + rmdir("testdir"); + + uid = geteuid(); + gid = getegid(); + + TEST_CHECK(UTI_CreateDirAndParents("testdir", 0700, uid, gid)); + + TST_SuspendLogging(); + TEST_CHECK(UTI_CheckDirPermissions("testdir", 0700, uid, gid)); + TEST_CHECK(!UTI_CheckDirPermissions("testdir", 0300, uid, gid)); + TEST_CHECK(!UTI_CheckDirPermissions("testdir", 0700, uid + 1, gid)); + TEST_CHECK(!UTI_CheckDirPermissions("testdir", 0700, uid, gid + 1)); + TST_ResumeLogging(); } |