diff --git a/src/core/timer.c b/src/core/timer.c index a45e0c393f..2e0a8a17c3 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -664,8 +664,6 @@ static int timer_start(Unit *u) { if (r < 0) return r; - t->last_trigger = DUAL_TIMESTAMP_NULL; - /* Reenable all timers that depend on unit activation time */ LIST_FOREACH(value, v, t->values) if (v->base == TIMER_ACTIVE) diff --git a/test/integration-tests/TEST-53-ISSUE-16347/meson.build b/test/integration-tests/TEST-53-TIMER/meson.build similarity index 100% rename from test/integration-tests/TEST-53-ISSUE-16347/meson.build rename to test/integration-tests/TEST-53-TIMER/meson.build diff --git a/test/integration-tests/meson.build b/test/integration-tests/meson.build index f28be9e24e..5965f6646c 100644 --- a/test/integration-tests/meson.build +++ b/test/integration-tests/meson.build @@ -70,7 +70,7 @@ foreach dirname : [ 'TEST-46-HOMED', 'TEST-50-DISSECT', 'TEST-52-HONORFIRSTSHUTDOWN', - 'TEST-53-ISSUE-16347', + 'TEST-53-TIMER', 'TEST-54-CREDS', 'TEST-55-OOMD', 'TEST-58-REPART', 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" </failed - # Reset host date to current time, 3 days in the past. date -s "-3 days" +trap 'date -s "+3 days"' EXIT # Run a timer for every 15 minutes. systemd-run --unit test-timer --on-calendar "*:0/15:0" true @@ -17,15 +16,12 @@ now=$(date +%s) time_delta=$((next_elapsed - now)) # Check that the timer will elapse in less than 20 minutes. -((0 < time_delta && time_delta < 1200)) || { +if [[ "$time_delta" -lt 0 || "$time_delta" -gt 1200 ]]; then echo 'Timer elapse outside of the expected 20 minute window.' echo " next_elapsed=${next_elapsed}" echo " now=${now}" echo " time_delta=${time_delta}" - echo '' -} >>/failed + echo -if test ! -s /failed ; then - rm -f /failed - touch /testok + exit 1 fi diff --git a/test/units/TEST-53-TIMER.restart-trigger.sh b/test/units/TEST-53-TIMER.restart-trigger.sh new file mode 100755 index 0000000000..057f379ddc --- /dev/null +++ b/test/units/TEST-53-TIMER.restart-trigger.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Restarting an already elapsed timer shouldn't immediately trigger the corresponding service unit. +# +# Provides coverage for: +# - https://github.com/systemd/systemd/issues/31231 +# - https://github.com/systemd/systemd/issues/35805 +set -eux +set -o pipefail + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/util.sh + +UNIT_NAME="timer-restart-$RANDOM" +TEST_MESSAGE="Hello from timer $RANDOM" + +# Setup +cat >"/run/systemd/system/$UNIT_NAME.timer" <"/run/systemd/system/$UNIT_NAME.service" <"/run/systemd/system/$UNIT_NAME.timer.d/99-override.conf" <&2 + exit 1 + fi +)} + assert_in() {( set +ex