From 9ed4d37017bb1d33c6ae1ca9d2a819311cba3102 Mon Sep 17 00:00:00 2001 From: Andreas Kienast <a.fernandez@scripting-base.de> Date: Sat, 30 Mar 2024 15:27:16 +0100 Subject: [PATCH] [BUGFIX] Handle roll-over of dates in `RotatingFileWriterTest` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the test class `RotatingFileWriterTest`, the `MONTHLY` and `YEARLY` cases for `writingLogWithExpiredLatestRotationInTimeFrameRotates` may fail as it tries to create a mock file that needs rotation with a broken date. It is expected to create a file with a date of the previous period that's tested. However, at the end of uneven months or each Feb. 29th this will heavily fail due to PHP's automatic roll-over to the next valid date. We'd need a fallback to the latest valid date here. The aforementioned test now has a special handling in place in case either `MONTHLY` or `YEARLY` are tested – the date is modified to go back to the first day of the respective period and then either set the current day OR the latest days in that period, whatever fits. Resolves: #103509 Releases: main Change-Id: Ic60c3056ed31933ff7be3af196ba08ed92f04855 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83630 Reviewed-by: Nikita Hovratov <nikita.h@live.de> Tested-by: core-ci <typo3@b13.com> Tested-by: Nikita Hovratov <nikita.h@live.de> Tested-by: Oliver Klee <typo3-coding@oliverklee.de> Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de> --- .../Log/Writer/RotatingFileWriterTest.php | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/typo3/sysext/core/Tests/Unit/Log/Writer/RotatingFileWriterTest.php b/typo3/sysext/core/Tests/Unit/Log/Writer/RotatingFileWriterTest.php index 4b583076f7d4..9d887cdf2ad3 100644 --- a/typo3/sysext/core/Tests/Unit/Log/Writer/RotatingFileWriterTest.php +++ b/typo3/sysext/core/Tests/Unit/Log/Writer/RotatingFileWriterTest.php @@ -131,11 +131,32 @@ final class RotatingFileWriterTest extends UnitTestCase #[Test] public function writingLogWithExpiredLatestRotationInTimeFrameRotates(Interval $interval): void { - // Helper variable to ensure the next rotation interval kicks in - $boost = 100; - $rotationDate = (new \DateTime('@' . (time() - $boost))) - ->sub(new \DateInterval($interval->getDateInterval())) - ->format('YmdHis'); + $rotationDateModifierClosure = match ($interval) { + Interval::MONTHLY, Interval::YEARLY => static function (\DateTimeImmutable $rotationDate) use ($interval): \DateTimeImmutable { + // This is great – when subtracting 1 month or 1 year, it may happen that the result would be invalid: + // e.g. 2024-03-30 -1 month -> 2024-02-30, 2024-05-31 -1 month -> 2024-04-31, 2028-02-29 -1 year -> 2027-02-29, etc. + // PHP thankfully catches this and rolls over to the next(!) valid date: + // e.g. 2024-03-30 -1 month -> 2024-03-01, 2024-05-31 -1 month -> 2024-05-01, 2028-02-29 -1 year -> 2027-03-01, etc. + // However, this is not the desired result in this case when SUBTRACTING a month as the previous(!!) valid date is required. + // For this reason, a custom handling in case of months and years is in place that goes back in time to the first day of + // the given period, and sets the current day or the last day of the resulting period, whatever fits: + // e.g. 2024-03-30 -1 month -> 2024-02-29, 2024-05-12 -1 month -> 2024-04-12, 2028-02-29 -1 year -> 2027-02-28, etc. + if ($interval === Interval::MONTHLY) { + $firstDayOfModifier = 'first day of -1 month'; + } else { + $firstDayOfModifier = 'first day of -1 year'; + } + + $currentDay = $rotationDate->format('j'); + $rotationDate = $rotationDate->modify($firstDayOfModifier); + $totalDays = $rotationDate->format('t'); + return $rotationDate->modify('+' . (min($currentDay, $totalDays) - 1) . ' days'); + }, + default => static function (\DateTimeImmutable $rotationDate) use ($interval): \DateTimeImmutable { + return $rotationDate->sub(new \DateInterval($interval->getDateInterval())); + }, + }; + $rotationDate = $rotationDateModifierClosure(new \DateTimeImmutable('@' . time()))->format('YmdHis'); $logFileName = $this->getDefaultFileName(); file_put_contents($logFileName, 'fooo'); -- GitLab