2022-06-10 07:55:54 +03:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
2023-05-22 17:02:43 +03:00
# shellcheck source=test/units/test-control.sh
. " $( dirname " $0 " ) " /test-control.sh
2023-05-16 20:09:13 +03:00
# shellcheck source=test/units/util.sh
. " $( dirname " $0 " ) " /util.sh
2022-06-10 07:55:54 +03:00
2023-05-22 17:02:43 +03:00
testcase_timedatectl( ) {
2023-04-15 20:51:44 +03:00
timedatectl --no-pager --help
timedatectl --version
timedatectl
timedatectl --no-ask-password
timedatectl status --machine= testuser@.host
timedatectl status
timedatectl show
timedatectl show --all
timedatectl show -p NTP
timedatectl show -p NTP --value
timedatectl list-timezones
if ! systemd-detect-virt -qc; then
systemctl enable --runtime --now systemd-timesyncd
timedatectl timesync-status
timedatectl show-timesync
fi
}
2022-06-14 03:02:00 +03:00
restore_timezone( ) {
if [ [ -f /tmp/timezone.bak ] ] ; then
mv /tmp/timezone.bak /etc/timezone
else
rm -f /etc/timezone
fi
}
2023-05-22 17:02:43 +03:00
testcase_timezone( ) {
2022-06-10 07:55:54 +03:00
local ORIG_TZ =
2022-06-14 03:02:00 +03:00
# Debian/Ubuntu specific file
if [ [ -f /etc/timezone ] ] ; then
mv /etc/timezone /tmp/timezone.bak
fi
2022-06-14 15:08:04 +03:00
trap restore_timezone RETURN
2022-06-14 03:02:00 +03:00
2022-06-10 07:55:54 +03:00
if [ [ -L /etc/localtime ] ] ; then
ORIG_TZ = $( readlink /etc/localtime | sed 's#^.*zoneinfo/##' )
echo " original tz: $ORIG_TZ "
fi
echo 'timedatectl works'
assert_in "Local time:" " $( timedatectl --no-pager) "
echo 'change timezone'
assert_eq " $( timedatectl --no-pager set-timezone Europe/Kiev 2>& 1) " ""
assert_eq " $( readlink /etc/localtime | sed 's#^.*zoneinfo/##' ) " "Europe/Kiev"
2022-06-14 03:02:00 +03:00
if [ [ -f /etc/timezone ] ] ; then
assert_eq " $( cat /etc/timezone) " "Europe/Kiev"
fi
2022-10-30 05:59:10 +03:00
assert_in "Time zone: Europe/Kiev \(EES*T, \+0[0-9]00\)" " $( timedatectl) "
2022-06-10 07:55:54 +03:00
if [ [ -n " $ORIG_TZ " ] ] ; then
echo 'reset timezone to original'
2022-06-14 03:01:00 +03:00
assert_eq " $( timedatectl set-timezone " $ORIG_TZ " 2>& 1) " ""
2022-06-10 07:55:54 +03:00
assert_eq " $( readlink /etc/localtime | sed 's#^.*zoneinfo/##' ) " " $ORIG_TZ "
2022-06-14 03:02:00 +03:00
if [ [ -f /etc/timezone ] ] ; then
assert_eq " $( cat /etc/timezone) " " $ORIG_TZ "
fi
2022-06-10 07:55:54 +03:00
fi
}
restore_adjtime( ) {
if [ [ -e /etc/adjtime.bak ] ] ; then
mv /etc/adjtime.bak /etc/adjtime
else
rm /etc/adjtime
fi
}
check_adjtime_not_exist( ) {
if [ [ -e /etc/adjtime ] ] ; then
echo "/etc/adjtime unexpectedly exists." >& 2
exit 1
fi
}
2023-05-22 17:02:43 +03:00
testcase_adjtime( ) {
2022-06-10 07:55:54 +03:00
# test setting UTC vs. LOCAL in /etc/adjtime
if [ [ -e /etc/adjtime ] ] ; then
mv /etc/adjtime /etc/adjtime.bak
fi
2022-06-14 15:08:04 +03:00
trap restore_adjtime RETURN
2022-06-10 07:55:54 +03:00
echo 'no adjtime file'
rm -f /etc/adjtime
timedatectl set-local-rtc 0
check_adjtime_not_exist
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
timedatectl set-local-rtc 0
check_adjtime_not_exist
echo 'UTC set in adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nUTC\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
UTC"
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'non-zero values in adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.1 123 0\n0\nLOCAL\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
assert_eq " $( cat /etc/adjtime) " " 0.1 123 0
0
UTC"
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.1 123 0
0
LOCAL"
echo 'fourth line adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nLOCAL\nsomethingelse\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
UTC
somethingelse"
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL
somethingelse"
echo 'no final newline in adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nUTC' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nUTC' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'only one line in adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'only one line in adjtime file, no final newline'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'only two lines in adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'only two lines in adjtime file, no final newline'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
echo 'unknown value in 3rd line of adjtime file'
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nFOO\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 0
check_adjtime_not_exist
2023-02-05 23:41:24 +03:00
printf '0.0 0 0\n0\nFOO\n' >/etc/adjtime
2022-06-10 07:55:54 +03:00
timedatectl set-local-rtc 1
assert_eq " $( cat /etc/adjtime) " " 0.0 0 0
0
LOCAL"
}
assert_ntp( ) {
2023-11-08 11:13:45 +03:00
local value = " ${ 1 : ? } "
for _ in { 0..9} ; do
[ [ " $( busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP) " = = " b $value " ] ] && return 0
sleep .5
done
return 1
2022-06-10 07:55:54 +03:00
}
2023-11-07 16:35:06 +03:00
assert_timedated_signal( ) {
local timestamp = " ${ 1 : ? } "
local value = " ${ 2 : ? } "
local args = ( -q -n 1 --since= " $timestamp " -p info _SYSTEMD_UNIT = "busctl-monitor.service" )
journalctl --sync
for _ in { 0..9} ; do
if journalctl " ${ args [@] } " --grep .; then
2023-11-09 15:27:02 +03:00
[ [ " $( journalctl " ${ args [@] } " -o cat | jq -r '.payload.data[1].NTP.data' ) " = = " $value " ] ] ;
2023-11-07 16:35:06 +03:00
return 0
fi
sleep .5
done
return 1
2022-06-10 07:55:54 +03:00
}
2023-11-07 16:35:06 +03:00
assert_timesyncd_state( ) {
local state = " ${ 1 : ? } "
for _ in { 0..9} ; do
[ [ " $( systemctl show systemd-timesyncd.service -P ActiveState) " = = " $state " ] ] && return 0
sleep .5
2022-06-10 07:55:54 +03:00
done
2023-11-07 16:35:06 +03:00
return 1
2022-06-10 07:55:54 +03:00
}
2023-05-22 17:02:43 +03:00
testcase_ntp( ) {
2022-06-10 07:55:54 +03:00
# timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing
if systemd-detect-virt --container --quiet; then
systemctl disable --quiet --now systemd-timesyncd
mkdir -p /run/systemd/system/systemd-timesyncd.service.d
cat >/run/systemd/system/systemd-timesyncd.service.d/container.conf <<EOF
[ Unit]
ConditionVirtualization =
[ Service]
Type = simple
AmbientCapabilities =
ExecStart =
2024-01-04 17:24:52 +03:00
ExecStart = sleep infinity
2022-06-10 07:55:54 +03:00
EOF
systemctl daemon-reload
fi
2023-11-09 02:00:27 +03:00
systemd-run --unit busctl-monitor.service --service-type= notify \
2023-11-09 01:38:28 +03:00
busctl monitor --json= short --match= "type=signal,sender=org.freedesktop.timedate1,member=PropertiesChanged,path=/org/freedesktop/timedate1"
2022-06-10 07:55:54 +03:00
2023-11-07 16:35:06 +03:00
: 'Disable NTP'
2023-11-09 13:45:35 +03:00
ts = " $( date +"%F %T.%6N" ) "
2022-06-10 07:55:54 +03:00
timedatectl set-ntp false
2023-11-09 13:45:35 +03:00
assert_timedated_signal " $ts " "false"
2023-11-07 16:35:06 +03:00
assert_timesyncd_state "inactive"
2022-06-10 07:55:54 +03:00
assert_ntp "false"
assert_rc 3 systemctl is-active --quiet systemd-timesyncd
2023-11-07 16:35:06 +03:00
: 'Enable NTP'
ts = " $( date +"%F %T.%6N" ) "
2022-06-10 07:55:54 +03:00
timedatectl set-ntp true
2023-11-07 16:35:06 +03:00
assert_timedated_signal " $ts " "true"
2022-06-10 07:55:54 +03:00
assert_ntp "true"
2023-11-07 16:35:06 +03:00
assert_timesyncd_state "active"
2022-06-10 07:55:54 +03:00
assert_rc 0 systemctl is-active --quiet systemd-timesyncd
2023-11-07 16:35:06 +03:00
: 'Re-disable NTP'
ts = " $( date +"%F %T.%6N" ) "
2022-06-10 07:55:54 +03:00
timedatectl set-ntp false
2023-11-07 16:35:06 +03:00
assert_timedated_signal " $ts " "false"
2022-06-10 07:55:54 +03:00
assert_ntp "false"
assert_rc 3 systemctl is-active --quiet systemd-timesyncd
2023-11-07 16:35:06 +03:00
systemctl stop busctl-monitor.service
2023-11-07 15:16:05 +03:00
rm -rf /run/systemd/system/systemd-timesyncd.service.d/
systemctl daemon-reload
}
assert_timesyncd_signal( ) {
local timestamp = " ${ 1 : ? } "
local property = " ${ 2 : ? } "
local value = " ${ 3 : ? } "
local args = ( -q --since= " $timestamp " -p info _SYSTEMD_UNIT = "busctl-monitor.service" )
journalctl --sync
for _ in { 0..9} ; do
if journalctl " ${ args [@] } " --grep .; then
2023-11-09 15:27:02 +03:00
[ [ " $( journalctl " ${ args [@] } " -o cat | jq -r " .payload.data[1]. $property .data | join(\" \") " ) " = = " $value " ] ] ;
2023-11-07 15:16:05 +03:00
return 0
fi
sleep .5
done
return 1
}
assert_networkd_ntp( ) {
local interface = " ${ 1 : ? } "
local value = " ${ 2 : ? } "
# Go through the array of NTP servers and for each entry do:
# - if the entry is an IPv4 address, join the Address array into a dot separated string
# - if the entry is a server address, select it unchanged
# These steps produce an array of strings, that is then joined into a space-separated string
# Note: this doesn't support IPv6 addresses, since converting them to a string is a bit more
# involved than a simple join(), but let's leave that to another time
local expr = '[.NTP[] | (select(.Family == 2).Address | join(".")), select(has("Server")).Server] | join(" ")'
[ [ " $( networkctl status " $interface " --json= short | jq -r " $expr " ) " = = " $value " ] ]
}
testcase_timesyncd( ) {
if systemd-detect-virt -cq; then
echo "This test case requires a VM, skipping..."
return 0
fi
if ! command -v networkctl >/dev/null; then
echo "This test requires systemd-networkd, skipping..."
return 0
fi
# Create a dummy interface managed by networkd, so we can configure link NTP servers
mkdir -p /run/systemd/network/
2023-11-08 21:10:59 +03:00
cat >/etc/systemd/network/10-ntp99.netdev <<EOF
2023-11-07 15:16:05 +03:00
[ NetDev]
Name = ntp99
Kind = dummy
EOF
2023-11-08 21:10:59 +03:00
cat >/etc/systemd/network/10-ntp99.network <<EOF
2023-11-07 15:16:05 +03:00
[ Match]
Name = ntp99
[ Network]
Address = 10.0.0.1/24
EOF
systemctl unmask systemd-timesyncd systemd-networkd
systemctl restart systemd-timesyncd
systemctl restart systemd-networkd
networkctl status ntp99
2023-11-09 02:00:27 +03:00
systemd-run --unit busctl-monitor.service --service-type= notify \
2023-11-09 01:38:28 +03:00
busctl monitor --json= short --match= "type=signal,sender=org.freedesktop.timesync1,member=PropertiesChanged,path=/org/freedesktop/timesync1"
2023-11-07 15:16:05 +03:00
# LinkNTPServers
#
# Single IP
ts = " $( date +"%F %T.%6N" ) "
timedatectl ntp-servers ntp99 10.0.0.1
assert_networkd_ntp ntp99 10.0.0.1
assert_timesyncd_signal " $ts " LinkNTPServers 10.0.0.1
# Setting NTP servers to the same value shouldn't emit a PropertiesChanged signal
ts = " $( date +"%F %T.%6N" ) "
timedatectl ntp-servers ntp99 10.0.0.1
assert_networkd_ntp ntp99 10.0.0.1
( ! assert_timesyncd_signal " $ts " LinkNTPServers 10.0.0.1)
# Multiple IPs
ts = " $( date +"%F %T.%6N" ) "
timedatectl ntp-servers ntp99 10.0.0.1 192.168.0.99
assert_networkd_ntp ntp99 "10.0.0.1 192.168.0.99"
assert_timesyncd_signal " $ts " LinkNTPServers "10.0.0.1 192.168.0.99"
# Multiple IPs + servers
ts = " $( date +"%F %T.%6N" ) "
timedatectl ntp-servers ntp99 10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13
assert_networkd_ntp ntp99 "10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13"
assert_timesyncd_signal " $ts " LinkNTPServers "10.0.0.1 192.168.0.99 foo.localhost foo 10.11.12.13"
# RuntimeNTPServers
#
2023-11-08 08:57:33 +03:00
# There's no user-facing API that allows changing this property (afaik), so let's
2023-11-07 15:16:05 +03:00
# call SetRuntimeNTPServers() directly to test things out. The inner workings should
# be exactly the same as in the previous case, so do just one test to make sure
# things work
ts = " $( date +"%F %T.%6N" ) "
busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
SetRuntimeNTPServers as 4 "10.0.0.1" foo "192.168.99.1" bar
servers = " $( busctl get-property org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager RuntimeNTPServers) "
[ [ " $servers " = = 'as 4 "10.0.0.1" "foo" "192.168.99.1" "bar"' ] ]
assert_timesyncd_signal " $ts " RuntimeNTPServers "10.0.0.1 foo 192.168.99.1 bar"
# Cleanup
systemctl stop systemd-networkd systemd-timesyncd
rm -f /run/systemd/network/ntp99.*
2022-06-10 07:55:54 +03:00
}
2023-05-22 17:02:43 +03:00
run_testcases
2022-06-10 07:55:54 +03:00
touch /testok