From fdd763b42d864b4f7777fe9394a29c520c613d78 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Tue, 23 Sep 2025 21:04:12 +0200 Subject: [PATCH] test: check the next elapse timer timestamp after deserialization When deserializing a serialized timer unit with RandomizedDelaySec= set, systemd should use the last inactive exit timestamp instead of current realtime to calculate the new next elapse, so the timer unit actually runs in the given calendar window. Provides coverage for: - https://github.com/systemd/systemd/issues/18678 - https://github.com/systemd/systemd/pull/27752 (cherry picked from commit f4c3c107d9be4e922a080fc292ed3889c4e0f4a5) Related: RHEL-108744 --- .../testsuite.RandomizedDelaySec-reload.sh | 94 +++++++++++++++++++ test/test-functions | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100755 test/TEST-53-TIMER/testsuite.RandomizedDelaySec-reload.sh diff --git a/test/TEST-53-TIMER/testsuite.RandomizedDelaySec-reload.sh b/test/TEST-53-TIMER/testsuite.RandomizedDelaySec-reload.sh new file mode 100755 index 0000000000..54b90d3dd1 --- /dev/null +++ b/test/TEST-53-TIMER/testsuite.RandomizedDelaySec-reload.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# When deserializing a serialized timer unit with RandomizedDelaySec= set, systemd should use the last +# inactive exit timestamp instead of current realtime to calculate the new next elapse, so the timer unit +# actually runs in the given calendar window. +# +# Provides coverage for: +# - https://github.com/systemd/systemd/issues/18678 +# - https://github.com/systemd/systemd/pull/27752 +set -eux +set -o pipefail + +UNIT_NAME="timer-RandomizedDelaySec-$RANDOM" +TARGET_TS="$(date --date="tomorrow 00:10")" +TARGET_TS_S="$(date --date="$TARGET_TS" "+%s")" +# Maximum possible next elapse timestamp: $TARGET_TS (OnCalendar=) + 22 hours (RandomizedDelaySec=) +MAX_NEXT_ELAPSE_REALTIME_S="$((TARGET_TS_S + 22 * 60 * 60))" +MAX_NEXT_ELAPSE_REALTIME="$(date --date="@$MAX_NEXT_ELAPSE_REALTIME_S")" + +# Let's make sure to return the date & time back to the original state once we're done with our time +# shenigans. One way to do this would be to use hwclock, but the RTC in VMs can be unreliable or slow to +# respond, causing unexpected test fails/timeouts. +# +# Instead, let's save the realtime timestamp before we start with the test together with a current monotonic +# timestamp, after the test ends take the difference between the current monotonic timestamp and the "start" +# one, add it to the originally saved realtime timestamp, and finally use that timestamp to set the system +# time. This should advance the system time by the amount of time the test actually ran, and hence restore it +# to some sane state after the time jumps performed by the test. It won't be perfect, but it should be close +# enough for our needs. +START_REALTIME="$(date "+%s")" +START_MONOTONIC="$(cut -d . -f 1 /proc/uptime)" +at_exit() { + : "Restore the system date to a sane state" + END_MONOTONIC="$(cut -d . -f 1 /proc/uptime)" + date --set="@$((START_REALTIME + END_MONOTONIC - START_MONOTONIC))" +} +trap at_exit EXIT + +# Set some predictable time so we can schedule the first timer elapse in a deterministic-ish way +date --set="23:00" + +# Setup +cat >"/run/systemd/system/$UNIT_NAME.timer" <"/run/systemd/system/$UNIT_NAME.service" <