8d419f
From 014a660c937c1c5ebfc05667466a16b44e446c60 Mon Sep 17 00:00:00 2001
8d419f
From: Yu Watanabe <watanabe.yu+github@gmail.com>
8d419f
Date: Fri, 10 Jun 2022 13:55:54 +0900
8d419f
Subject: [PATCH] test: import timedated test from debian/ubuntu test suite
8d419f
8d419f
(cherry picked from commit 759ed0a2533da8840dea315d07f92e6bb0272cdd)
8d419f
8d419f
Related: #2087652
8d419f
---
8d419f
 test/TEST-45-TIMEDATE/Makefile  |   1 +
8d419f
 test/TEST-45-TIMEDATE/test.sh   |  10 ++
8d419f
 test/units/assert.sh            |  44 ++++++
8d419f
 test/units/testsuite-45.service |  10 ++
8d419f
 test/units/testsuite-45.sh      | 246 ++++++++++++++++++++++++++++++++
8d419f
 5 files changed, 311 insertions(+)
8d419f
 create mode 120000 test/TEST-45-TIMEDATE/Makefile
8d419f
 create mode 100755 test/TEST-45-TIMEDATE/test.sh
8d419f
 create mode 100644 test/units/assert.sh
8d419f
 create mode 100644 test/units/testsuite-45.service
8d419f
 create mode 100755 test/units/testsuite-45.sh
8d419f
8d419f
diff --git a/test/TEST-45-TIMEDATE/Makefile b/test/TEST-45-TIMEDATE/Makefile
8d419f
new file mode 120000
8d419f
index 0000000000..e9f93b1104
8d419f
--- /dev/null
8d419f
+++ b/test/TEST-45-TIMEDATE/Makefile
8d419f
@@ -0,0 +1 @@
8d419f
+../TEST-01-BASIC/Makefile
8d419f
\ No newline at end of file
8d419f
diff --git a/test/TEST-45-TIMEDATE/test.sh b/test/TEST-45-TIMEDATE/test.sh
8d419f
new file mode 100755
8d419f
index 0000000000..27edf4a3b9
8d419f
--- /dev/null
8d419f
+++ b/test/TEST-45-TIMEDATE/test.sh
8d419f
@@ -0,0 +1,10 @@
8d419f
+#!/usr/bin/env bash
8d419f
+# SPDX-License-Identifier: LGPL-2.1-or-later
8d419f
+set -e
8d419f
+
8d419f
+TEST_DESCRIPTION="test timedated"
8d419f
+
8d419f
+# shellcheck source=test/test-functions
8d419f
+. "${TEST_BASE_DIR:?}/test-functions"
8d419f
+
8d419f
+do_test "$@"
8d419f
diff --git a/test/units/assert.sh b/test/units/assert.sh
8d419f
new file mode 100644
8d419f
index 0000000000..db67dad268
8d419f
--- /dev/null
8d419f
+++ b/test/units/assert.sh
8d419f
@@ -0,0 +1,44 @@
8d419f
+#!/usr/bin/env bash
8d419f
+# SPDX-License-Identifier: LGPL-2.1-or-later
8d419f
+
8d419f
+# utility functions for shell tests
8d419f
+
8d419f
+assert_true() {
8d419f
+    local rc
8d419f
+
8d419f
+    set +e
8d419f
+    "$@"
8d419f
+    rc=$?
8d419f
+    set -e
8d419f
+    if [[ "$rc" != "0" ]]; then
8d419f
+        echo "FAIL: command '$*' failed with exit code $rc" >&2
8d419f
+        exit 1
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+
8d419f
+assert_eq() {
8d419f
+    if [[ "$1" != "$2" ]]; then
8d419f
+        echo "FAIL: expected: '$2' actual: '$1'" >&2
8d419f
+        exit 1
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+assert_in() {
8d419f
+    if ! echo "$2" | grep -q "$1"; then
8d419f
+        echo "FAIL: '$1' not found in:" >&2
8d419f
+        echo "$2" >&2
8d419f
+        exit 1
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+assert_rc() {
8d419f
+    local exp=$1
8d419f
+    local rc
8d419f
+    shift
8d419f
+    set +e
8d419f
+    "$@"
8d419f
+    rc=$?
8d419f
+    set -e
8d419f
+    assert_eq "$rc" "$exp"
8d419f
+}
8d419f
diff --git a/test/units/testsuite-45.service b/test/units/testsuite-45.service
8d419f
new file mode 100644
8d419f
index 0000000000..79c0a6f117
8d419f
--- /dev/null
8d419f
+++ b/test/units/testsuite-45.service
8d419f
@@ -0,0 +1,10 @@
8d419f
+# SPDX-License-Identifier: LGPL-2.1-or-later
8d419f
+[Unit]
8d419f
+Description=TEST-45-TIMEDATE
8d419f
+
8d419f
+[Service]
8d419f
+ExecStartPre=rm -f /failed /testok
8d419f
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
8d419f
+StandardOutput=journal+console
8d419f
+StandardError=journal+console
8d419f
+Type=oneshot
8d419f
diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh
8d419f
new file mode 100755
8d419f
index 0000000000..ac7860dccd
8d419f
--- /dev/null
8d419f
+++ b/test/units/testsuite-45.sh
8d419f
@@ -0,0 +1,246 @@
8d419f
+#!/usr/bin/env bash
8d419f
+# SPDX-License-Identifier: LGPL-2.1-or-later
8d419f
+
8d419f
+set -eux
8d419f
+set -o pipefail
8d419f
+
8d419f
+# shellcheck source=test/units/assert.sh
8d419f
+. "$(dirname "$0")"/assert.sh
8d419f
+
8d419f
+test_timezone() {
8d419f
+    local ORIG_TZ=
8d419f
+
8d419f
+    if [[ -L /etc/localtime ]]; then
8d419f
+        ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')
8d419f
+        echo "original tz: $ORIG_TZ"
8d419f
+    fi
8d419f
+
8d419f
+    echo 'timedatectl works'
8d419f
+    assert_in "Local time:" "$(timedatectl --no-pager)"
8d419f
+
8d419f
+    echo 'change timezone'
8d419f
+    assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" ""
8d419f
+    assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev"
8d419f
+    assert_in "Time.*zone: Europe/Kiev (EEST, +" "$(timedatectl --no-pager)"
8d419f
+
8d419f
+    if [[ -n "$ORIG_TZ" ]]; then
8d419f
+        echo 'reset timezone to original'
8d419f
+        assert_eq "$(timedatectl --no-pager set-timezone "$ORIG_TZ" 2>&1)" ""
8d419f
+        assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ"
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+restore_adjtime() {
8d419f
+    if [[ -e /etc/adjtime.bak ]]; then
8d419f
+        mv /etc/adjtime.bak /etc/adjtime
8d419f
+    else
8d419f
+        rm /etc/adjtime
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+check_adjtime_not_exist() {
8d419f
+    if [[ -e /etc/adjtime ]]; then
8d419f
+        echo "/etc/adjtime unexpectedly exists." >&2
8d419f
+        exit 1
8d419f
+    fi
8d419f
+}
8d419f
+
8d419f
+test_adjtime() {
8d419f
+    # test setting UTC vs. LOCAL in /etc/adjtime
8d419f
+    if [[ -e /etc/adjtime ]]; then
8d419f
+        mv /etc/adjtime /etc/adjtime.bak
8d419f
+    fi
8d419f
+
8d419f
+    trap restore_adjtime EXIT
8d419f
+
8d419f
+    echo 'no adjtime file'
8d419f
+    rm -f /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+
8d419f
+    echo 'UTC set in adjtime file'
8d419f
+    printf '0.0 0 0\n0\nUTC\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+UTC"
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'non-zero values in adjtime file'
8d419f
+    printf '0.1 123 0\n0\nLOCAL\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.1 123 0
8d419f
+0
8d419f
+UTC"
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.1 123 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'fourth line adjtime file'
8d419f
+    printf '0.0 0 0\n0\nLOCAL\nsomethingelse\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+UTC
8d419f
+somethingelse"
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL
8d419f
+somethingelse"
8d419f
+
8d419f
+    echo 'no final newline in adjtime file'
8d419f
+    printf '0.0 0 0\n0\nUTC' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0\n0\nUTC' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'only one line in adjtime file'
8d419f
+    printf '0.0 0 0\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'only one line in adjtime file, no final newline'
8d419f
+    printf '0.0 0 0' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'only two lines in adjtime file'
8d419f
+    printf '0.0 0 0\n0\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0\n0\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'only two lines in adjtime file, no final newline'
8d419f
+    printf '0.0 0 0\n0' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0\n0' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    echo 'unknown value in 3rd line of adjtime file'
8d419f
+    printf '0.0 0 0\n0\nFOO\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 0
8d419f
+    check_adjtime_not_exist
8d419f
+    printf '0.0 0 0\n0\nFOO\n' > /etc/adjtime
8d419f
+    timedatectl set-local-rtc 1
8d419f
+    assert_eq "$(cat /etc/adjtime)" "0.0 0 0
8d419f
+0
8d419f
+LOCAL"
8d419f
+
8d419f
+    restore_adjtime
8d419f
+    trap - EXIT
8d419f
+}
8d419f
+
8d419f
+assert_ntp() {
8d419f
+    assert_eq "$(busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP)" "b $1"
8d419f
+}
8d419f
+
8d419f
+start_mon() {
8d419f
+    busctl monitor --match="type='signal',sender=org.freedesktop.timedate1,member='PropertiesChanged',path=/org/freedesktop/timedate1" >"$mon" &
8d419f
+    MONPID=$!
8d419f
+}
8d419f
+
8d419f
+wait_mon() {
8d419f
+    for ((i=0;i<10;i++)); do
8d419f
+        if (( i != 0 )); then sleep 1; fi
8d419f
+        if grep -q "$1" "$mon"; then break; fi
8d419f
+    done
8d419f
+    assert_in "$2" "$(cat "$mon")"
8d419f
+    kill "$MONPID"
8d419f
+    wait "$MONPID" 2>/dev/null || true
8d419f
+}
8d419f
+
8d419f
+test_ntp() {
8d419f
+    # timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing
8d419f
+    if systemd-detect-virt --container --quiet; then
8d419f
+        systemctl disable --quiet --now systemd-timesyncd
8d419f
+        mkdir -p /run/systemd/system/systemd-timesyncd.service.d
8d419f
+        cat >/run/systemd/system/systemd-timesyncd.service.d/container.conf <
8d419f
+[Unit]
8d419f
+ConditionVirtualization=
8d419f
+
8d419f
+[Service]
8d419f
+Type=simple
8d419f
+AmbientCapabilities=
8d419f
+ExecStart=
8d419f
+ExecStart=/bin/sleep infinity
8d419f
+EOF
8d419f
+        systemctl daemon-reload
8d419f
+    fi
8d419f
+
8d419f
+    mon=$(mktemp -t dbusmon.XXXXXX)
8d419f
+
8d419f
+    echo 'disable NTP'
8d419f
+    timedatectl set-ntp false
8d419f
+    for ((i=0;i<10;i++)); do
8d419f
+        if (( i != 0 )); then sleep 1; fi
8d419f
+        if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then
8d419f
+            break;
8d419f
+        fi
8d419f
+    done
8d419f
+    assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=inactive"
8d419f
+    assert_ntp "false"
8d419f
+    assert_rc 3 systemctl is-active --quiet systemd-timesyncd
8d419f
+
8d419f
+    echo 'enable NTP'
8d419f
+    start_mon
8d419f
+    timedatectl set-ntp true
8d419f
+    wait_mon "NTP" "BOOLEAN true"
8d419f
+    assert_ntp "true"
8d419f
+    for ((i=0;i<10;i++)); do
8d419f
+        if (( i != 0 )); then sleep 1; fi
8d419f
+        if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then
8d419f
+            break;
8d419f
+        fi
8d419f
+    done
8d419f
+    assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=active"
8d419f
+    assert_rc 0 systemctl is-active --quiet systemd-timesyncd
8d419f
+
8d419f
+    echo 're-disable NTP'
8d419f
+    start_mon
8d419f
+    timedatectl set-ntp false
8d419f
+    wait_mon "NTP" "BOOLEAN false"
8d419f
+    assert_ntp "false"
8d419f
+    assert_rc 3 systemctl is-active --quiet systemd-timesyncd
8d419f
+}
8d419f
+
8d419f
+: >/failed
8d419f
+
8d419f
+test_timezone
8d419f
+test_adjtime
8d419f
+test_ntp
8d419f
+
8d419f
+touch /testok
8d419f
+rm /failed