Completed
Push — master ( c5ac33...914d12 )
by Siad
13:46 queued 07:42
created

CommonAdapterTest::testClearByNamespace()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 33
rs 8.8571
cc 2
eloc 22
nc 2
nop 0
1
<?php
2
/**
3
 * Zend Framework (http://framework.zend.com/)
4
 *
5
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6
 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7
 * @license   http://framework.zend.com/license/new-bsd New BSD License
8
 */
9
10
namespace MehrAlsNix\Test\ZF\Cache\Storage\Adapter;
11
12
use Zend\Cache\Storage\AvailableSpaceCapableInterface;
13
use Zend\Cache\Storage\IterableInterface;
14
use Zend\Cache\Storage\IteratorInterface;
15
use Zend\Cache\Storage\StorageInterface;
16
use Zend\Cache\Storage\ClearExpiredInterface;
17
use Zend\Cache\Storage\ClearByNamespaceInterface;
18
use Zend\Cache\Storage\ClearByPrefixInterface;
19
use Zend\Cache\Storage\FlushableInterface;
20
use Zend\Cache\Storage\OptimizableInterface;
21
use Zend\Cache\Storage\TaggableInterface;
22
use Zend\Cache\Storage\TotalSpaceCapableInterface;
23
use Zend\Stdlib\ErrorHandler;
24
25
/**
26
 * PHPUnit test case
27
 */
28
29
/**
30
 * @group      Zend_Cache
31
 */
32
abstract class CommonAdapterTest extends \PHPUnit_Framework_TestCase
33
{
34
    /**
35
     * @var \Zend\Cache\Storage\Adapter\AdapterOptions
36
     */
37
    protected $_options;
38
39
    /**
40
     * The storage adapter
41
     *
42
     * @var StorageInterface
43
     */
44
    protected $_storage;
45
46
    /**
47
     * All datatypes of PHP
48
     *
49
     * @var string[]
50
     */
51
    protected $_phpDatatypes = [
52
        'NULL', 'boolean', 'integer', 'double',
53
        'string', 'array', 'object', 'resource'
54
    ];
55
56
    public function setUp()
57
    {
58
        $this->assertInstanceOf(
59
            'Zend\Cache\Storage\StorageInterface',
60
            $this->_storage,
61
            'Storage adapter instance is needed for tests'
62
        );
63
        $this->assertInstanceOf(
64
            'Zend\Cache\Storage\Adapter\AdapterOptions',
65
            $this->_options,
66
            'Options instance is needed for tests'
67
        );
68
    }
69
70
    public function _tearDown()
71
    {
72
        // be sure the error handler has been stopped
73
        if (ErrorHandler::started()) {
74
            ErrorHandler::stop();
75
            $this->fail('ErrorHandler not stopped');
76
        }
77
    }
78
79
    public function testOptionNamesValid()
80
    {
81
        $options = $this->_storage->getOptions()->toArray();
82
        foreach ($options as $name => $value) {
83
            $this->assertRegExp(
84
                '/^[a-z]+[a-z0-9_]*[a-z0-9]+$/',
85
                $name,
86
                "Invalid option name '{$name}'"
87
            );
88
        }
89
    }
90
91
    public function testGettersAndSettersOfOptionsExists()
92
    {
93
        $options = $this->_storage->getOptions();
94
        foreach ($options->toArray() as $option => $value) {
95
            if ($option == 'adapter') {
96
                // Skip this, as it's a "special" value
97
                continue;
98
            }
99
            $method = ucwords(str_replace('_', ' ', $option));
100
            $method = str_replace(' ', '', $method);
101
102
            $this->assertTrue(
103
                method_exists($options, 'set' . $method),
104
                "Missing method 'set'{$method}"
105
            );
106
107
            $this->assertTrue(
108
                method_exists($options, 'get' . $method),
109
                "Missing method 'get'{$method}"
110
            );
111
        }
112
    }
113
114
    public function testOptionsGetAndSetDefault()
115
    {
116
        $options = $this->_storage->getOptions();
117
        $this->_storage->setOptions($options);
118
        $this->assertSame($options, $this->_storage->getOptions());
119
    }
120
121
    public function testOptionsFluentInterface()
122
    {
123
        $options = $this->_storage->getOptions();
124
        foreach ($options->toArray() as $option => $value) {
125
            $method = ucwords(str_replace('_', ' ', $option));
126
            $method = 'set' . str_replace(' ', '', $method);
127
            $this->assertSame(
128
                $options,
129
                $options->{$method}($value),
130
                "Method '{$method}' doesn't implement the fluent interface"
131
            );
132
        }
133
134
        $this->assertSame(
135
            $this->_storage,
136
            $this->_storage->setOptions($options),
137
            "Method 'setOptions' doesn't implement the fluent interface"
138
        );
139
    }
140
141
    public function testGetCapabilities()
142
    {
143
        $capabilities = $this->_storage->getCapabilities();
144
        $this->assertInstanceOf('Zend\Cache\Storage\Capabilities', $capabilities);
145
    }
146
147
    public function testDatatypesCapability()
148
    {
149
        $capabilities = $this->_storage->getCapabilities();
150
        $datatypes = $capabilities->getSupportedDatatypes();
151
        $this->assertInternalType('array', $datatypes);
152
153
        foreach ($datatypes as $sourceType => $targetType) {
154
            $this->assertContains(
155
                $sourceType, $this->_phpDatatypes,
156
                "Unknown source type '{$sourceType}'"
157
            );
158
            if (is_string($targetType)) {
159
                $this->assertContains(
160
                    $targetType, $this->_phpDatatypes,
161
                    "Unknown target type '{$targetType}'"
162
                );
163
            } else {
164
                $this->assertInternalType(
165
                    'bool', $targetType,
166
                    "Target type must be a string or boolean"
167
                );
168
            }
169
        }
170
    }
171
172
    public function testSupportedMetadataCapability()
173
    {
174
        $capabilities = $this->_storage->getCapabilities();
175
        $metadata = $capabilities->getSupportedMetadata();
176
        $this->assertInternalType('array', $metadata);
177
178
        foreach ($metadata as $property) {
179
            $this->assertInternalType('string', $property);
180
        }
181
    }
182
183
    public function testTtlCapabilities()
184
    {
185
        $capabilities = $this->_storage->getCapabilities();
186
187
        $this->assertInternalType('integer', $capabilities->getMaxTtl());
188
        $this->assertGreaterThanOrEqual(0, $capabilities->getMaxTtl());
189
190
        $this->assertInternalType('bool', $capabilities->getStaticTtl());
191
192
        $this->assertInternalType('numeric', $capabilities->getTtlPrecision());
193
        $this->assertGreaterThan(0, $capabilities->getTtlPrecision());
194
195
        $this->assertInternalType('bool', $capabilities->getExpiredRead());
196
    }
197
198
    public function testKeyCapabilities()
199
    {
200
        $capabilities = $this->_storage->getCapabilities();
201
202
        $this->assertInternalType('integer', $capabilities->getMaxKeyLength());
203
        $this->assertGreaterThanOrEqual(-1, $capabilities->getMaxKeyLength());
204
205
        $this->assertInternalType('bool', $capabilities->getNamespaceIsPrefix());
206
207
        $this->assertInternalType('string', $capabilities->getNamespaceSeparator());
208
    }
209
210
    public function testHasItemReturnsTrueOnValidItem()
211
    {
212
        $this->assertTrue($this->_storage->setItem('key', 'value'));
213
        $this->assertTrue($this->_storage->hasItem('key'));
214
    }
215
216
    public function testHasItemReturnsFalseOnMissingItem()
217
    {
218
        $this->assertFalse($this->_storage->hasItem('key'));
219
    }
220
221
    public function testHasItemReturnsFalseOnExpiredItem()
222
    {
223
        $capabilities = $this->_storage->getCapabilities();
224
225
        if ($capabilities->getMinTtl() === 0) {
226
            $this->markTestSkipped("Adapter doesn't support item expiration");
227
        }
228
229
        $ttl = $capabilities->getTtlPrecision();
230
        $this->_options->setTtl($ttl);
231
232
        $this->waitForFullSecond();
233
234
        $this->assertTrue($this->_storage->setItem('key', 'value'));
235
236
        // wait until the item expired
237
        $wait = $ttl + $capabilities->getTtlPrecision();
238
        usleep($wait * 2000000);
239
240
        if (!$capabilities->getUseRequestTime()) {
241
            $this->assertFalse($this->_storage->hasItem('key'));
242
        } else {
243
            $this->assertTrue($this->_storage->hasItem('key'));
244
        }
245
    }
246
247
    public function testHasItemNonReadable()
248
    {
249
        $this->assertTrue($this->_storage->setItem('key', 'value'));
250
251
        $this->_options->setReadable(false);
252
        $this->assertFalse($this->_storage->hasItem('key'));
253
    }
254
255
    public function testHasItemsReturnsKeysOfFoundItems()
256
    {
257
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
258
        $this->assertTrue($this->_storage->setItem('key2', 'value2'));
259
260
        $result = $this->_storage->hasItems(['missing', 'key1', 'key2']);
261
        sort($result);
262
263
        $exprectedResult = ['key1', 'key2'];
264
        $this->assertEquals($exprectedResult, $result);
265
    }
266
267
    public function testHasItemsReturnsEmptyArrayIfNonReadable()
268
    {
269
        $this->assertTrue($this->_storage->setItem('key', 'value'));
270
271
        $this->_options->setReadable(false);
272
        $this->assertEquals([], $this->_storage->hasItems(['key']));
273
    }
274
275
    public function testGetItemReturnsNullOnMissingItem()
276
    {
277
        $this->assertNull($this->_storage->getItem('unknwon'));
278
    }
279
280
    public function testGetItemSetsSuccessFlag()
281
    {
282
        $success = null;
283
284
        // $success = false on get missing item
285
        $this->_storage->getItem('unknown', $success);
286
        $this->assertFalse($success);
287
288
        // $success = true on get valid item
289
        $this->_storage->setItem('test', 'test');
290
        $this->_storage->getItem('test', $success);
291
        $this->assertTrue($success);
292
    }
293
294
    public function testGetItemReturnsNullOnExpiredItem()
295
    {
296
        $capabilities = $this->_storage->getCapabilities();
297
298
        if ($capabilities->getMinTtl() === 0) {
299
            $this->markTestSkipped("Adapter doesn't support item expiration");
300
        }
301
302
        if ($capabilities->getUseRequestTime()) {
303
            $this->markTestSkipped("Can't test get expired item if request time will be used");
304
        }
305
306
        $ttl = $capabilities->getTtlPrecision();
307
        $this->_options->setTtl($ttl);
308
309
        $this->waitForFullSecond();
310
311
        $this->_storage->setItem('key', 'value');
312
313
        // wait until expired
314
        $wait = $ttl + $capabilities->getTtlPrecision();
315
        usleep($wait * 2000000);
316
317
        $this->assertNull($this->_storage->getItem('key'));
318
    }
319
320
    public function testGetItemReturnsNullIfNonReadable()
321
    {
322
        $this->_options->setReadable(false);
323
324
        $this->assertTrue($this->_storage->setItem('key', 'value'));
325
        $this->assertNull($this->_storage->getItem('key'));
326
    }
327
328
    public function testGetItemsReturnsKeyValuePairsOfFoundItems()
329
    {
330
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
331
        $this->assertTrue($this->_storage->setItem('key2', 'value2'));
332
333
        $result = $this->_storage->getItems(['missing', 'key1', 'key2']);
334
        ksort($result);
335
336
        $exprectedResult = [
337
            'key1' => 'value1',
338
            'key2' => 'value2',
339
        ];
340
        $this->assertEquals($exprectedResult, $result);
341
    }
342
343
    public function testGetItemsReturnsEmptyArrayIfNonReadable()
344
    {
345
        $this->_options->setReadable(false);
346
347
        $this->assertTrue($this->_storage->setItem('key', 'value'));
348
        $this->assertEquals([], $this->_storage->getItems(['key']));
349
    }
350
351
    public function testGetMetadata()
352
    {
353
        $capabilities = $this->_storage->getCapabilities();
354
        $supportedMetadatas = $capabilities->getSupportedMetadata();
355
356
        $this->assertTrue($this->_storage->setItem('key', 'value'));
357
        $metadata = $this->_storage->getMetadata('key');
358
359
        $this->assertInternalType('array', $metadata);
360
        foreach ($supportedMetadatas as $supportedMetadata) {
361
            $this->assertArrayHasKey($supportedMetadata, $metadata);
362
        }
363
    }
364
365
    public function testGetMetadataReturnsFalseOnMissingItem()
366
    {
367
        $this->assertFalse($this->_storage->getMetadata('unknown'));
368
    }
369
370
    public function testGetMetadataReturnsFalseIfNonReadable()
371
    {
372
        $this->_options->setReadable(false);
373
374
        $this->assertTrue($this->_storage->setItem('key', 'value'));
375
        $this->assertFalse($this->_storage->getMetadata('key'));
376
    }
377
378
    public function testGetMetadatas()
379
    {
380
        $capabilities       = $this->_storage->getCapabilities();
381
        $supportedMetadatas = $capabilities->getSupportedMetadata();
382
383
        $items = [
384
            'key1' => 'value1',
385
            'key2' => 'value2'
386
        ];
387
        $this->assertSame([], $this->_storage->setItems($items));
388
389
        $metadatas = $this->_storage->getMetadatas(array_keys($items));
390
        $this->assertInternalType('array', $metadatas);
391
        $this->assertSame(count($items), count($metadatas));
392
        foreach ($metadatas as $k => $metadata) {
393
            $this->assertInternalType('array', $metadata);
394
            foreach ($supportedMetadatas as $supportedMetadata) {
395
                $this->assertArrayHasKey($supportedMetadata, $metadata);
396
            }
397
        }
398
    }
399
400
    /**
401
     * @group 7031
402
     * @group 7032
403
     */
404
    public function testGetMetadatasWithEmptyNamespace()
405
    {
406
        $this->_options->setNamespace('');
407
        $this->testGetMetadatas();
408
    }
409
410
    public function testGetMetadatasReturnsEmptyArrayIfNonReadable()
411
    {
412
        $this->_options->setReadable(false);
413
414
        $this->assertTrue($this->_storage->setItem('key', 'value'));
415
        $this->assertEquals([], $this->_storage->getMetadatas(['key']));
416
    }
417
418
    public function testSetGetHasAndRemoveItemWithoutNamespace()
419
    {
420
        $this->_storage->getOptions()->setNamespace('');
421
422
        $this->assertTrue($this->_storage->setItem('key', 'value'));
423
        $this->assertEquals('value', $this->_storage->getItem('key'));
424
        $this->assertTrue($this->_storage->hasItem('key'));
425
426
        $this->assertTrue($this->_storage->removeItem('key'));
427
        $this->assertFalse($this->_storage->hasItem('key'));
428
        $this->assertNull($this->_storage->getItem('key'));
429
    }
430
431
    public function testSetGetHasAndRemoveItemsWithoutNamespace()
432
    {
433
        $this->_storage->getOptions()->setNamespace('');
434
435
        $items = [
436
            'key1' => 'value1',
437
            'key2' => 'value2',
438
            'key3' => 'value3',
439
        ];
440
441
        $this->assertSame([], $this->_storage->setItems($items));
442
443
        $rs = $this->_storage->getItems(array_keys($items));
444
        $this->assertInternalType('array', $rs);
445
        foreach ($items as $key => $value) {
446
            $this->assertArrayHasKey($key, $rs);
447
            $this->assertEquals($value, $rs[$key]);
448
        }
449
450
        $rs = $this->_storage->hasItems(array_keys($items));
451
        $this->assertInternalType('array', $rs);
452
        $this->assertEquals(count($items), count($rs));
453
        foreach ($items as $key => $value) {
454
            $this->assertContains($key, $rs);
455
        }
456
457
        $this->assertSame(['missing'], $this->_storage->removeItems(['missing', 'key1', 'key3']));
458
        unset($items['key1'], $items['key3']);
459
460
        $rs = $this->_storage->getItems(array_keys($items));
461
        $this->assertInternalType('array', $rs);
462
        foreach ($items as $key => $value) {
463
            $this->assertArrayHasKey($key, $rs);
464
            $this->assertEquals($value, $rs[$key]);
465
        }
466
467
        $rs = $this->_storage->hasItems(array_keys($items));
468
        $this->assertInternalType('array', $rs);
469
        $this->assertEquals(count($items), count($rs));
470
        foreach ($items as $key => $value) {
471
            $this->assertContains($key, $rs);
472
        }
473
    }
474
475
    public function testSetGetHasAndRemoveItemWithNamespace()
476
    {
477
        // write "key" to default namespace
478
        $this->_options->setNamespace('defaultns1');
479
        $this->assertTrue($this->_storage->setItem('key', 'defaultns1'));
480
481
        // write "key" to an other default namespace
482
        $this->_options->setNamespace('defaultns2');
483
        $this->assertTrue($this->_storage->setItem('key', 'defaultns2'));
484
485
        // test value of defaultns2
486
        $this->assertTrue($this->_storage->hasItem('key'));
487
        $this->assertEquals('defaultns2', $this->_storage->getItem('key'));
488
489
        // test value of defaultns1
490
        $this->_options->setNamespace('defaultns1');
491
        $this->assertTrue($this->_storage->hasItem('key'));
492
        $this->assertEquals('defaultns1', $this->_storage->getItem('key'));
493
494
        // remove item of defaultns1
495
        $this->_options->setNamespace('defaultns1');
496
        $this->assertTrue($this->_storage->removeItem('key'));
497
        $this->assertFalse($this->_storage->hasItem('key'));
498
499
        // remove item of defaultns2
500
        $this->_options->setNamespace('defaultns2');
501
        $this->assertTrue($this->_storage->removeItem('key'));
502
        $this->assertFalse($this->_storage->hasItem('key'));
503
    }
504
505
    public function testSetGetHasAndRemoveItemsWithNamespace()
506
    {
507
        $items = [
508
            'key1' => 'value1',
509
            'key2' => 'value2',
510
            'key3' => 'value3',
511
        ];
512
513
        $this->_options->setNamespace('defaultns1');
514
        $this->assertSame([], $this->_storage->setItems($items));
515
516
        $this->_options->setNamespace('defaultns2');
517
        $this->assertSame([],  $this->_storage->hasItems(array_keys($items)));
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 2 after comma in function call.
Loading history...
518
519
        $this->_options->setNamespace('defaultns1');
520
        $rs = $this->_storage->getItems(array_keys($items));
521
        $this->assertInternalType('array', $rs);
522
        foreach ($items as $key => $value) {
523
            $this->assertArrayHasKey($key, $rs);
524
            $this->assertEquals($value, $rs[$key]);
525
        }
526
527
        $rs = $this->_storage->hasItems(array_keys($items));
528
        $this->assertInternalType('array', $rs);
529
        $this->assertEquals(count($items), count($rs));
530
        foreach ($items as $key => $value) {
531
            $this->assertContains($key, $rs);
532
        }
533
534
        // remove the first and the last item
535
        $this->assertSame(['missing'], $this->_storage->removeItems(['missing', 'key1', 'key3']));
536
        unset($items['key1'], $items['key3']);
537
538
        $rs = $this->_storage->getItems(array_keys($items));
539
        $this->assertInternalType('array', $rs);
540
        foreach ($items as $key => $value) {
541
            $this->assertArrayHasKey($key, $rs);
542
            $this->assertEquals($value, $rs[$key]);
543
        }
544
545
        $rs = $this->_storage->hasItems(array_keys($items));
546
        $this->assertInternalType('array', $rs);
547
        $this->assertEquals(count($items), count($rs));
548
        foreach ($items as $key => $value) {
549
            $this->assertContains($key, $rs);
550
        }
551
    }
552
553
    public function testSetAndGetExpiredItem()
554
    {
555
        $capabilities = $this->_storage->getCapabilities();
556
557
        if ($capabilities->getMinTtl() === 0) {
558
            $this->markTestSkipped("Adapter doesn't support item expiration");
559
        }
560
561
        $ttl = $capabilities->getTtlPrecision();
562
        $this->_options->setTtl($ttl);
563
564
        $this->waitForFullSecond();
565
566
        $this->_storage->setItem('key', 'value');
567
568
        // wait until expired
569
        $wait = $ttl + $capabilities->getTtlPrecision();
570
        usleep($wait * 2000000);
571
572
        if ($capabilities->getUseRequestTime()) {
573
            // Can't test much more if the request time will be used
574
            $this->assertEquals('value', $this->_storage->getItem('key'));
575
            return;
576
        }
577
578
        $this->assertNull($this->_storage->getItem('key'));
579
580
        $this->_options->setTtl(0);
581
        if ($capabilities->getExpiredRead()) {
582
            $this->assertEquals('value', $this->_storage->getItem('key'));
583
        } else {
584
            $this->assertNull($this->_storage->getItem('key'));
585
        }
586
    }
587
588
    public function testSetAndGetExpiredItems()
589
    {
590
        $capabilities = $this->_storage->getCapabilities();
591
592
        if ($capabilities->getMinTtl() === 0) {
593
            $this->markTestSkipped("Adapter doesn't support item expiration");
594
        }
595
596
        // item definition
597
        $itemsHigh = [
598
            'keyHigh1' => 'valueHigh1',
599
            'keyHigh2' => 'valueHigh2',
600
            'keyHigh3' => 'valueHigh3'
601
        ];
602
        $itemsLow = [
603
            'keyLow1' => 'valueLow1',
604
            'keyLow2' => 'valueLow2',
605
            'keyLow3' => 'valueLow3'
606
        ];
607
        $items = $itemsHigh + $itemsLow;
608
609
        // set items with high TTL
610
        $this->_options->setTtl(123456);
611
        $this->assertSame([], $this->_storage->setItems($itemsHigh));
612
613
        // set items with low TTL
614
        $ttl = $capabilities->getTtlPrecision();
615
        $this->_options->setTtl($ttl);
616
        $this->waitForFullSecond();
617
        $this->assertSame([], $this->_storage->setItems($itemsLow));
618
619
        // wait until expired
620
        $wait = $ttl + $capabilities->getTtlPrecision();
621
        usleep($wait * 2000000);
622
623
        $rs = $this->_storage->getItems(array_keys($items));
624
        ksort($rs); // make comparable
625
626
        if ($capabilities->getExpiredRead()) {
627
            // if item expiration will be done on read there is no difference
628
            // between the previos set items in TTL.
629
            // -> all items will be expired
630
            $this->assertEquals([], $rs);
631
632
            // after disabling TTL all items will be available
633
            $this->_options->setTtl(0);
634
            $rs = $this->_storage->getItems(array_keys($items));
635
            ksort($rs); // make comparable
636
            $this->assertEquals($items, $rs);
637
        } elseif ($capabilities->getUseRequestTime()) {
638
            // if the request time will be used as current time all items will
639
            // be available as expiration doesn't work within the same process
640
            $this->assertEquals($items, $rs);
641
        } else {
642
            $this->assertEquals($itemsHigh, $rs);
643
        }
644
    }
645
646
    public function testSetAndGetItemOfDifferentTypes()
647
    {
648
        $capabilities = $this->_storage->getCapabilities();
649
650
        $types = [
651
            'NULL'     => null,
652
            'boolean'  => true,
653
            'integer'  => 12345,
654
            'double'   => 123.45,
655
            'string'   => 'string', // already tested
656
            'array'    => ['one', 'tow' => 'two', 'three' => ['four' => 'four']],
657
            'object'   => new \stdClass(),
658
            'resource' => fopen(__FILE__, 'r'),
659
        ];
660
        $types['object']->one = 'one';
661
        $types['object']->two = new \stdClass();
662
        $types['object']->two->three = 'three';
663
664
        foreach ($capabilities->getSupportedDatatypes() as $sourceType => $targetType) {
665
            if ($targetType === false) {
666
                continue;
667
            }
668
669
            $value = $types[$sourceType];
670
            $this->assertTrue($this->_storage->setItem('key', $value), "Failed to set type '{$sourceType}'");
671
672
            if ($targetType === true) {
673
                $this->assertSame($value, $this->_storage->getItem('key'));
674
            } elseif (is_string($targetType)) {
675
                settype($value, $targetType);
676
                $this->assertEquals($value, $this->_storage->getItem('key'));
677
            }
678
        }
679
    }
680
681
    public function testSetItemReturnsFalseIfNonWritable()
682
    {
683
        $this->_options->setWritable(false);
684
685
        $this->assertFalse($this->_storage->setItem('key', 'value'));
686
        $this->assertFalse($this->_storage->hasItem('key'));
687
    }
688
689
    public function testAddNewItem()
690
    {
691
        $this->assertTrue($this->_storage->addItem('key', 'value'));
692
        $this->assertTrue($this->_storage->hasItem('key'));
693
    }
694
695
    public function testAddItemReturnsFalseIfItemAlreadyExists()
696
    {
697
        $this->assertTrue($this->_storage->setItem('key', 'value'));
698
        $this->assertFalse($this->_storage->addItem('key', 'newValue'));
699
    }
700
701
    public function testAddItemReturnsFalseIfNonWritable()
702
    {
703
        $this->_options->setWritable(false);
704
705
        $this->assertFalse($this->_storage->addItem('key', 'value'));
706
        $this->assertFalse($this->_storage->hasItem('key'));
707
    }
708
709
    public function testAddItemsReturnsFailedKeys()
710
    {
711
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
712
713
        $failedKeys = $this->_storage->addItems([
714
            'key1' => 'XYZ',
715
            'key2' => 'value2',
716
        ]);
717
718
        $this->assertSame(['key1'], $failedKeys);
719
        $this->assertSame('value1', $this->_storage->getItem('key1'));
720
        $this->assertTrue($this->_storage->hasItem('key2'));
721
    }
722
723
    public function testAddItemSetsTTL()
724
    {
725
        $capabilities = $this->_storage->getCapabilities();
726
727
        if ($capabilities->getMinTtl() === 0) {
728
            $this->markTestSkipped("Adapter doesn't support item expiration");
729
        }
730
731
        $ttl = $capabilities->getTtlPrecision();
732
        $this->_options->setTtl($ttl);
733
734
        $this->waitForFullSecond();
735
736
        $this->assertTrue($this->_storage->addItem('key', 'value'));
737
738
        // wait until the item expired
739
        $wait = $ttl + $capabilities->getTtlPrecision();
740
        usleep($wait * 2000000);
741
742
        if (!$capabilities->getUseRequestTime()) {
743
            $this->assertFalse($this->_storage->hasItem('key'));
744
        } else {
745
            $this->assertTrue($this->_storage->hasItem('key'));
746
        }
747
    }
748
749
    public function testReplaceExistingItem()
750
    {
751
        $this->assertTrue($this->_storage->setItem('key', 'value'));
752
        $this->assertTrue($this->_storage->replaceItem('key', 'anOtherValue'));
753
        $this->assertEquals('anOtherValue', $this->_storage->getItem('key'));
754
    }
755
756
    public function testReplaceItemReturnsFalseOnMissingItem()
757
    {
758
        $this->assertFalse($this->_storage->replaceItem('missingKey', 'value'));
759
    }
760
761
    public function testReplaceItemReturnsFalseIfNonWritable()
762
    {
763
        $this->_storage->setItem('key', 'value');
764
        $this->_options->setWritable(false);
765
766
        $this->assertFalse($this->_storage->replaceItem('key', 'newvalue'));
767
        $this->assertEquals('value', $this->_storage->getItem('key'));
768
    }
769
770
    public function testReplaceItemsReturnsFailedKeys()
771
    {
772
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
773
774
        $failedKeys = $this->_storage->replaceItems([
775
            'key1' => 'XYZ',
776
            'key2' => 'value2',
777
        ]);
778
779
        $this->assertSame(['key2'], $failedKeys);
780
        $this->assertSame('XYZ', $this->_storage->getItem('key1'));
781
        $this->assertFalse($this->_storage->hasItem('key2'));
782
    }
783
784
    public function testRemoveItemReturnsFalseOnMissingItem()
785
    {
786
        $this->assertFalse($this->_storage->removeItem('missing'));
787
    }
788
789
    public function testRemoveItemsReturnsMissingKeys()
790
    {
791
        $this->_storage->setItem('key', 'value');
792
        $this->assertSame(['missing'], $this->_storage->removeItems(['key', 'missing']));
793
    }
794
795
    public function testCheckAndSetItem()
796
    {
797
        $this->assertTrue($this->_storage->setItem('key', 'value'));
798
799
        $success  = null;
800
        $casToken = null;
801
        $this->assertEquals('value', $this->_storage->getItem('key', $success, $casToken));
802
        $this->assertNotNull($casToken);
803
804
        $this->assertTrue($this->_storage->checkAndSetItem($casToken, 'key', 'newValue'));
805
        $this->assertFalse($this->_storage->checkAndSetItem($casToken, 'key', 'failedValue'));
806
        $this->assertEquals('newValue', $this->_storage->getItem('key'));
807
    }
808
809
    public function testIncrementItem()
810
    {
811
        $this->assertTrue($this->_storage->setItem('counter', 10));
812
        $this->assertEquals(15, $this->_storage->incrementItem('counter', 5));
813
        $this->assertEquals(15, $this->_storage->getItem('counter'));
814
    }
815
816
    public function testIncrementItemInitialValue()
817
    {
818
        $this->assertEquals(5, $this->_storage->incrementItem('counter', 5));
819
        $this->assertEquals(5, $this->_storage->getItem('counter'));
820
    }
821
822
    public function testIncrementItemReturnsFalseIfNonWritable()
823
    {
824
        $this->_storage->setItem('key', 10);
825
        $this->_options->setWritable(false);
826
827
        $this->assertFalse($this->_storage->incrementItem('key', 5));
828
        $this->assertEquals(10, $this->_storage->getItem('key'));
829
    }
830
831
    public function testIncrementItemsResturnsKeyValuePairsOfWrittenItems()
832
    {
833
        $this->assertTrue($this->_storage->setItem('key1', 10));
834
835
        $result = $this->_storage->incrementItems([
836
            'key1' => 10,
837
            'key2' => 10,
838
        ]);
839
        ksort($result);
840
841
        $this->assertSame([
842
            'key1' => 20,
843
            'key2' => 10,
844
        ], $result);
845
    }
846
847
    public function testIncrementItemsReturnsEmptyArrayIfNonWritable()
848
    {
849
        $this->_storage->setItem('key', 10);
850
        $this->_options->setWritable(false);
851
852
        $this->assertSame([], $this->_storage->incrementItems(['key' => 5]));
853
        $this->assertEquals(10, $this->_storage->getItem('key'));
854
    }
855
856
    public function testDecrementItem()
857
    {
858
        $this->assertTrue($this->_storage->setItem('counter', 30));
859
        $this->assertEquals(25, $this->_storage->decrementItem('counter', 5));
860
        $this->assertEquals(25, $this->_storage->getItem('counter'));
861
    }
862
863
    public function testDecrementItemInitialValue()
864
    {
865
        $this->assertEquals(-5, $this->_storage->decrementItem('counter', 5));
866
        $this->assertEquals(-5, $this->_storage->getItem('counter'));
867
    }
868
869
    public function testDecrementItemReturnsFalseIfNonWritable()
870
    {
871
        $this->_storage->setItem('key', 10);
872
        $this->_options->setWritable(false);
873
874
        $this->assertFalse($this->_storage->decrementItem('key', 5));
875
        $this->assertEquals(10, $this->_storage->getItem('key'));
876
    }
877
878
    public function testDecrementItemsReturnsEmptyArrayIfNonWritable()
879
    {
880
        $this->_storage->setItem('key', 10);
881
        $this->_options->setWritable(false);
882
883
        $this->assertSame([], $this->_storage->decrementItems(['key' => 5]));
884
        $this->assertEquals(10, $this->_storage->getItem('key'));
885
    }
886
887
    public function testTouchItem()
888
    {
889
        $capabilities = $this->_storage->getCapabilities();
890
891
        if ($capabilities->getMinTtl() === 0) {
892
            $this->markTestSkipped("Adapter doesn't support item expiration");
893
        }
894
895
        $this->_options->setTtl(2 * $capabilities->getTtlPrecision());
896
897
        $this->waitForFullSecond();
898
899
        $this->assertTrue($this->_storage->setItem('key', 'value'));
900
901
        // sleep 1 times before expire to touch the item
902
        usleep($capabilities->getTtlPrecision() * 1000000);
903
        $this->assertTrue($this->_storage->touchItem('key'));
904
905
        usleep($capabilities->getTtlPrecision() * 1000000);
906
        $this->assertTrue($this->_storage->hasItem('key'));
907
908
        if (!$capabilities->getUseRequestTime()) {
909
            usleep($capabilities->getTtlPrecision() * 2000000);
910
            $this->assertFalse($this->_storage->hasItem('key'));
911
        }
912
    }
913
914
    public function testTouchItemReturnsFalseOnMissingItem()
915
    {
916
        $this->assertFalse($this->_storage->touchItem('missing'));
917
    }
918
919
    public function testTouchItemReturnsFalseIfNonWritable()
920
    {
921
        $this->_options->setWritable(false);
922
923
        $this->assertFalse($this->_storage->touchItem('key'));
924
    }
925
926
    public function testTouchItemsReturnsGivenKeysIfNonWritable()
927
    {
928
        $this->_options->setWritable(false);
929
        $this->assertSame(['key'], $this->_storage->touchItems(['key']));
930
    }
931
932
    public function testOptimize()
933
    {
934
        if (!($this->_storage instanceof OptimizableInterface)) {
935
            $this->markTestSkipped("Storage doesn't implement OptimizableInterface");
936
        }
937
938
        $this->assertTrue($this->_storage->optimize());
939
    }
940
941
    public function testIterator()
942
    {
943
        if (!$this->_storage instanceof IterableInterface) {
944
            $this->markTestSkipped("Storage doesn't implement IterableInterface");
945
        }
946
947
        $items = [
948
            'key1' => 'value1',
949
            'key2' => 'value2',
950
        ];
951
        $this->assertSame([], $this->_storage->setItems($items));
952
953
        // check iterator aggregate
954
        $iterator = $this->_storage->getIterator();
955
        $this->assertInstanceOf('Zend\Cache\Storage\IteratorInterface', $iterator);
956
        $this->assertSame(IteratorInterface::CURRENT_AS_KEY, $iterator->getMode());
957
958
        // check mode CURRENT_AS_KEY
959
        $iterator = $this->_storage->getIterator();
960
        $iterator->setMode(IteratorInterface::CURRENT_AS_KEY);
961
        $keys = iterator_to_array($iterator, false);
962
        sort($keys);
963
        $this->assertSame(array_keys($items), $keys);
964
965
        // check mode CURRENT_AS_VALUE
966
        $iterator = $this->_storage->getIterator();
967
        $iterator->setMode(IteratorInterface::CURRENT_AS_VALUE);
968
        $result = iterator_to_array($iterator, true);
969
        ksort($result);
970
        $this->assertSame($items, $result);
971
    }
972
973
    public function testFlush()
974
    {
975
        if (!($this->_storage instanceof FlushableInterface)) {
976
            $this->markTestSkipped("Storage doesn't implement OptimizableInterface");
977
        }
978
979
        $this->assertSame([], $this->_storage->setItems([
980
            'key1' => 'value1',
981
            'key2' => 'value2',
982
        ]));
983
984
        $this->assertTrue($this->_storage->flush());
985
        $this->assertFalse($this->_storage->hasItem('key1'));
986
        $this->assertFalse($this->_storage->hasItem('key2'));
987
    }
988
989
    public function testClearByPrefix()
990
    {
991
        if (!($this->_storage instanceof ClearByPrefixInterface)) {
992
            $this->markTestSkipped("Storage doesn't implement ClearByPrefixInterface");
993
        }
994
995
        $this->assertSame([], $this->_storage->setItems([
996
            'key1' => 'value1',
997
            'key2' => 'value2',
998
            'test' => 'value',
999
        ]));
1000
1001
        $this->assertTrue($this->_storage->clearByPrefix('key'));
1002
        $this->assertFalse($this->_storage->hasItem('key1'));
1003
        $this->assertFalse($this->_storage->hasItem('key2'));
1004
        $this->assertTrue($this->_storage->hasItem('test'));
1005
    }
1006
1007
    public function testClearByPrefixThrowsInvalidArgumentExceptionOnEmptyPrefix()
1008
    {
1009
        if (!($this->_storage instanceof ClearByPrefixInterface)) {
1010
            $this->markTestSkipped("Storage doesn't implement ClearByPrefixInterface");
1011
        }
1012
1013
        $this->setExpectedException('Zend\Cache\Exception\InvalidArgumentException');
1014
        $this->_storage->clearByPrefix('');
1015
    }
1016
1017
    public function testClearByNamespace()
1018
    {
1019
        if (!($this->_storage instanceof ClearByNamespaceInterface)) {
1020
            $this->markTestSkipped("Storage doesn't implement ClearByNamespaceInterface");
1021
        }
1022
1023
        // write 2 items of 2 different namespaces
1024
        $this->_options->setNamespace('ns1');
1025
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
1026
        $this->_options->setNamespace('ns2');
1027
        $this->assertTrue($this->_storage->setItem('key2', 'value2'));
1028
1029
        // clear unknown namespace should return true but clear nothing
1030
        $this->assertTrue($this->_storage->clearByNamespace('unknown'));
1031
        $this->_options->setNamespace('ns1');
1032
        $this->assertTrue($this->_storage->hasItem('key1'));
1033
        $this->_options->setNamespace('ns2');
1034
        $this->assertTrue($this->_storage->hasItem('key2'));
1035
1036
        // clear "ns1"
1037
        $this->assertTrue($this->_storage->clearByNamespace('ns1'));
1038
        $this->_options->setNamespace('ns1');
1039
        $this->assertFalse($this->_storage->hasItem('key1'));
1040
        $this->_options->setNamespace('ns2');
1041
        $this->assertTrue($this->_storage->hasItem('key2'));
1042
1043
        // clear "ns2"
1044
        $this->assertTrue($this->_storage->clearByNamespace('ns2'));
1045
        $this->_options->setNamespace('ns1');
1046
        $this->assertFalse($this->_storage->hasItem('key1'));
1047
        $this->_options->setNamespace('ns2');
1048
        $this->assertFalse($this->_storage->hasItem('key2'));
1049
    }
1050
1051
    public function testClearByNamespaceThrowsInvalidArgumentExceptionOnEmptyNamespace()
1052
    {
1053
        if (!($this->_storage instanceof ClearByNamespaceInterface)) {
1054
            $this->markTestSkipped("Storage doesn't implement ClearByNamespaceInterface");
1055
        }
1056
1057
        $this->setExpectedException('Zend\Cache\Exception\InvalidArgumentException');
1058
        $this->_storage->clearByNamespace('');
1059
    }
1060
1061
    public function testClearExpired()
1062
    {
1063
        if (!($this->_storage instanceof ClearExpiredInterface)) {
1064
            $this->markTestSkipped("Storage doesn't implement ClearExpiredInterface");
1065
        }
1066
1067
        $capabilities = $this->_storage->getCapabilities();
1068
        $ttl = $capabilities->getTtlPrecision();
1069
        $this->_options->setTtl($ttl);
1070
1071
        $this->waitForFullSecond();
1072
1073
        $this->assertTrue($this->_storage->setItem('key1', 'value1'));
1074
1075
        // wait until the first item expired
1076
        $wait = $ttl + $capabilities->getTtlPrecision();
1077
        usleep($wait * 2000000);
1078
1079
        $this->assertTrue($this->_storage->setItem('key2', 'value2'));
1080
1081
        $this->assertTrue($this->_storage->clearExpired());
1082
1083
        if ($capabilities->getUseRequestTime()) {
1084
            $this->assertTrue($this->_storage->hasItem('key1'));
1085
        } else {
1086
            $this->assertFalse($this->_storage->hasItem('key1', ['ttl' => 0]));
1087
        }
1088
1089
        $this->assertTrue($this->_storage->hasItem('key2'));
1090
    }
1091
1092
    public function testTaggable()
1093
    {
1094
        if (!($this->_storage instanceof TaggableInterface)) {
1095
            $this->markTestSkipped("Storage doesn't implement TaggableInterface");
1096
        }
1097
1098
        // store 3 items and register the current default namespace
1099
        $this->assertSame([], $this->_storage->setItems([
1100
            'key1' => 'value1',
1101
            'key2' => 'value2',
1102
            'key3' => 'value3',
1103
        ]));
1104
1105
        $this->assertTrue($this->_storage->setTags('key1', ['tag1a', 'tag1b']));
1106
        $this->assertTrue($this->_storage->setTags('key2', ['tag2a', 'tag2b']));
1107
        $this->assertTrue($this->_storage->setTags('key3', ['tag3a', 'tag3b']));
1108
        $this->assertFalse($this->_storage->setTags('missing', ['tag']));
1109
1110
        // return tags
1111
        $tags = $this->_storage->getTags('key1');
1112
        $this->assertInternalType('array', $tags);
1113
        sort($tags);
1114
        $this->assertSame(['tag1a', 'tag1b'], $tags);
1115
1116
        // this should remove nothing
1117
        $this->assertTrue($this->_storage->clearByTags(['tag1a', 'tag2a']));
1118
        $this->assertTrue($this->_storage->hasItem('key1'));
1119
        $this->assertTrue($this->_storage->hasItem('key2'));
1120
        $this->assertTrue($this->_storage->hasItem('key3'));
1121
1122
        // this should remove key1 and key2
1123
        $this->assertTrue($this->_storage->clearByTags(['tag1a', 'tag2b'], true));
1124
        $this->assertFalse($this->_storage->hasItem('key1'));
1125
        $this->assertFalse($this->_storage->hasItem('key2'));
1126
        $this->assertTrue($this->_storage->hasItem('key3'));
1127
1128
        // this should remove key3
1129
        $this->assertTrue($this->_storage->clearByTags(['tag3a', 'tag3b'], true));
1130
        $this->assertFalse($this->_storage->hasItem('key1'));
1131
        $this->assertFalse($this->_storage->hasItem('key2'));
1132
        $this->assertFalse($this->_storage->hasItem('key3'));
1133
    }
1134
1135
    /**
1136
     * @group 6878
1137
     */
1138
    public function testTaggableFunctionsOnEmptyStorage()
1139
    {
1140
        if (!($this->_storage instanceof TaggableInterface)) {
1141
            $this->markTestSkipped("Storage doesn't implement TaggableInterface");
1142
        }
1143
1144
        $this->assertFalse($this->_storage->setTags('unknown', ['no']));
1145
        $this->assertFalse($this->_storage->getTags('unknown'));
1146
        $this->assertTrue($this->_storage->clearByTags(['unknown']));
1147
    }
1148
1149
    public function testGetTotalSpace()
1150
    {
1151
        if (!($this->_storage instanceof TotalSpaceCapableInterface)) {
1152
            $this->markTestSkipped("Storage doesn't implement TotalSpaceCapableInterface");
1153
        }
1154
1155
        $totalSpace = $this->_storage->getTotalSpace();
1156
        $this->assertGreaterThanOrEqual(0, $totalSpace);
1157
1158
        if ($this->_storage instanceof AvailableSpaceCapableInterface) {
1159
            $availableSpace = $this->_storage->getAvailableSpace();
1160
            $this->assertGreaterThanOrEqual($availableSpace, $totalSpace);
1161
        }
1162
    }
1163
1164
    public function testGetAvailableSpace()
1165
    {
1166
        if (!($this->_storage instanceof AvailableSpaceCapableInterface)) {
1167
            $this->markTestSkipped("Storage doesn't implement AvailableSpaceCapableInterface");
1168
        }
1169
1170
        $availableSpace = $this->_storage->getAvailableSpace();
1171
        $this->assertGreaterThanOrEqual(0, $availableSpace);
1172
1173
        if ($this->_storage instanceof TotalSpaceCapableInterface) {
1174
            $totalSpace = $this->_storage->getTotalSpace();
1175
            $this->assertLessThanOrEqual($totalSpace, $availableSpace);
1176
        }
1177
    }
1178
1179
    /**
1180
     * This will wait for a full second started
1181
     * to reduce test failures on high load servers
1182
     * @see https://github.com/zendframework/zf2/issues/5144
1183
     */
1184
    protected function waitForFullSecond()
1185
    {
1186
        $interval = (microtime(true)-time()) * 1000000;
1187
        usleep((int) $interval);
1188
    }
1189
}
1190