$this->assertFalse($response->headers->hasCacheControlDirective('s-maxage'));
}
+
+ public function testMasterResponseNotCacheableWhenEmbeddedResponseRequiresValidation()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $embeddedResponse = new Response();
+ $embeddedResponse->setLastModified(new \DateTime());
+ $cacheStrategy->add($embeddedResponse);
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
+ $this->assertFalse($masterResponse->isFresh());
+ }
+
+ public function testValidationOnMasterResponseIsNotPossibleWhenItContainsEmbeddedResponses()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ // This master response uses the "validation" model
+ $masterResponse = new Response();
+ $masterResponse->setLastModified(new \DateTime());
+ $masterResponse->setEtag('foo');
+
+ // Embedded response uses "expiry" model
+ $embeddedResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600);
+ $cacheStrategy->add($embeddedResponse);
+
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertFalse($masterResponse->isValidateable());
+ $this->assertFalse($masterResponse->headers->has('Last-Modified'));
+ $this->assertFalse($masterResponse->headers->has('ETag'));
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
+ }
+
+ public function testMasterResponseWithValidationIsUnchangedWhenThereIsNoEmbeddedResponse()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setLastModified(new \DateTime());
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->isValidateable());
+ }
+
+ public function testMasterResponseWithExpirationIsUnchangedWhenThereIsNoEmbeddedResponse()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->isFresh());
+ }
+
+ public function testMasterResponseIsNotCacheableWhenEmbeddedResponseIsNotCacheable()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600); // Public, cacheable
+
+ /* This response has no validation or expiration information.
+ That makes it uncacheable, it is always stale.
+ (It does *not* make this private, though.) */
+ $embeddedResponse = new Response();
+ $this->assertFalse($embeddedResponse->isFresh()); // not fresh, as no lifetime is provided
+
+ $cacheStrategy->add($embeddedResponse);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
+ $this->assertFalse($masterResponse->isFresh());
+ }
+
+ public function testEmbeddingPrivateResponseMakesMainResponsePrivate()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600); // public, cacheable
+
+ // The embedded response might for example contain per-user data that remains valid for 60 seconds
+ $embeddedResponse = new Response();
+ $embeddedResponse->setPrivate();
+ $embeddedResponse->setMaxAge(60); // this would implicitly set "private" as well, but let's be explicit
+
+ $cacheStrategy->add($embeddedResponse);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('private'));
+ // Not sure if we should pass "max-age: 60" in this case, as long as the response is private and
+ // that's the more conservative of both the master and embedded response...?
+ }
+
+ public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndValidation()
+ {
+ /* When "expiration wins over validation" (https://symfony.com/doc/current/http_cache/validation.html)
+ * and both the main and embedded response provide s-maxage, then the more restricting value of both
+ * should be fine, regardless of whether the embedded response can be validated later on or must be
+ * completely regenerated.
+ */
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600);
+
+ $embeddedResponse = new Response();
+ $embeddedResponse->setSharedMaxAge(60);
+ $embeddedResponse->setEtag('foo');
+
+ $cacheStrategy->add($embeddedResponse);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage'));
+ }
+
+ public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombinesExpirationAndValidation()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setSharedMaxAge(3600);
+ $masterResponse->setEtag('foo');
+ $masterResponse->setLastModified(new \DateTime());
+
+ $embeddedResponse = new Response();
+ $embeddedResponse->setSharedMaxAge(60);
+
+ $cacheStrategy->add($embeddedResponse);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage'));
+ $this->assertFalse($masterResponse->isValidateable());
+ }
}