From 7826cd7a4e1dc66fbd9239415107a75f8bab07cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 Aug 2025 14:39:48 +0000 Subject: [PATCH 1/3] Initial plan From fa030f3af82ba551c5f6a88b4dd88eaf4938a6af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 Aug 2025 14:53:49 +0000 Subject: [PATCH 2/3] Fix DST transition issue in cache expiry handling Replace DateTime('-1 seconds') with UTC timestamp approach to avoid timezone ambiguity during DST transitions. This prevents cache entries that should expire immediately from being cached for extended periods during DST transitions. Co-authored-by: Kevinrob <4509277+Kevinrob@users.noreply.github.com> --- src/Strategy/PrivateCacheStrategy.php | 4 +- tests/DstTransitionTest.php | 99 +++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 tests/DstTransitionTest.php diff --git a/src/Strategy/PrivateCacheStrategy.php b/src/Strategy/PrivateCacheStrategy.php index 23db04e..86d7947 100644 --- a/src/Strategy/PrivateCacheStrategy.php +++ b/src/Strategy/PrivateCacheStrategy.php @@ -83,7 +83,7 @@ protected function getCacheObject(RequestInterface $request, ResponseInterface $ if ($cacheControl->has('no-cache')) { // Stale response see RFC7234 section 5.2.1.4 - $entry = new CacheEntry($request, $response, new \DateTime('-1 seconds')); + $entry = new CacheEntry($request, $response, new \DateTime('@' . (time() - 1))); return $entry->hasValidationInformation() ? $entry : null; } @@ -109,7 +109,7 @@ protected function getCacheObject(RequestInterface $request, ResponseInterface $ } } - return new CacheEntry($request, $response, new \DateTime('-1 seconds')); + return new CacheEntry($request, $response, new \DateTime('@' . (time() - 1))); } /** diff --git a/tests/DstTransitionTest.php b/tests/DstTransitionTest.php new file mode 100644 index 0000000..f0ed84d --- /dev/null +++ b/tests/DstTransitionTest.php @@ -0,0 +1,99 @@ +originalTimezone = date_default_timezone_get(); + } + + protected function tearDown(): void + { + // Restore original timezone + date_default_timezone_set($this->originalTimezone); + } + + /** + * Test that UTC timestamp approach provides consistent behavior + * This verifies that our fix using '@' . (time() - 1) always creates + * expired timestamps regardless of timezone. + */ + public function testUtcTimestampApproachIsConsistentAcrossTimezones() + { + $timezones = ['UTC', 'Europe/Berlin', 'America/New_York', 'Asia/Tokyo']; + + foreach ($timezones as $timezone) { + date_default_timezone_set($timezone); + + // Create DateTime using UTC timestamp (the fix) + $utcDateTime = new \DateTime('@' . (time() - 1)); + + // Calculate TTL as the CacheEntry does + $ttl = $utcDateTime->getTimestamp() - time(); + + // This should always be negative (approximately -1) + $this->assertLessThanOrEqual(0, $ttl, "TTL should be negative in timezone: $timezone"); + $this->assertGreaterThanOrEqual(-2, $ttl, "TTL should not be too negative in timezone: $timezone"); + } + } + + /** + * Test CacheEntry behavior with UTC timestamp approach + * This ensures that cache entries marked for immediate expiry + * behave consistently across timezones. + */ + public function testCacheEntryWithUtcTimestampIsAlwaysStale() + { + $timezones = ['UTC', 'Europe/Berlin', 'America/New_York']; + + foreach ($timezones as $timezone) { + date_default_timezone_set($timezone); + + $request = new Request('GET', 'http://example.com'); + $response = new Response(200, [], 'test content'); + + // Create entry with UTC timestamp approach (the fix) + $entry = new CacheEntry($request, $response, new \DateTime('@' . (time() - 1))); + + // Should always be stale regardless of timezone + $this->assertTrue($entry->isStale(), "Entry should be stale in timezone: $timezone"); + $this->assertFalse($entry->isFresh(), "Entry should not be fresh in timezone: $timezone"); + $this->assertGreaterThan(0, $entry->getStaleAge(), "Stale age should be positive in timezone: $timezone"); + } + } + + /** + * Test that validates the TTL calculation is correct + */ + public function testCacheEntryTtlWithUtcTimestamp() + { + date_default_timezone_set('Europe/Berlin'); + + $request = new Request('GET', 'http://example.com'); + $response = new Response(200, [], 'test content'); + + // Create entry with UTC timestamp approach + $entry = new CacheEntry($request, $response, new \DateTime('@' . (time() - 1))); + + $ttl = $entry->getTTL(); + + // TTL should be -1 for expired entries without validation info + $this->assertEquals(-1, $ttl, "TTL should be -1 for expired entries without validation info"); + } +} \ No newline at end of file From 21b1fd53d8ec3f9a31e11e38936ea484bcc7e7ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:45:13 +0000 Subject: [PATCH 3/3] Remove framework testing method from DST transition tests Remove testUtcTimestampApproachIsConsistentAcrossTimezones method as it tests PHP's DateTime behavior rather than our cache middleware logic. Keep the tests that actually verify our CacheEntry implementation. Co-authored-by: Kevinrob <4509277+Kevinrob@users.noreply.github.com> --- tests/DstTransitionTest.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/DstTransitionTest.php b/tests/DstTransitionTest.php index f0ed84d..7e6757e 100644 --- a/tests/DstTransitionTest.php +++ b/tests/DstTransitionTest.php @@ -29,30 +29,6 @@ protected function tearDown(): void date_default_timezone_set($this->originalTimezone); } - /** - * Test that UTC timestamp approach provides consistent behavior - * This verifies that our fix using '@' . (time() - 1) always creates - * expired timestamps regardless of timezone. - */ - public function testUtcTimestampApproachIsConsistentAcrossTimezones() - { - $timezones = ['UTC', 'Europe/Berlin', 'America/New_York', 'Asia/Tokyo']; - - foreach ($timezones as $timezone) { - date_default_timezone_set($timezone); - - // Create DateTime using UTC timestamp (the fix) - $utcDateTime = new \DateTime('@' . (time() - 1)); - - // Calculate TTL as the CacheEntry does - $ttl = $utcDateTime->getTimestamp() - time(); - - // This should always be negative (approximately -1) - $this->assertLessThanOrEqual(0, $ttl, "TTL should be negative in timezone: $timezone"); - $this->assertGreaterThanOrEqual(-2, $ttl, "TTL should not be too negative in timezone: $timezone"); - } - } - /** * Test CacheEntry behavior with UTC timestamp approach * This ensures that cache entries marked for immediate expiry