1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\HttpKernel\Tests\HttpCache;
13
14use PHPUnit\Framework\TestCase;
15use Symfony\Component\HttpFoundation\Request;
16use Symfony\Component\HttpKernel\HttpCache\Esi;
17use Symfony\Component\HttpKernel\HttpCache\HttpCache;
18use Symfony\Component\HttpKernel\HttpCache\Store;
19use Symfony\Component\HttpKernel\HttpKernelInterface;
20
21class HttpCacheTestCase extends TestCase
22{
23    protected $kernel;
24    protected $cache;
25    protected $caches;
26    protected $cacheConfig;
27    protected $request;
28    protected $response;
29    protected $responses;
30    protected $catch;
31    protected $esi;
32
33    /**
34     * @var Store
35     */
36    protected $store;
37
38    protected function setUp()
39    {
40        $this->kernel = null;
41
42        $this->cache = null;
43        $this->esi = null;
44        $this->caches = [];
45        $this->cacheConfig = [];
46
47        $this->request = null;
48        $this->response = null;
49        $this->responses = [];
50
51        $this->catch = false;
52
53        $this->clearDirectory(sys_get_temp_dir().'/http_cache');
54    }
55
56    protected function tearDown()
57    {
58        if ($this->cache) {
59            $this->cache->getStore()->cleanup();
60        }
61        $this->kernel = null;
62        $this->cache = null;
63        $this->caches = null;
64        $this->request = null;
65        $this->response = null;
66        $this->responses = null;
67        $this->cacheConfig = null;
68        $this->catch = null;
69        $this->esi = null;
70
71        $this->clearDirectory(sys_get_temp_dir().'/http_cache');
72    }
73
74    public function assertHttpKernelIsCalled()
75    {
76        $this->assertTrue($this->kernel->hasBeenCalled());
77    }
78
79    public function assertHttpKernelIsNotCalled()
80    {
81        $this->assertFalse($this->kernel->hasBeenCalled());
82    }
83
84    public function assertResponseOk()
85    {
86        $this->assertEquals(200, $this->response->getStatusCode());
87    }
88
89    public function assertTraceContains($trace)
90    {
91        $traces = $this->cache->getTraces();
92        $traces = current($traces);
93
94        $this->assertMatchesRegularExpression('/'.$trace.'/', implode(', ', $traces));
95    }
96
97    public function assertTraceNotContains($trace)
98    {
99        $traces = $this->cache->getTraces();
100        $traces = current($traces);
101
102        $this->assertDoesNotMatchRegularExpression('/'.$trace.'/', implode(', ', $traces));
103    }
104
105    public function assertExceptionsAreCaught()
106    {
107        $this->assertTrue($this->kernel->isCatchingExceptions());
108    }
109
110    public function assertExceptionsAreNotCaught()
111    {
112        $this->assertFalse($this->kernel->isCatchingExceptions());
113    }
114
115    public function request($method, $uri = '/', $server = [], $cookies = [], $esi = false, $headers = [])
116    {
117        if (null === $this->kernel) {
118            throw new \LogicException('You must call setNextResponse() before calling request().');
119        }
120
121        $this->kernel->reset();
122
123        $this->store = new Store(sys_get_temp_dir().'/http_cache');
124
125        $this->cacheConfig['debug'] = true;
126
127        $this->esi = $esi ? new Esi() : null;
128        $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig);
129        $this->request = Request::create($uri, $method, [], $cookies, [], $server);
130        $this->request->headers->add($headers);
131
132        $this->response = $this->cache->handle($this->request, HttpKernelInterface::MASTER_REQUEST, $this->catch);
133
134        $this->responses[] = $this->response;
135    }
136
137    public function getMetaStorageValues()
138    {
139        $values = [];
140        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(sys_get_temp_dir().'/http_cache/md', \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
141            $values[] = file_get_contents($file);
142        }
143
144        return $values;
145    }
146
147    // A basic response with 200 status code and a tiny body.
148    public function setNextResponse($statusCode = 200, array $headers = [], $body = 'Hello World', \Closure $customizer = null)
149    {
150        $this->kernel = new TestHttpKernel($body, $statusCode, $headers, $customizer);
151    }
152
153    public function setNextResponses($responses)
154    {
155        $this->kernel = new TestMultipleHttpKernel($responses);
156    }
157
158    public function catchExceptions($catch = true)
159    {
160        $this->catch = $catch;
161    }
162
163    public static function clearDirectory($directory)
164    {
165        if (!is_dir($directory)) {
166            return;
167        }
168
169        $fp = opendir($directory);
170        while (false !== $file = readdir($fp)) {
171            if (!\in_array($file, ['.', '..'])) {
172                if (is_link($directory.'/'.$file)) {
173                    unlink($directory.'/'.$file);
174                } elseif (is_dir($directory.'/'.$file)) {
175                    self::clearDirectory($directory.'/'.$file);
176                    rmdir($directory.'/'.$file);
177                } else {
178                    unlink($directory.'/'.$file);
179                }
180            }
181        }
182
183        closedir($fp);
184    }
185}
186