testPreInvalidateCalled()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 16
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 21
ccs 16
cts 16
cp 1
crap 1
rs 9.7333
1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCache package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.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
12
namespace FOS\HttpCache\Test;
13
14
use FOS\HttpCache\SymfonyCache\CacheEvent;
15
use FOS\HttpCache\SymfonyCache\CacheInvalidation;
16
use FOS\HttpCache\SymfonyCache\EventDispatchingHttpCache;
17
use FOS\HttpCache\SymfonyCache\Events;
18
use PHPUnit\Framework\MockObject\MockObject;
0 ignored issues
show
Bug introduced by
The type PHPUnit\Framework\MockObject\MockObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use PHPUnit\Framework\TestCase;
0 ignored issues
show
Bug introduced by
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
24
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
25
use Symfony\Component\HttpKernel\HttpKernelInterface;
26
27
/**
28
 * This test ensures that the EventDispatchingHttpCache trait is correctly used.
29
 */
30
abstract class EventDispatchingHttpCacheTestCase extends TestCase
31
{
32
    /**
33
     * Specify the CacheInvalidationInterface HttpCache class to test.
34
     *
35
     * @return string Fully qualified class name of the AppCache
36
     */
37
    abstract protected function getCacheClass();
38
39
    /**
40
     * Create a partial mock of the HttpCache to only test some methods.
41
     *
42
     * @param array $mockedMethods List of methods to mock
43
     *
44
     * @return CacheInvalidation|EventDispatchingHttpCache|MockObject
45
     */
46 9
    protected function getHttpCachePartialMock(array $mockedMethods = null)
47
    {
48
        $mock = $this
49 9
            ->getMockBuilder($this->getCacheClass())
50 9
            ->setMethods($mockedMethods)
51 9
            ->disableOriginalConstructor()
52 9
            ->getMock()
53
        ;
54
55 9
        $this->assertInstanceOf(CacheInvalidation::class, $mock);
56
57
        // Force setting options property since we can't use original constructor.
58
        $options = [
59 9
            'debug' => false,
60
            'default_ttl' => 0,
61
            'private_headers' => ['Authorization', 'Cookie'],
62
            'allow_reload' => false,
63
            'allow_revalidate' => false,
64
            'stale_while_revalidate' => 2,
65
            'stale_if_error' => 60,
66
            'trace_level' => 'full',
67
            'trace_header' => 'FOSHttpCache',
68
        ];
69
70 9
        $refHttpCache = new \ReflectionClass(HttpCache::class);
71 9
        $refOptions = $refHttpCache->getProperty('options');
72 9
        $refOptions->setAccessible(true);
73 9
        $refOptions->setValue($mock, $options);
74
75 9
        $surrogate = $refHttpCache->getProperty('surrogate');
76 9
        $surrogate->setAccessible(true);
77 9
        $surrogate->setValue($mock, null);
78
79 9
        return $mock;
80
    }
81
82
    /**
83
     * Set the store property on a HttpCache to a StoreInterface expecting one write with request and response.
84
     */
85 2
    protected function setStoreMock(CacheInvalidation $httpCache, Request $request, Response $response)
86
    {
87 2
        $store = $this->createMock(StoreInterface::class);
88
        $store
89 2
            ->expects($this->once())
90 2
            ->method('write')
91 2
            ->with($request, $response)
92
        ;
93 2
        $refHttpCache = new \ReflectionClass(HttpCache::class);
94 2
        $refStore = $refHttpCache->getProperty('store');
95 2
        $refStore->setAccessible(true);
96 2
        $refStore->setValue($httpCache, $store);
97 2
    }
98
99
    /**
100
     * Assert that preHandle and postHandle are called.
101
     */
102 1
    public function testHandleCalled()
103
    {
104 1
        $catch = true;
105 1
        $request = Request::create('/foo', 'GET');
106 1
        $response = new Response();
107
108 1
        $httpCache = $this->getHttpCachePartialMock(['lookup']);
109 1
        $testListener = new TestListener($this, $httpCache, $request);
110 1
        $httpCache->addSubscriber($testListener);
111
        $httpCache
112 1
            ->expects($this->any())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on FOS\HttpCache\SymfonyCache\CacheInvalidation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
            ->/** @scrutinizer ignore-call */ 
113
              expects($this->any())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
It seems like expects() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
            ->/** @scrutinizer ignore-call */ 
113
              expects($this->any())
Loading history...
113 1
            ->method('lookup')
114 1
            ->with($request)
115 1
            ->will($this->returnValue($response))
116
        ;
117
118 1
        $this->assertSame($response, $httpCache->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch));
0 ignored issues
show
Deprecated Code introduced by
The constant Symfony\Component\HttpKe...terface::MASTER_REQUEST has been deprecated: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won't be removed until Symfony 7.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

118
        $this->assertSame($response, $httpCache->handle($request, /** @scrutinizer ignore-deprecated */ HttpKernelInterface::MASTER_REQUEST, $catch));

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
119 1
        $this->assertEquals(1, $testListener->preHandleCalls);
120 1
        $this->assertEquals(1, $testListener->postHandleCalls);
121 1
    }
122
123
    /**
124
     * Assert that when preHandle returns a response, that response is used and the normal kernel flow stopped.
125
     *
126
     * @depends testHandleCalled
127
     */
128 1
    public function testPreHandleReturnEarly()
129
    {
130 1
        $catch = true;
131 1
        $request = Request::create('/foo', 'GET');
132 1
        $response = new Response();
133
134 1
        $httpCache = $this->getHttpCachePartialMock(['lookup']);
135 1
        $testListener = new TestListener($this, $httpCache, $request);
136 1
        $testListener->preHandleResponse = $response;
137 1
        $httpCache->addSubscriber($testListener);
138
        $httpCache
139 1
            ->expects($this->never())
140 1
            ->method('lookup')
141
        ;
142
143 1
        $this->assertSame($response, $httpCache->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch));
0 ignored issues
show
Deprecated Code introduced by
The constant Symfony\Component\HttpKe...terface::MASTER_REQUEST has been deprecated: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won't be removed until Symfony 7.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

143
        $this->assertSame($response, $httpCache->handle($request, /** @scrutinizer ignore-deprecated */ HttpKernelInterface::MASTER_REQUEST, $catch));

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
144 1
        $this->assertEquals(1, $testListener->preHandleCalls);
145 1
        $this->assertEquals(1, $testListener->postHandleCalls);
146 1
    }
147
148
    /**
149
     * Assert that postHandle can update the response.
150
     *
151
     * @depends testHandleCalled
152
     */
153 1
    public function testPostHandleReturn()
154
    {
155 1
        $catch = true;
156 1
        $request = Request::create('/foo', 'GET');
157 1
        $regularResponse = new Response();
158 1
        $postResponse = new Response();
159
160 1
        $httpCache = $this->getHttpCachePartialMock(['lookup']);
161 1
        $testListener = new TestListener($this, $httpCache, $request);
162 1
        $testListener->postHandleResponse = $postResponse;
163 1
        $httpCache->addSubscriber($testListener);
164
        $httpCache
165 1
            ->expects($this->any())
166 1
            ->method('lookup')
167 1
            ->with($request)
168 1
            ->will($this->returnValue($regularResponse))
169
        ;
170
171 1
        $this->assertSame($postResponse, $httpCache->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch));
0 ignored issues
show
Deprecated Code introduced by
The constant Symfony\Component\HttpKe...terface::MASTER_REQUEST has been deprecated: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won't be removed until Symfony 7.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

171
        $this->assertSame($postResponse, $httpCache->handle($request, /** @scrutinizer ignore-deprecated */ HttpKernelInterface::MASTER_REQUEST, $catch));

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
172 1
        $this->assertEquals(1, $testListener->preHandleCalls);
173 1
        $this->assertEquals(1, $testListener->postHandleCalls);
174 1
    }
175
176
    /**
177
     * Assert that postHandle is called and the response can be updated even when preHandle returned a response.
178
     *
179
     * @depends testHandleCalled
180
     */
181 1
    public function testPostHandleAfterPreHandle()
182
    {
183 1
        $catch = true;
184 1
        $request = Request::create('/foo', 'GET');
185 1
        $preResponse = new Response();
186 1
        $postResponse = new Response();
187
188 1
        $httpCache = $this->getHttpCachePartialMock(['lookup']);
189 1
        $testListener = new TestListener($this, $httpCache, $request);
190 1
        $testListener->preHandleResponse = $preResponse;
191 1
        $testListener->postHandleResponse = $postResponse;
192 1
        $httpCache->addSubscriber($testListener);
193
        $httpCache
194 1
            ->expects($this->never())
195 1
            ->method('lookup')
196
        ;
197
198 1
        $this->assertSame($postResponse, $httpCache->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch));
0 ignored issues
show
Deprecated Code introduced by
The constant Symfony\Component\HttpKe...terface::MASTER_REQUEST has been deprecated: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won't be removed until Symfony 7.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

198
        $this->assertSame($postResponse, $httpCache->handle($request, /** @scrutinizer ignore-deprecated */ HttpKernelInterface::MASTER_REQUEST, $catch));

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
199 1
        $this->assertEquals(1, $testListener->preHandleCalls);
200 1
        $this->assertEquals(1, $testListener->postHandleCalls);
201 1
    }
202
203
    /**
204
     * Assert that preStore is called.
205
     */
206 1
    public function testPreStoreCalled()
207
    {
208 1
        $request = Request::create('/foo', 'GET');
209 1
        $response = new Response();
210
211 1
        $httpCache = $this->getHttpCachePartialMock();
212 1
        $testListener = new TestListener($this, $httpCache, $request);
213 1
        $httpCache->addSubscriber($testListener);
214
215 1
        $this->setStoreMock($httpCache, $request, $response);
216
217 1
        $refHttpCache = new \ReflectionObject($httpCache);
218 1
        $method = $refHttpCache->getMethod('store');
219 1
        $method->setAccessible(true);
220 1
        $method->invokeArgs($httpCache, [$request, $response]);
221 1
        $this->assertEquals(1, $testListener->preStoreCalls);
222 1
    }
223
224
    /**
225
     * Assert that preStore response is used when provided.
226
     */
227 1
    public function testPreStoreResponse()
228
    {
229 1
        $request = Request::create('/foo', 'GET');
230 1
        $regularResponse = new Response();
231 1
        $preStoreResponse = new Response();
232
233 1
        $httpCache = $this->getHttpCachePartialMock();
234 1
        $testListener = new TestListener($this, $httpCache, $request);
235 1
        $testListener->preStoreResponse = $preStoreResponse;
236 1
        $httpCache->addSubscriber($testListener);
237
238 1
        $this->setStoreMock($httpCache, $request, $preStoreResponse);
239
240 1
        $refHttpCache = new \ReflectionObject($httpCache);
241 1
        $method = $refHttpCache->getMethod('store');
242 1
        $method->setAccessible(true);
243 1
        $method->invokeArgs($httpCache, [$request, $regularResponse]);
244 1
        $this->assertEquals(1, $testListener->preStoreCalls);
245 1
    }
246
247
    /**
248
     * Assert that preInvalidate is called.
249
     */
250 1
    public function testPreInvalidateCalled()
251
    {
252 1
        $catch = true;
253 1
        $request = Request::create('/foo', 'GET');
254 1
        $response = new Response('', 500);
255
256 1
        $httpCache = $this->getHttpCachePartialMock(['pass']);
257 1
        $testListener = new TestListener($this, $httpCache, $request);
258 1
        $httpCache->addSubscriber($testListener);
259
        $httpCache
260 1
            ->expects($this->any())
261 1
            ->method('pass')
262 1
            ->with($request)
263 1
            ->will($this->returnValue($response))
264
        ;
265 1
        $refHttpCache = new \ReflectionObject($httpCache);
266 1
        $method = $refHttpCache->getMethod('invalidate');
267 1
        $method->setAccessible(true);
268
269 1
        $this->assertSame($response, $method->invokeArgs($httpCache, [$request, $catch]));
270 1
        $this->assertEquals(1, $testListener->preInvalidateCalls);
271 1
    }
272
273
    /**
274
     * Assert that when preInvalidate returns a response, that response is used and the normal kernel flow stopped.
275
     *
276
     * @depends testPreInvalidateCalled
277
     */
278 1
    public function testPreInvalidateReturnEarly()
279
    {
280 1
        $catch = true;
281 1
        $request = Request::create('/foo', 'GET');
282 1
        $response = new Response('', 400);
283
284 1
        $httpCache = $this->getHttpCachePartialMock(['pass']);
285 1
        $testListener = new TestListener($this, $httpCache, $request);
286 1
        $testListener->preInvalidateResponse = $response;
287 1
        $httpCache->addSubscriber($testListener);
288
        $httpCache
289 1
            ->expects($this->never())
290 1
            ->method('pass')
291
        ;
292 1
        $refHttpCache = new \ReflectionObject($httpCache);
293 1
        $method = $refHttpCache->getMethod('invalidate');
294 1
        $method->setAccessible(true);
295
296 1
        $this->assertSame($response, $method->invokeArgs($httpCache, [$request, $catch]));
297 1
        $this->assertEquals(1, $testListener->preInvalidateCalls);
298 1
    }
299
300 1
    public function testAddListener()
301
    {
302 1
        $request = Request::create('/foo', 'GET');
303 1
        $response = new Response();
304
305 1
        $httpCache = $this->getHttpCachePartialMock(['lookup']);
306 1
        $simpleListener = new SimpleListener($this, $httpCache, $request);
307 1
        $httpCache->addListener(Events::PRE_HANDLE, [$simpleListener, 'callback']);
308
309
        $httpCache
310 1
            ->expects($this->any())
311 1
            ->method('lookup')
312 1
            ->with($request)
313 1
            ->will($this->returnValue($response))
314
        ;
315
316 1
        $this->assertSame($response, $httpCache->handle($request, HttpKernelInterface::MASTER_REQUEST));
0 ignored issues
show
Deprecated Code introduced by
The constant Symfony\Component\HttpKe...terface::MASTER_REQUEST has been deprecated: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won't be removed until Symfony 7.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

316
        $this->assertSame($response, $httpCache->handle($request, /** @scrutinizer ignore-deprecated */ HttpKernelInterface::MASTER_REQUEST));

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
317 1
        $this->assertEquals(1, $simpleListener->calls);
318 1
    }
319
}
320
321
class TestListener implements EventSubscriberInterface
322
{
323
    /**
324
     * @var int Count how many times preHandle has been called
325
     */
326
    public $preHandleCalls = 0;
327
328
    /**
329
     * @var int Count how many times postHandle has been called
330
     */
331
    public $postHandleCalls = 0;
332
333
    /**
334
     * @var int Count how many times preStore has been called
335
     */
336
    public $preStoreCalls = 0;
337
338
    /**
339
     * @var int Count how many times preInvalidate has been called
340
     */
341
    public $preInvalidateCalls = 0;
342
343
    /**
344
     * @var Response A response to set during the preHandle
345
     */
346
    public $preHandleResponse;
347
348
    /**
349
     * @var Response A response to set during the postHandle
350
     */
351
    public $postHandleResponse;
352
353
    /**
354
     * @var Response A response to set during the preStore
355
     */
356
    public $preStoreResponse;
357
358
    /**
359
     * @var Response A response to set during the preInvalidate
360
     */
361
    public $preInvalidateResponse;
362
363
    /**
364
     * @var EventDispatchingHttpCacheTestCase To do assertions
365
     */
366
    private $test;
367
368
    /**
369
     * @var CacheInvalidation The kernel to ensure the event carries the correct kernel
370
     */
371
    private $kernel;
372
373
    /**
374
     * @var Request The request to ensure the event carries the correct request
375
     */
376
    private $request;
377
378 8
    public function __construct(
379
        EventDispatchingHttpCacheTestCase $test,
380
        CacheInvalidation $kernel,
381
        Request $request
382
    ) {
383 8
        $this->test = $test;
384 8
        $this->kernel = $kernel;
385 8
        $this->request = $request;
386 8
    }
387
388 8
    public static function getSubscribedEvents(): array
389
    {
390
        return [
391 8
            Events::PRE_HANDLE => 'preHandle',
392 8
            Events::POST_HANDLE => 'postHandle',
393 8
            Events::PRE_STORE => 'preStore',
394 8
            Events::PRE_INVALIDATE => 'preInvalidate',
395
        ];
396
    }
397
398 4
    public function preHandle(CacheEvent $event)
399
    {
400 4
        $this->test->assertSame($this->kernel, $event->getKernel());
401 4
        $this->test->assertSame($this->request, $event->getRequest());
402 4
        if ($this->preHandleResponse) {
403 2
            $event->setResponse($this->preHandleResponse);
404
        }
405 4
        ++$this->preHandleCalls;
406 4
    }
407
408 4
    public function postHandle(CacheEvent $event)
409
    {
410 4
        $this->test->assertSame($this->kernel, $event->getKernel());
411 4
        $this->test->assertSame($this->request, $event->getRequest());
412 4
        if ($this->postHandleResponse) {
413 2
            $event->setResponse($this->postHandleResponse);
414
        }
415 4
        ++$this->postHandleCalls;
416 4
    }
417
418 2
    public function preStore(CacheEvent $event)
419
    {
420 2
        $this->test->assertSame($this->kernel, $event->getKernel());
421 2
        $this->test->assertSame($this->request, $event->getRequest());
422 2
        if ($this->preStoreResponse) {
423 1
            $event->setResponse($this->preStoreResponse);
424
        }
425 2
        ++$this->preStoreCalls;
426 2
    }
427
428 2
    public function preInvalidate(CacheEvent $event)
429
    {
430 2
        $this->test->assertSame($this->kernel, $event->getKernel());
431 2
        $this->test->assertSame($this->request, $event->getRequest());
432 2
        if ($this->preInvalidateResponse) {
433 1
            $event->setResponse($this->preInvalidateResponse);
434
        }
435 2
        ++$this->preInvalidateCalls;
436 2
    }
437
}
438
439
class SimpleListener
440
{
441
    public $calls = 0;
442
443
    /**
444
     * @var EventDispatchingHttpCacheTestCase To do assertions
445
     */
446
    private $test;
447
448
    /**
449
     * @var CacheInvalidation The kernel to ensure the event carries the correct kernel
450
     */
451
    private $kernel;
452
453
    /**
454
     * @var Request The request to ensure the event carries the correct request
455
     */
456
    private $request;
457
458 1
    public function __construct(
459
        EventDispatchingHttpCacheTestCase $test,
460
        CacheInvalidation $kernel,
461
        Request $request
462
    ) {
463 1
        $this->test = $test;
464 1
        $this->kernel = $kernel;
465 1
        $this->request = $request;
466 1
    }
467
468 1
    public function callback(CacheEvent $event)
469
    {
470 1
        $this->test->assertSame($this->kernel, $event->getKernel());
471 1
        $this->test->assertSame($this->request, $event->getRequest());
472 1
        ++$this->calls;
473 1
    }
474
}
475