diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 17:35:01 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 17:35:01 +0000 |
commit | 763b5e2c4bed507e0fa34ca2b7cb4f15a136cb82 (patch) | |
tree | 829cb7231c945c8e1e7d8ad62e94c4cb0f902ec6 /test/system | |
parent | Initial commit. (diff) | |
download | chrony-763b5e2c4bed507e0fa34ca2b7cb4f15a136cb82.tar.xz chrony-763b5e2c4bed507e0fa34ca2b7cb4f15a136cb82.zip |
Adding upstream version 4.0.upstream/4.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rwxr-xr-x | test/system/001-minimal | 13 | ||||
-rwxr-xr-x | test/system/002-extended | 13 | ||||
-rwxr-xr-x | test/system/003-memlock | 15 | ||||
-rwxr-xr-x | test/system/004-priority | 15 | ||||
-rwxr-xr-x | test/system/005-scfilter | 17 | ||||
-rwxr-xr-x | test/system/006-privdrop | 17 | ||||
-rwxr-xr-x | test/system/007-cmdmon | 157 | ||||
-rwxr-xr-x | test/system/008-confload | 75 | ||||
-rwxr-xr-x | test/system/009-binddevice | 24 | ||||
-rwxr-xr-x | test/system/100-clockupdate | 30 | ||||
-rwxr-xr-x | test/system/101-rtc | 19 | ||||
-rwxr-xr-x | test/system/102-hwtimestamp | 28 | ||||
-rwxr-xr-x | test/system/103-refclock | 19 | ||||
-rwxr-xr-x | test/system/104-systemdirs | 19 | ||||
-rwxr-xr-x | test/system/105-nts | 72 | ||||
-rwxr-xr-x | test/system/run | 64 | ||||
-rw-r--r-- | test/system/test.common | 338 |
17 files changed, 935 insertions, 0 deletions
diff --git a/test/system/001-minimal b/test/system/001-minimal new file mode 100755 index 0000000..107fa3f --- /dev/null +++ b/test/system/001-minimal @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "minimal configuration" + +minimal_config=1 + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail + +test_pass diff --git a/test/system/002-extended b/test/system/002-extended new file mode 100755 index 0000000..7a6734f --- /dev/null +++ b/test/system/002-extended @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "extended configuration" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/003-memlock b/test/system/003-memlock new file mode 100755 index 0000000..e4ab1bf --- /dev/null +++ b/test/system/003-memlock @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "memory locking" + +extra_chronyd_options="-m" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/004-priority b/test/system/004-priority new file mode 100755 index 0000000..bf8a04b --- /dev/null +++ b/test/system/004-priority @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "process priority" + +extra_chronyd_options="-P 1" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/005-scfilter b/test/system/005-scfilter new file mode 100755 index 0000000..778a688 --- /dev/null +++ b/test/system/005-scfilter @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features SCFILTER || test_skip "SCFILTER support disabled" + +test_start "system call filter" + +for extra_chronyd_options in "-F -1" "-F 1"; do + start_chronyd || test_fail + wait_for_sync || test_fail + stop_chronyd || test_fail + check_chronyd_messages || test_fail + check_chronyd_files || test_fail +done + +test_pass diff --git a/test/system/006-privdrop b/test/system/006-privdrop new file mode 100755 index 0000000..6d7b0c9 --- /dev/null +++ b/test/system/006-privdrop @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features PRIVDROP || test_skip "PRIVDROP support disabled" + +user="nobody" + +test_start "dropping of root privileges" + +minimal_config=1 + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail + +test_pass diff --git a/test/system/007-cmdmon b/test/system/007-cmdmon new file mode 100755 index 0000000..37a1d34 --- /dev/null +++ b/test/system/007-cmdmon @@ -0,0 +1,157 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "chronyc commands" + +start_chronyd || test_fail +wait_for_sync || test_fail + +for command in \ + "allow 1.2.3.4" \ + "deny 1.2.3.4" \ + "cmddeny" \ + "cmdallow" \ + "cmddeny 1.2.3.4" \ + "cmdallow 1.2.3.4" \ + "add server 127.123.1.1" \ + "delete 127.123.1.1" \ + "burst 1/1" \ + "cyclelogs" \ + "dfreq 1.0e-3" \ + "doffset -0.1" \ + "dump" \ + "local off" \ + "local" \ + "maxdelay $server 1e-1" \ + "maxdelaydevratio $server 5.0" \ + "maxdelayratio $server 3.0" \ + "maxpoll $server 5" \ + "maxupdateskew $server 10.0" \ + "minpoll $server 3" \ + "minstratum $server 1" \ + "offline" \ + "online" \ + "onoffline" \ + "polltarget $server 10" \ + "refresh" \ + "rekey" \ + "reload sources" \ + "reselect" \ + "reselectdist 1e-3" \ + "reset sources" \ + "smoothtime reset" \ + "smoothtime activate" \ +; do + run_chronyc "$command" || test_fail + check_chronyc_output "^200 OK$" || test_fail +done + +run_chronyc "accheck $server" || test_fail +check_chronyc_output "^208 Access allowed$" || test_fail +run_chronyc "accheck 1.2.3.4" || test_fail +check_chronyc_output "^209 Access denied$" || test_fail + +run_chronyc "cmdaccheck 1.2.3.4" || test_fail +check_chronyc_output "^208 Access allowed$" || test_fail + +run_chronyc "authdata" || test_fail +check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen +========================================================================= +127\.0\.0\.1 - 0 0 0 - 0 0 0 0$" \ + || test_chronyc + +run_chronyc "clients" || test_fail +check_chronyc_output "^Hostname NTP Drop Int IntL Last Cmd Drop Int Last +=============================================================================== +127\.0\.0\.1 [0-9 ]+ 0 [-0-9 ]+ - [0-9] 0 0 - -$" \ + || test_fail + +run_chronyc "ntpdata $server" || test_fail +check_chronyc_output "^Remote address : 127\.0\.0\.1 \(7F000001\) +Remote port : [0-9]+ +Local address : 127\.0\.0\.1 \(7F000001\) +Leap status : Normal +Version : 4 +Mode : Server +Stratum : 10 +Poll interval : (-6|[0345]) \([0-9]+ seconds\) +Precision : [0-9 +-]+ \(0\.[0-9]+ seconds\) +Root delay : 0\.000000 seconds +Root dispersion : 0\.000000 seconds +Reference ID : 7F7F0101 \(\) +Reference time : [A-Za-z0-9: ]+ +Offset : [+-]0\.......... seconds +Peer delay : 0\.......... seconds +Peer dispersion : 0\.......... seconds +Response time : 0\.......... seconds +Jitter asymmetry: \+0\.00 +NTP tests : 111 111 1110 +Interleaved : No +Authenticated : No +TX timestamping : (Daemon|Kernel) +RX timestamping : (Daemon|Kernel) +Total TX : [0-9]+ +Total RX : [0-9]+ +Total valid RX : [0-9]+$" || test_fail + +run_chronyc "selectdata" || test_fail +check_chronyc_output "^S Name/IP Address Auth COpts EOpts Last Score Interval Leap +======================================================================= +M 127\.0\.0\.1 N ----- ----- 0 1\.0 \+0ns \+0ns \?$" || test_fail + +run_chronyc "serverstats" || test_fail +check_chronyc_output "^NTP packets received : [0-9]+ +NTP packets dropped : 0 +Command packets received : [0-9]+ +Command packets dropped : 0 +Client log records dropped : 0 +NTS-KE connections accepted: 0 +NTS-KE connections dropped : 0 +Authenticated NTP packets : 0$" || test_fail + +run_chronyc "manual on" || test_fail +check_chronyc_output "^200 OK$" || test_fail + +run_chronyc "settime now" || test_fail +check_chronyc_output "^200 OK +Clock was.*$" || test_fail + +run_chronyc "manual delete 0" || test_fail +check_chronyc_output "^200 OK$" || test_fail + +run_chronyc "settime now" || test_fail +check_chronyc_output "^200 OK +Clock was.*$" || test_fail + +run_chronyc "manual list" || test_fail +check_chronyc_output "^210 n_samples = 1 +# Date Time\(UTC\) Slewed Original Residual +======================================================= + 0.*$" || test_fail + +run_chronyc "manual reset" || test_fail +check_chronyc_output "^200 OK$" || test_fail + +run_chronyc "manual off" || test_fail +check_chronyc_output "^200 OK$" || test_fail + +run_chronyc "shutdown" || test_fail +check_chronyc_output "^200 OK$" || test_fail + +stop_chronyd || test_fail +check_chronyd_messages || test_fail +start_chronyd || test_fail + +run_chronyc "makestep" && test_fail +check_chronyc_output "500 Failure" || test_fail + +run_chronyc "trimrtc" && test_fail +check_chronyc_output "513 RTC driver not running" || test_fail + +run_chronyc "writertc" && test_fail +check_chronyc_output "513 RTC driver not running" || test_fail + +stop_chronyd || test_fail + +test_pass diff --git a/test/system/008-confload b/test/system/008-confload new file mode 100755 index 0000000..689e38b --- /dev/null +++ b/test/system/008-confload @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "loading of configuration" + +minimal_config=1 +extra_chronyd_directives=" +include $TEST_DIR/conf1.d/conf.1 +confdir $TEST_DIR/conf1.d +confdir $TEST_DIR/conf2.d $TEST_DIR/conf3.d $TEST_DIR/conf4.d +sourcedir $TEST_DIR/conf5.d +include $TEST_DIR/conf1.d/conf.2" + +mkdir $TEST_DIR/conf{1,2,3,4,5}.d + +echo "server 127.123.1.1" > $TEST_DIR/conf1.d/conf.1 +echo "server 127.123.1.2" > $TEST_DIR/conf1.d/conf.2 +echo "server 127.123.1.3" > $TEST_DIR/conf1.d/3.conf +echo "server 127.123.1.4" > $TEST_DIR/conf1.d/4.conf +echo "server 127.123.2.2" > $TEST_DIR/conf2.d/2.conf +echo "server 127.123.2.3" > $TEST_DIR/conf2.d/3.conf +echo "server 127.123.3.1" > $TEST_DIR/conf3.d/1.conf +echo "server 127.123.3.2" > $TEST_DIR/conf3.d/2.conf +echo "server 127.123.3.3" > $TEST_DIR/conf3.d/3.conf +echo "server 127.123.4.1" > $TEST_DIR/conf4.d/1.conf +echo "server 127.123.4.2" > $TEST_DIR/conf4.d/2.conf +echo "server 127.123.4.3" > $TEST_DIR/conf4.d/3.conf +echo "server 127.123.4.4" > $TEST_DIR/conf4.d/4.conf +echo "server 127.123.5.1" > $TEST_DIR/conf5.d/1.sources +echo "server 127.123.5.2" > $TEST_DIR/conf5.d/2.sources +echo "server 127.123.5.3" > $TEST_DIR/conf5.d/3.sources + +start_chronyd || test_fail +wait_for_sync || test_fail + +run_chronyc "sources" || test_fail +check_chronyc_output "^[^=]* +=* +.. 127\.123\.1\.1 [^^]* +.. 127\.123\.1\.3 [^^]* +.. 127\.123\.1\.4 [^^]* +.. 127\.123\.3\.1 [^^]* +.. 127\.123\.2\.2 [^^]* +.. 127\.123\.2\.3 [^^]* +.. 127\.123\.4\.4 [^^]* +.. 127\.123\.1\.2 [^^]* +.. 127\.123\.5\.1 [^^]* +.. 127\.123\.5\.2 [^^]* +.. 127\.123\.5\.3 [^^]*$" || test_fail + +rm $TEST_DIR/conf5.d/1.sources +echo "server 127.123.5.2 minpoll 7" > $TEST_DIR/conf5.d/2.sources +echo > $TEST_DIR/conf5.d/3.sources +echo "server 127.123.5.4" > $TEST_DIR/conf5.d/4.sources + +run_chronyc "reload sources" || test_fail + +run_chronyc "sources" || test_fail +check_chronyc_output "^[^=]* +=* +.. 127\.123\.1\.1 [^^]* +.. 127\.123\.1\.3 [^^]* +.. 127\.123\.1\.4 [^^]* +.. 127\.123\.3\.1 [^^]* +.. 127\.123\.2\.2 [^^]* +.. 127\.123\.2\.3 [^^]* +.. 127\.123\.4\.4 [^^]* +.. 127\.123\.1\.2 *0 6 [^^]* +.. 127\.123\.5\.2 *0 7 [^^]* +.. 127\.123\.5\.4 [^^]*$" || test_fail + +stop_chronyd || test_fail + +test_pass diff --git a/test/system/009-binddevice b/test/system/009-binddevice new file mode 100755 index 0000000..fc64ae2 --- /dev/null +++ b/test/system/009-binddevice @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +. ./test.common + +[ "$(uname -s)" = "Linux" ] || test_skip "non-Linux system" + +test_start "binddevice directives" + +extra_chronyd_directives=" +binddevice lo +bindacqdevice lo +bindcmddevice lo" + +start_chronyd || test_fail +wait_for_sync || test_fail + +run_chronyc "ntpdata $server" || test_fail +check_chronyc_output "^Remote address" || test_fail + +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/100-clockupdate b/test/system/100-clockupdate new file mode 100755 index 0000000..191e461 --- /dev/null +++ b/test/system/100-clockupdate @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "update of system clock" + +clock_control=1 +minimal_config=1 + +start_chronyd || test_fail +run_chronyc "dfreq 1e-3" || test_fail +check_chronyc_output "200 OK" || test_fail + +before=$(date '+%s') +run_chronyc "doffset -1.0" || test_fail +check_chronyc_output "200 OK" || test_fail +run_chronyc "makestep" || test_fail +check_chronyc_output "200 OK" || test_fail +after=$(date '+%s') + +test_message 1 0 "checking system clock" +[ "$before" -lt "$after" ] && test_ok || test_bad || test_fail + +run_chronyc "doffset 1.0" || test_fail +run_chronyc "makestep" || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_message_count "System clock was stepped by" 2 2 || test_fail + +test_pass diff --git a/test/system/101-rtc b/test/system/101-rtc new file mode 100755 index 0000000..68bce68 --- /dev/null +++ b/test/system/101-rtc @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features RTC || test_skip "RTC support disabled" +[ -c "/dev/rtc" ] || test_skip "missing /dev/rtc" + +test_start "real-time clock" + +minimal_config=1 +extra_chronyd_options="-s" +extra_chronyd_directives="rtcfile $TEST_DIR/rtcfile" +echo "1 $(date +%s) 0.0 0.0" > "$TEST_DIR/rtcfile" + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_message_count "\(clock off from RTC\|RTC time before last\|Could not \(enable\|disable\) RTC interrupt\)" 1 1 || test_fail + +test_pass diff --git a/test/system/102-hwtimestamp b/test/system/102-hwtimestamp new file mode 100755 index 0000000..6b86d20 --- /dev/null +++ b/test/system/102-hwtimestamp @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +. ./test.common + +[ "$(uname -s)" = "Linux" ] || test_skip "non-Linux system" + +hwts_iface="" +for iface_path in /sys/class/net/*; do + iface=$(basename "$iface_path") + if ethtool -T "$iface" 2> /dev/null | grep -q ' all\($\| \)'; then + hwts_iface="$iface" + break + fi +done + +[ -n "$hwts_iface" ] || test_skip "no HW timestamping interface found" + +test_start "hardware timestamping" + +minimal_config=1 +extra_chronyd_directives="hwtimestamp $hwts_iface" + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_message_count "Enabled HW timestamping on $hwts_iface" 1 1 || test_fail + +test_pass diff --git a/test/system/103-refclock b/test/system/103-refclock new file mode 100755 index 0000000..e5b74e0 --- /dev/null +++ b/test/system/103-refclock @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features REFCLOCK || test_skip "refclock support disabled" + +test_start "reference clocks" + +extra_chronyd_directives=" +refclock SOCK $TEST_DIR/refclock.sock +refclock SHM 100" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/104-systemdirs b/test/system/104-systemdirs new file mode 100755 index 0000000..15508dc --- /dev/null +++ b/test/system/104-systemdirs @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +TEST_LIBDIR=${CHRONY_LIBDIR:-/var/lib/chrony} +TEST_LOGDIR=${CHRONY_LOGDIR:-/var/log/chrony} +TEST_RUNDIR=${CHRONY_RUNDIR:-/var/run/chrony} + +. ./test.common + +user=$(ls -ld "$TEST_RUNDIR" 2> /dev/null | awk '{print $3}') + +test_start "system directories" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/105-nts b/test/system/105-nts new file mode 100755 index 0000000..5833b2f --- /dev/null +++ b/test/system/105-nts @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +. ./test.common + +server_name="chrony-nts-test" + +check_chronyd_features NTS || test_skip "NTS support disabled" +certtool --help &> /dev/null || test_skip "certtool missing" +sed -i "/ $server_name\$/d" /etc/hosts && echo "$server $server_name" >> /etc/hosts || \ + test_skip "Cannot modify /etc/hosts" + +check_chronyd_features PRIVDROP && user="nobody" + +test_start "NTS authentication" + +cat > $TEST_DIR/cert.cfg <<EOF +cn = "$server_name" +serial = 001 +activation_date = "$(date -d '1 year ago' +'%Y-%m-%d') 00:00:00 UTC" +expiration_date = "$(date -d '1 year' +'%Y-%m-%d') 00:00:00 UTC" +signing_key +encryption_key +EOF + +certtool --generate-privkey --key-type=ed25519 --outfile $TEST_DIR/server.key \ + &> $TEST_DIR/certtool.log +certtool --generate-self-signed --load-privkey $TEST_DIR/server.key \ + --template $TEST_DIR/cert.cfg --outfile $TEST_DIR/server.crt &>> $TEST_DIR/certtool.log +chown $user $TEST_DIR/server.* + +ntpport=$(get_free_port) +ntsport=$(get_free_port) + +server_options="port $ntpport nts ntsport $ntsport" +extra_chronyd_directives=" +port $ntpport +ntsport $ntsport +ntsserverkey $TEST_DIR/server.key +ntsservercert $TEST_DIR/server.crt +ntstrustedcerts $TEST_DIR/server.crt +ntsdumpdir $TEST_LIBDIR +ntsprocesses 3" + +start_chronyd || test_fail +sleep 3 + +run_chronyc "authdata" || test_fail +check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen +========================================================================= +127\.0\.0\.1 NTS 1 15 256 [0-9] 0 0 [78] 100$" || test_fail + +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +rm -f $TEST_LOGDIR/measurements.log + +server_options="port $ntpport nts ntsport $((ntsport + 1))" + +start_chronyd || test_fail +sleep 2 + +run_chronyc "authdata" || test_fail +check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen +========================================================================= +127\.0\.0\.1 NTS 1 15 256 [0-9] 0 0 [78] 100$" || test_fail + +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/run b/test/system/run new file mode 100755 index 0000000..5516ed4 --- /dev/null +++ b/test/system/run @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +print_help() { + echo "$1 [-a] [-d] [TEST]..." +} + +run_test() { + local result name=$1 + + if [ $destructive -ne 1 ] && [[ "$name" == 1[0-9][0-9]-* ]]; then + echo "SKIP (destructive test)" + return 9 + fi + + ./$name + result=$? + + if [ $result -ne 0 -a $result -ne 9 ]; then + if [ $abort_on_fail -ne 0 ]; then + exit 1 + fi + fi + + return $result +} + +passed=() failed=() skipped=() + +abort_on_fail=0 +destructive=0 + +while getopts ":ad" opt; do + case $opt in + a) abort_on_fail=1;; + d) destructive=1;; + *) print_help "$0"; exit 3;; + esac +done + +shift $[$OPTIND - 1] + +[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_]) + +for test in "${tests[@]}"; do + printf "%s " "$test" + run_test $test + result=$? + echo + + case $result in + 0) passed=(${passed[@]} $test);; + 9) skipped=(${skipped[@]} $test);; + *) failed=(${failed[@]} $test);; + esac +done + +echo +echo "SUMMARY:" +echo " TOTAL $[${#passed[@]} + ${#failed[@]} + ${#skipped[@]}]" +echo " PASSED ${#passed[@]}" +echo " FAILED ${#failed[@]} (${failed[@]})" +echo " SKIPPED ${#skipped[@]} (${skipped[@]})" + +[ ${#failed[@]} -eq 0 ] diff --git a/test/system/test.common b/test/system/test.common new file mode 100644 index 0000000..1e48819 --- /dev/null +++ b/test/system/test.common @@ -0,0 +1,338 @@ +# Copyright (C) Miroslav Lichvar 2009 +# +# 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. + +export LC_ALL=C +export PATH=${CHRONY_PATH:-../..}:$PATH + +TEST_DIR=${TEST_DIR:-$(pwd)/tmp} +TEST_LIBDIR=${TEST_LIBDIR:-$TEST_DIR} +TEST_LOGDIR=${TEST_LOGDIR:-$TEST_DIR} +TEST_RUNDIR=${TEST_RUNDIR:-$TEST_DIR} + +test_start() { + check_chronyd_features NTP CMDMON || test_skip "NTP/CMDMON support disabled" + + [ "${#TEST_DIR}" -ge 5 ] || test_skip "invalid TEST_DIR" + + rm -rf "$TEST_DIR" + mkdir -p "$TEST_DIR" && chmod 700 "$TEST_DIR" || test_skip "could not create $TEST_DIR" + + [ -d "$TEST_LIBDIR" ] || test_skip "missing $TEST_LIBDIR" + [ -d "$TEST_LOGDIR" ] || test_skip "missing $TEST_LOGDIR" + [ -d "$TEST_RUNDIR" ] || test_skip "missing $TEST_RUNDIR" + + rm -f "$TEST_LIBDIR"/* "$TEST_LOGDIR"/* "$TEST_RUNDIR"/* + + if [ "$user" != "root" ]; then + id -u "$user" > /dev/null 2> /dev/null || test_skip "missing user $user" + chown "$user:$(id -g "$user")" "$TEST_DIR" || test_skip "could not chown $TEST_DIR" + su "$user" -s /bin/sh -c "touch $TEST_DIR/test" 2> /dev/null || \ + test_skip "$user cannot access $TEST_DIR" + rm "$TEST_DIR/test" + fi + + echo "Testing $*:" +} + +test_pass() { + echo "PASS" + exit 0 +} + +test_fail() { + echo "FAIL" + exit 1 +} + +test_skip() { + local msg=$1 + + [ -n "$msg" ] && echo "SKIP ($msg)" || echo "SKIP" + exit 9 +} + +test_ok() { + pad_line + echo -e "\tOK" + return 0 +} + +test_bad() { + pad_line + echo -e "\tBAD" + return 1 +} + +test_error() { + pad_line + echo -e "\tERROR" + return 1 +} + +chronyd=$(command -v chronyd) +chronyc=$(command -v chronyc) + +[ $EUID -eq 0 ] || test_skip "not root" + +[ -x "$chronyd" ] || test_skip "chronyd not found" +[ -x "$chronyc" ] || test_skip "chronyc not found" + +netstat -aln > /dev/null 2> /dev/null || test_skip "missing netstat" + +# Default test testings +default_minimal_config=0 +default_extra_chronyd_directives="" +default_extra_chronyd_options="" +default_clock_control=0 +default_server=127.0.0.1 +default_server_name=127.0.0.1 +default_server_options="" +default_user=root + +# Initialize test settings from their defaults +for defoptname in ${!default_*}; do + optname=${defoptname#default_} + [ -z "${!optname}" ] && declare "$optname"="${!defoptname}" +done + +msg_length=0 +pad_line() { + local line_length=56 + [ $msg_length -lt $line_length ] && \ + printf "%$((line_length - msg_length))s" "" + msg_length=0 +} + +# Print aligned message +test_message() { + local level=$1 eol=$2 + shift 2 + local msg="$*" + + while [ "$level" -gt 0 ]; do + echo -n " " + level=$((level - 1)) + msg_length=$((msg_length + 2)) + done + echo -n "$msg" + + msg_length=$((msg_length + ${#msg})) + if [ "$eol" -ne 0 ]; then + echo + msg_length=0 + fi +} + +# Check if chronyd has specified features +check_chronyd_features() { + local feature features + + features=$($chronyd -v | sed 's/.*(\(.*\)).*/\1/') + + for feature; do + echo "$features" | grep -q "+$feature" || return 1 + done +} + +# Print test settings which differ from default value +print_nondefaults() { + local defoptname optname + + test_message 1 1 "non-default settings:" + for defoptname in ${!default_*}; do + optname=${defoptname#default_} + [ "${!defoptname}" = "${!optname}" ] || \ + test_message 2 1 "$optname"=${!optname} + done +} + +get_conffile() { + echo "$TEST_DIR/chronyd.conf" +} + +get_pidfile() { + echo "$TEST_RUNDIR/chronyd.pid" +} + +get_logfile() { + echo "$TEST_LOGDIR/chronyd.log" +} + +get_cmdsocket() { + echo "$TEST_RUNDIR/chronyd.sock" +} + +# Find a free port in the 10000-20000 range (their use is racy) +get_free_port() { + local port + + while true; do + port=$((RANDOM % 10000 + 10000)) + netstat -aln | grep '^\(tcp\|udp\).*[:.]'"$port " && continue + break + done + + echo $port +} + +generate_chrony_conf() { + local ntpport cmdport + + ntpport=$(get_free_port) + cmdport=$(get_free_port) + + echo "0.0 10000" > "$TEST_LIBDIR/driftfile" + echo "1 MD5 abcdefghijklmnopq" > "$TEST_DIR/keys" + chown "$user:$(id -g "$user")" "$TEST_LIBDIR/driftfile" "$TEST_DIR/keys" + echo "0.0" > "$TEST_DIR/tempcomp" + + ( + echo "pidfile $(get_pidfile)" + echo "bindcmdaddress $(get_cmdsocket)" + echo "port $ntpport" + echo "cmdport $cmdport" + + echo "$extra_chronyd_directives" + + [ "$minimal_config" -ne 0 ] && exit 0 + + echo "allow" + echo "cmdallow" + echo "local" + + echo "server $server_name port $ntpport minpoll -6 maxpoll -6 $server_options" + + [ "$server" = "127.0.0.1" ] && echo "bindacqaddress $server" + echo "bindaddress 127.0.0.1" + echo "bindcmdaddress 127.0.0.1" + echo "dumpdir $TEST_RUNDIR" + echo "logdir $TEST_LOGDIR" + echo "log tempcomp rawmeasurements refclocks statistics tracking rtc" + echo "logbanner 0" + echo "smoothtime 100.0 0.001" + + echo "include /dev/null" + echo "keyfile $TEST_DIR/keys" + echo "driftfile $TEST_LIBDIR/driftfile" + echo "tempcomp $TEST_DIR/tempcomp 0.1 0 0 0 0" + + ) > "$(get_conffile)" +} + +get_chronyd_options() { + [ "$clock_control" -eq 0 ] && echo "-x" + echo "-l $(get_logfile)" + echo "-f $(get_conffile)" + echo "-u $user" + echo "$extra_chronyd_options" +} + +# Start a chronyd instance +start_chronyd() { + local pid pidfile=$(get_pidfile) + + print_nondefaults + test_message 1 0 "starting chronyd" + + generate_chrony_conf + + trap stop_chronyd EXIT + + $CHRONYD_WRAPPER "$chronyd" $(get_chronyd_options) > "$TEST_DIR/chronyd.out" 2>&1 + + [ $? -eq 0 ] && [ -f "$pidfile" ] && ps -p "$(cat "$pidfile")" > /dev/null && test_ok || test_error +} + +wait_for_sync() { + test_message 1 0 "waiting for synchronization" + sleep 1 && test_ok || test_error +} + +# Stop the chronyd instance +stop_chronyd() { + local pid pidfile + + pidfile=$(get_pidfile) + [ -f "$pidfile" ] || return 0 + + pid=$(cat "$pidfile") + + test_message 1 0 "stopping chronyd" + + if ! kill "$pid" 2> /dev/null; then + test_error + return + fi + + # Wait for the process to terminate (we cannot use "wait") + while ps -p "$pid" > /dev/null; do + sleep 0.1 + done + + test_ok +} + +# Check chronyd log for expected and unexpected messages +check_chronyd_messages() { + local logfile=$(get_logfile) + + test_message 1 0 "checking chronyd messages" + + grep -q 'chronyd exiting' "$logfile" && \ + ([ "$clock_control" -eq 0 ] || ! grep -q 'Disabled control of system clock' "$logfile") && \ + ([ "$clock_control" -ne 0 ] || grep -q 'Disabled control of system clock' "$logfile") && \ + ([ "$minimal_config" -ne 0 ] || grep -q 'Frequency .* read from' "$logfile") && \ + grep -q 'chronyd exiting' "$logfile" && \ + ! grep -q 'Could not' "$logfile" && \ + ! grep -q 'Disabled command socket' "$logfile" && \ + test_ok || test_bad +} + +# Check the number of messages matching a pattern in a specified file +check_chronyd_message_count() { + local count pattern=$1 min=$2 max=$3 logfile=$(get_logfile) + + test_message 1 0 "checking message \"$pattern\"" + + count=$(grep "$pattern" "$(get_logfile)" | wc -l) + + [ "$min" -le "$count" ] && [ "$count" -le "$max" ] && test_ok || test_bad +} + +# Check the logs and dump file for measurements and a clock update +check_chronyd_files() { + test_message 1 0 "checking chronyd files" + + grep -q " $server .* 111 111 1110 " "$TEST_LOGDIR/measurements.log" && \ + [ -f "$TEST_LOGDIR/tempcomp.log" ] && [ "$(wc -l < "$TEST_LOGDIR/tempcomp.log")" -ge 2 ] && \ + test_ok || test_bad +} + +# Run a chronyc command +run_chronyc() { + test_message 1 0 "running chronyc $*" + + $CHRONYC_WRAPPER "$chronyc" -h "$(get_cmdsocket)" -n -m "$@" > "$TEST_DIR/chronyc.out" && \ + test_ok || test_error +} + +# Compare chronyc output with specified pattern +check_chronyc_output() { + local pattern=$1 + + test_message 1 0 "checking chronyc output" + + [[ "$(cat "$TEST_DIR/chronyc.out")" =~ $pattern ]] && test_ok || test_bad +} |