summaryrefslogtreecommitdiffstats
path: root/test/system
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 17:35:01 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 17:35:01 +0000
commit763b5e2c4bed507e0fa34ca2b7cb4f15a136cb82 (patch)
tree829cb7231c945c8e1e7d8ad62e94c4cb0f902ec6 /test/system
parentInitial commit. (diff)
downloadchrony-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 'test/system')
-rwxr-xr-xtest/system/001-minimal13
-rwxr-xr-xtest/system/002-extended13
-rwxr-xr-xtest/system/003-memlock15
-rwxr-xr-xtest/system/004-priority15
-rwxr-xr-xtest/system/005-scfilter17
-rwxr-xr-xtest/system/006-privdrop17
-rwxr-xr-xtest/system/007-cmdmon157
-rwxr-xr-xtest/system/008-confload75
-rwxr-xr-xtest/system/009-binddevice24
-rwxr-xr-xtest/system/100-clockupdate30
-rwxr-xr-xtest/system/101-rtc19
-rwxr-xr-xtest/system/102-hwtimestamp28
-rwxr-xr-xtest/system/103-refclock19
-rwxr-xr-xtest/system/104-systemdirs19
-rwxr-xr-xtest/system/105-nts72
-rwxr-xr-xtest/system/run64
-rw-r--r--test/system/test.common338
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
+}