diff --git a/test/units/TEST-53-TIMER.RandomizedDelaySec-reload.sh b/test/units/TEST-53-TIMER.RandomizedDelaySec-reload.sh new file mode 100755 index 0000000000..08f4f469d6 --- /dev/null +++ b/test/units/TEST-53-TIMER.RandomizedDelaySec-reload.sh @@ -0,0 +1,97 @@ +#!/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 + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/util.sh + +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" <&2 + exit 1 + fi +)} + assert_in() {( set +ex