diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 6d67a177398c2..6522c935c36c0 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -237,4 +237,144 @@ public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombi $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage')); $this->assertFalse($masterResponse->isValidateable()); } + + /** + * @dataProvider cacheControlMergingProvider + */ + public function testCacheControlMerging(array $expects, array $master, array $surrogates) + { + $cacheStrategy = new ResponseCacheStrategy(); + $buildResponse = function ($config) { + $response = new Response(); + + foreach ($config as $key => $value) { + switch ($key) { + case 'max-age': + $response->setMaxAge($value); + break; + + case 's-maxage': + $response->setSharedMaxAge($value); + break; + + case 'private': + $response->setPrivate(); + break; + + case 'public': + $response->setPublic(); + break; + + default: + $response->headers->addCacheControlDirective($key, $value); + } + } + + return $response; + }; + + foreach ($surrogates as $config) { + $cacheStrategy->add($buildResponse($config)); + } + + $response = $buildResponse($master); + $cacheStrategy->update($response); + + foreach ($expects as $key => $value) { + if (true === $value) { + $this->assertTrue($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must have "%s" flag', $key)); + } elseif (false === $value) { + $this->assertFalse($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must NOT have "%s" flag', $key)); + } else { + $this->assertEquals($value, $response->headers->getCacheControlDirective($key), sprintf('Cache-Control flag "%s" should be "%s"', $key, $value)); + } + } + } + + public function cacheControlMergingProvider() + { + yield 'result is public if all responses are public' => array( + array('private' => false, 'public' => true), + array('public' => true), + array( + array('public' => true), + ), + ); + + yield 'result is private by default' => array( + array('private' => true, 'public' => false), + array('public' => true), + array( + array(), + ), + ); + + yield 'combines public and private responses' => array( + array('must-revalidate' => false, 'private' => true, 'public' => false), + array('public' => true), + array( + array('private' => true), + ), + ); + + yield 'inherits no-cache from surrogates' => array( + array('no-cache' => true, 'public' => false), + array('public' => true), + array( + array('no-cache' => true), + ), + ); + + yield 'inherits no-store from surrogate' => array( + array('no-store' => true, 'public' => false), + array('public' => true), + array( + array('no-store' => true), + ), + ); + + yield 'resolve to lowest possible max-age' => array( + array('public' => false, 'private' => true, 's-maxage' => false, 'max-age' => 60), + array('public' => true, 'max-age' => 3600), + array( + array('private' => true, 'max-age' => 60), + ), + ); + + yield 'resolves multiple max-age' => array( + array('public' => false, 'private' => true, 's-maxage' => false, 'max-age' => 60), + array('private' => true, 'max-age' => 100), + array( + array('private' => true, 'max-age' => 3600), + array('public' => true, 'max-age' => 60, 's-maxage' => 60), + array('private' => true, 'max-age' => 60), + ), + ); + + yield 'merge max-age and s-maxage' => array( + array('public' => true, 's-maxage' => 60, 'max-age' => null), + array('public' => true, 's-maxage' => 3600), + array( + array('public' => true, 'max-age' => 60), + ), + ); + + yield 'result is private when combining private responses' => array( + array('no-cache' => false, 'must-revalidate' => false, 'private' => true), + array('s-maxage' => 60, 'private' => true), + array( + array('s-maxage' => 60, 'private' => true), + ), + ); + + yield 'result can have s-maxage and max-age' => array( + array('public' => true, 'private' => false, 's-maxage' => 60, 'max-age' => 30), + array('s-maxage' => 100, 'max-age' => 2000), + array( + array('s-maxage' => 1000, 'max-age' => 30), + array('s-maxage' => 500, 'max-age' => 500), + array('s-maxage' => 60, 'max-age' => 1000), + ), + ); + } }