Completed
Push — sf_cache ( b9ead9...8c890f )
by André
18:16
created

HandlerTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
dl 0
loc 234
rs 10
c 0
b 0
f 0
wmc 10
lcom 1
cbo 13

10 Methods

Rating   Name   Duplication   Size   Complexity  
B setUp() 0 38 1
A tearDown() 0 9 1
getHandlerMethodName() 0 1 ?
getHandlerClassName() 0 1 ?
providerForUnCachedMethods() 0 1 ?
B testUnCachedMethods() 0 37 5
providerForCachedLoadMethods() 0 1 ?
A testLoadMethodsCacheHit() 0 20 1
B testLoadMethodsCacheMiss() 0 34 1
A getCacheItem() 0 5 1
1
<?php
2
3
/**
4
 * File contains Test class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Cache\Tests;
10
11
use eZ\Publish\Core\Persistence\Cache\Handler as CacheHandler;
12
use eZ\Publish\Core\Persistence\Cache\SectionHandler as CacheSectionHandler;
13
use eZ\Publish\Core\Persistence\Cache\LocationHandler as CacheLocationHandler;
14
use eZ\Publish\Core\Persistence\Cache\ContentHandler as CacheContentHandler;
15
use eZ\Publish\Core\Persistence\Cache\ContentLanguageHandler as CacheContentLanguageHandler;
16
use eZ\Publish\Core\Persistence\Cache\ContentTypeHandler as CacheContentTypeHandler;
17
use eZ\Publish\Core\Persistence\Cache\UserHandler as CacheUserHandler;
18
use eZ\Publish\Core\Persistence\Cache\TransactionHandler as CacheTransactionHandler;
19
use eZ\Publish\Core\Persistence\Cache\TrashHandler as CacheTrashHandler;
20
use eZ\Publish\Core\Persistence\Cache\UrlAliasHandler as CacheUrlAliasHandler;
21
use eZ\Publish\Core\Persistence\Cache\ObjectStateHandler as CacheObjectStateHandler;
22
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
23
use Symfony\Component\Cache\CacheItem;
24
use PHPUnit_Framework_TestCase;
25
26
/**
27
 * Abstract test case for spi cache impl.
28
 */
29
abstract class HandlerTest extends PHPUnit_Framework_TestCase
30
{
31
    /**
32
     * @var \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
33
     */
34
    protected $cacheMock;
35
36
    /**
37
     * @var \eZ\Publish\SPI\Persistence\Handler|\PHPUnit_Framework_MockObject_MockObject
38
     */
39
    protected $persistenceHandlerMock;
40
41
    /**
42
     * @var \eZ\Publish\SPI\Persistence\TransactionHandler|\PHPUnit_Framework_MockObject_MockObject
43
     */
44
    protected $transactionHandlerMock;
45
46
    /**
47
     * @var \eZ\Publish\Core\Persistence\Cache\Handler
48
     */
49
    protected $persistenceCacheHandler;
50
51
    /**
52
     * @var \eZ\Publish\Core\Persistence\Cache\PersistenceLogger|\PHPUnit_Framework_MockObject_MockObject
53
     */
54
    protected $loggerMock;
55
56
    /**
57
     * @param array|null $persistenceFactoryMockMethod
58
     */
59
    protected $persistenceFactoryMockMethods = array();
60
61
    /**
62
     * @var \Closure
63
     */
64
    protected $cacheItemsClosure;
65
66
    /**
67
     * Setup the HandlerTest.
68
     */
69
    final protected function setUp()
70
    {
71
        parent::setUp();
72
73
        $this->persistenceHandlerMock = $this->getMock('eZ\Publish\SPI\Persistence\Handler');
74
        $this->cacheMock = $this->getMock(TagAwareAdapterInterface::class);
75
        $this->loggerMock = $this->getMock('eZ\\Publish\\Core\\Persistence\\Cache\\PersistenceLogger');
76
77
        $this->persistenceCacheHandler = new CacheHandler(
78
            $this->persistenceHandlerMock,
79
            new CacheSectionHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
80
            new CacheLocationHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
81
            new CacheContentHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
82
            new CacheContentLanguageHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
83
            new CacheContentTypeHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
84
            new CacheUserHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
85
            new CacheTransactionHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
86
            new CacheTrashHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
87
            new CacheUrlAliasHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
88
            new CacheObjectStateHandler($this->cacheMock, $this->persistenceHandlerMock, $this->loggerMock),
89
            $this->loggerMock,
90
            $this->cacheMock
91
        );
92
93
        $this->cacheItemsClosure = \Closure::bind(
94
            function ($key, $value, $isHit, $defaultLifetime = 0) {
95
                $item = new CacheItem();
96
                $item->key = $key;
0 ignored issues
show
Bug introduced by
The property key cannot be accessed from this context as it is declared protected in class Symfony\Component\Cache\CacheItem.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
97
                $item->value = $value;
0 ignored issues
show
Bug introduced by
The property value cannot be accessed from this context as it is declared protected in class Symfony\Component\Cache\CacheItem.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
98
                $item->isHit = $isHit;
0 ignored issues
show
Bug introduced by
The property isHit cannot be accessed from this context as it is declared protected in class Symfony\Component\Cache\CacheItem.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
99
                $item->defaultLifetime = $defaultLifetime;
0 ignored issues
show
Bug introduced by
The property defaultLifetime cannot be accessed from this context as it is declared protected in class Symfony\Component\Cache\CacheItem.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
100
101
                return $item;
102
            },
103
            null,
104
            CacheItem::class
105
        );
106
    }
107
108
    /**
109
     * Tear down test (properties).
110
     */
111
    final protected function tearDown()
112
    {
113
        unset($this->cacheMock);
114
        unset($this->persistenceHandlerMock);
115
        unset($this->persistenceCacheHandler);
116
        unset($this->loggerMock);
117
        unset($this->cacheItemsClosure);
118
        parent::tearDown();
119
    }
120
121
122
    abstract public function getHandlerMethodName() : string;
123
124
    abstract public function getHandlerClassName() : string;
125
126
    abstract public function providerForUnCachedMethods() : array;
127
128
    /**
129
     * @dataProvider providerForUnCachedMethods
130
     *
131
     * @param string $method
132
     * @param array $arguments
133
     * @param array|null $tags
134
     * @param string|null $key
135
     */
136
    final public function testUnCachedMethods(string $method, array $arguments, array $tags = null, string $key = null)
137
    {
138
        $handlerMethodName = $this->getHandlerMethodName();
139
140
        $this->loggerMock->expects($this->once())->method('logCall');
141
142
        $innerHandler = $this->getMock($this->getHandlerClassName());
143
        $this->persistenceHandlerMock
144
            ->expects($this->once())
145
            ->method($handlerMethodName)
146
            ->will($this->returnValue($innerHandler));
147
148
        $innerHandler
149
            ->expects($this->once())
150
            ->method($method)
151
            ->with(...$arguments)
152
            ->will($this->returnValue(null));
153
154
        if ($tags || $key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
155
            $this->cacheMock
156
                ->expects(!empty($tags) ? $this->once() : $this->never())
157
                ->method('invalidateTags')
158
                ->with($tags);
159
160
            $this->cacheMock
161
                ->expects(!empty($key) ? $this->once() : $this->never())
162
                ->method('deleteItem')
163
                ->with($key);
164
        } else {
165
            $this->cacheMock
166
                ->expects($this->never())
167
                ->method($this->anything());
168
        }
169
170
        $handler = $this->persistenceCacheHandler->$handlerMethodName();
171
        call_user_func_array(array($handler, $method), $arguments);
172
    }
173
174
175
    abstract public function providerForCachedLoadMethods() : array;
176
177
    /**
178
     * @dataProvider providerForCachedLoadMethods
179
     *
180
     * @param string $method
181
     * @param array $arguments
182
     * @param string $key
183
     * @param mixed $data
184
     */
185
    final public function testLoadMethodsCacheHit(string $method, array $arguments, string $key, $data = null)
186
    {
187
        $cacheItem = $this->getCacheItem($key, $data);
188
        $handlerMethodName = $this->getHandlerMethodName();
189
190
        $this->loggerMock->expects($this->never())->method('logCall');
191
192
        $this->cacheMock
193
            ->expects($this->once())
194
            ->method('getItem')
195
            ->with($cacheItem->getKey())
196
            ->will($this->returnValue($cacheItem));
197
198
        $this->persistenceHandlerMock
199
            ->expects($this->never())
200
            ->method($handlerMethodName);
201
202
        $handler = $this->persistenceCacheHandler->$handlerMethodName();
203
        call_user_func_array([$handler, $method], $arguments);
204
    }
205
206
    /**
207
     * @dataProvider providerForCachedLoadMethods
208
     *
209
     * @param string $method
210
     * @param array $arguments
211
     * @param string $key
212
     * @param object $data
213
     */
214
    final public function testLoadMethodsCacheMiss(string $method, array $arguments, string $key, $data = null)
215
    {
216
        $cacheItem = $this->getCacheItem($key, null);
217
        $handlerMethodName = $this->getHandlerMethodName();
218
219
        $this->loggerMock->expects($this->once())->method('logCall');
220
221
        $this->cacheMock
222
            ->expects($this->once())
223
            ->method('getItem')
224
            ->with($cacheItem->getKey())
225
            ->will($this->returnValue($cacheItem));
226
227
        $innerHandlerMock = $this->getMock($this->getHandlerClassName());
228
        $this->persistenceHandlerMock
229
            ->expects($this->once())
230
            ->method($handlerMethodName)
231
            ->will($this->returnValue($innerHandlerMock));
232
233
        $innerHandlerMock
234
            ->expects($this->once())
235
            ->method($method)
236
            ->with(...$arguments)
237
            ->will($this->returnValue($data));
238
239
        // @todo find way to also verify tags on the cache item
240
        $this->cacheMock
241
            ->expects($this->once())
242
            ->method('save')
243
            ->with($cacheItem);
244
245
        $handler = $this->persistenceCacheHandler->$handlerMethodName();
246
        call_user_func_array([$handler, $method], $arguments);
247
    }
248
249
250
    /**
251
     * @param $key
252
     * @param null $value If null the cache item will be assumed to be a cache miss here.
253
     * @param int $defaultLifetime
254
     *
255
     * @return CacheItem
256
     */
257
    final protected function getCacheItem($key, $value = null, $defaultLifetime = 0)
258
    {
259
        $cacheItemsClosure = $this->cacheItemsClosure;
260
        return $cacheItemsClosure($key, $value, !!$value, $defaultLifetime);
261
    }
262
}
263