‪TYPO3CMS  11.5
Typo3DatabaseBackendTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
24 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
25 
29 class ‪Typo3DatabaseBackendTest extends FunctionalTestCase
30 {
31  use \Prophecy\PhpUnit\ProphecyTrait;
35  public function ‪getReturnsPreviouslySetEntry(): void
36  {
37  $frontendProphecy = $this->prophesize(FrontendInterface::class);
38  $frontendProphecy->getIdentifier()->willReturn('pages');
39 
40  $subject = new ‪Typo3DatabaseBackend('Testing');
41  $subject->setCache($frontendProphecy->reveal());
42 
43  $subject->set('myIdentifier', 'myData');
44  self::assertSame('myData', $subject->get('myIdentifier'));
45  }
46 
51  {
52  $frontendProphecy = $this->prophesize(FrontendInterface::class);
53  $frontendProphecy->getIdentifier()->willReturn('pages');
54 
55  $subject = new ‪Typo3DatabaseBackend('Testing');
56  $subject->setCache($frontendProphecy->reveal());
57 
58  $subject->set('myIdentifier', 'myData');
59  $subject->set('myIdentifier', 'myNewData');
60  self::assertSame('myNewData', $subject->get('myIdentifier'));
61  }
62 
66  public function ‪setInsertsDataWithTagsIntoCacheTable(): void
67  {
68  $frontendProphecy = $this->prophesize(FrontendInterface::class);
69  $frontendProphecy->getIdentifier()->willReturn('pages');
70 
71  $subject = new ‪Typo3DatabaseBackend('Testing');
72  $subject->setCache($frontendProphecy->reveal());
73 
74  $subject->set('myIdentifier', 'myData', ['aTag', 'anotherTag']);
75 
76  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
77  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
78  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'myIdentifier']));
79  self::assertSame(1, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'myIdentifier', 'tag' => 'aTag']));
80  self::assertSame(1, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'myIdentifier', 'tag' => 'anotherTag']));
81  }
82 
86  public function ‪setStoresCompressedContent(): void
87  {
88  $frontendProphecy = $this->prophesize(FrontendInterface::class);
89  $frontendProphecy->getIdentifier()->willReturn('pages');
90 
91  // Have backend with compression enabled
92  $subject = new ‪Typo3DatabaseBackend('Testing', ['compression' => true]);
93  $subject->setCache($frontendProphecy->reveal());
94 
95  $subject->set('myIdentifier', 'myCachedContent');
96 
97  $row = (new ‪ConnectionPool())
98  ->getConnectionForTable('cache_pages')
99  ->select(
100  ['content'],
101  'cache_pages',
102  ['identifier' => 'myIdentifier']
103  )
104  ->fetchAssociative();
105 
106  // Content comes back uncompressed
107  self::assertSame('myCachedContent', gzuncompress($row['content']));
108  }
109 
113  public function ‪getReturnsFalseIfNoCacheEntryExists(): void
114  {
115  $frontendProphecy = $this->prophesize(FrontendInterface::class);
116  $frontendProphecy->getIdentifier()->willReturn('pages');
117 
118  $subject = new ‪Typo3DatabaseBackend('Testing');
119  $subject->setCache($frontendProphecy->reveal());
120 
121  self::assertFalse($subject->get('myIdentifier'));
122  }
123 
127  public function ‪getReturnsFalseForExpiredCacheEntry(): void
128  {
129  $frontendProphecy = $this->prophesize(FrontendInterface::class);
130  $frontendProphecy->getIdentifier()->willReturn('pages');
131 
132  // Push an expired row into db
133  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
134  'cache_pages',
135  [
136  'identifier' => 'myIdentifier',
137  'expires' => ‪$GLOBALS['EXEC_TIME'] - 60,
138  'content' => 'myCachedContent',
139  ],
140  [
141  'content' => ‪Connection::PARAM_LOB,
142  ]
143  );
144 
145  $subject = new ‪Typo3DatabaseBackend('Testing');
146  $subject->setCache($frontendProphecy->reveal());
147 
148  self::assertFalse($subject->get('myIdentifier'));
149  }
150 
154  public function ‪getReturnsNotExpiredCacheEntry(): void
155  {
156  $frontendProphecy = $this->prophesize(FrontendInterface::class);
157  $frontendProphecy->getIdentifier()->willReturn('pages');
158 
159  // Push a row into db
160  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
161  'cache_pages',
162  [
163  'identifier' => 'myIdentifier',
164  'expires' => ‪$GLOBALS['EXEC_TIME'] + 60,
165  'content' => 'myCachedContent',
166  ],
167  [
168  'content' => ‪Connection::PARAM_LOB,
169  ]
170  );
171 
172  $subject = new ‪Typo3DatabaseBackend('Testing');
173  $subject->setCache($frontendProphecy->reveal());
174 
175  self::assertSame('myCachedContent', $subject->get('myIdentifier'));
176  }
177 
181  public function ‪getReturnsUnzipsNotExpiredCacheEntry(): void
182  {
183  $frontendProphecy = $this->prophesize(FrontendInterface::class);
184  $frontendProphecy->getIdentifier()->willReturn('pages');
185 
186  // Push a compressed row into db
187  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
188  'cache_pages',
189  [
190  'identifier' => 'myIdentifier',
191  'expires' => ‪$GLOBALS['EXEC_TIME'] + 60,
192  'content' => gzcompress('myCachedContent'),
193  ],
194  [
195  'content' => ‪Connection::PARAM_LOB,
196  ]
197  );
198 
199  // Have backend with compression enabled
200  $subject = new ‪Typo3DatabaseBackend('Testing', ['compression' => true]);
201  $subject->setCache($frontendProphecy->reveal());
202 
203  // Content comes back uncompressed
204  self::assertSame('myCachedContent', $subject->get('myIdentifier'));
205  }
206 
210  public function ‪getReturnsEmptyStringUnzipped(): void
211  {
212  $frontendProphecy = $this->prophesize(FrontendInterface::class);
213  $frontendProphecy->getIdentifier()->willReturn('pages');
214 
215  // Push a compressed row into db
216  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
217  'cache_pages',
218  [
219  'identifier' => 'myIdentifier',
220  'expires' => ‪$GLOBALS['EXEC_TIME'] + 60,
221  'content' => gzcompress(''),
222  ],
223  [
224  'content' => ‪Connection::PARAM_LOB,
225  ]
226  );
227 
228  // Have backend with compression enabled
229  $subject = new ‪Typo3DatabaseBackend('Testing', ['compression' => true]);
230  $subject->setCache($frontendProphecy->reveal());
231 
232  // Content comes back uncompressed
233  self::assertSame('', $subject->get('myIdentifier'));
234  }
235 
239  public function ‪hasReturnsFalseIfNoCacheEntryExists(): void
240  {
241  $frontendProphecy = $this->prophesize(FrontendInterface::class);
242  $frontendProphecy->getIdentifier()->willReturn('pages');
243 
244  $subject = new ‪Typo3DatabaseBackend('Testing');
245  $subject->setCache($frontendProphecy->reveal());
246 
247  self::assertFalse($subject->has('myIdentifier'));
248  }
249 
253  public function ‪hasReturnsFalseForExpiredCacheEntry(): void
254  {
255  $frontendProphecy = $this->prophesize(FrontendInterface::class);
256  $frontendProphecy->getIdentifier()->willReturn('pages');
257 
258  // Push an expired row into db
259  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
260  'cache_pages',
261  [
262  'identifier' => 'myIdentifier',
263  'expires' => ‪$GLOBALS['EXEC_TIME'] - 60,
264  'content' => 'myCachedContent',
265  ],
266  [
267  'content' => ‪Connection::PARAM_LOB,
268  ]
269  );
270 
271  $subject = new ‪Typo3DatabaseBackend('Testing');
272  $subject->setCache($frontendProphecy->reveal());
273 
274  self::assertFalse($subject->has('myIdentifier'));
275  }
276 
280  public function ‪hasReturnsNotExpiredCacheEntry(): void
281  {
282  $frontendProphecy = $this->prophesize(FrontendInterface::class);
283  $frontendProphecy->getIdentifier()->willReturn('pages');
284 
285  // Push a row into db
286  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
287  'cache_pages',
288  [
289  'identifier' => 'myIdentifier',
290  'expires' => ‪$GLOBALS['EXEC_TIME'] + 60,
291  'content' => 'myCachedContent',
292  ],
293  [
294  'content' => ‪Connection::PARAM_LOB,
295  ]
296  );
297 
298  $subject = new ‪Typo3DatabaseBackend('Testing');
299  $subject->setCache($frontendProphecy->reveal());
300 
301  self::assertTrue($subject->has('myIdentifier'));
302  }
303 
307  public function ‪removeReturnsFalseIfNoEntryHasBeenRemoved(): void
308  {
309  $frontendProphecy = $this->prophesize(FrontendInterface::class);
310  $frontendProphecy->getIdentifier()->willReturn('pages');
311 
312  $subject = new ‪Typo3DatabaseBackend('Testing');
313  $subject->setCache($frontendProphecy->reveal());
314 
315  self::assertFalse($subject->remove('myIdentifier'));
316  }
317 
321  public function ‪removeReturnsTrueIfAnEntryHasBeenRemoved(): void
322  {
323  $frontendProphecy = $this->prophesize(FrontendInterface::class);
324  $frontendProphecy->getIdentifier()->willReturn('pages');
325 
326  // Push a row into db
327  (new ‪ConnectionPool())->getConnectionForTable('cache_pages')->insert(
328  'cache_pages',
329  [
330  'identifier' => 'myIdentifier',
331  'expires' => ‪$GLOBALS['EXEC_TIME'] + 60,
332  'content' => 'myCachedContent',
333  ],
334  [
335  'content' => ‪Connection::PARAM_LOB,
336  ]
337  );
338 
339  $subject = new ‪Typo3DatabaseBackend('Testing');
340  $subject->setCache($frontendProphecy->reveal());
341 
342  self::assertTrue($subject->remove('myIdentifier'));
343  }
344 
348  public function ‪removeRemovesCorrectEntriesFromDatabase(): void
349  {
350  $frontendProphecy = $this->prophesize(FrontendInterface::class);
351  $frontendProphecy->getIdentifier()->willReturn('pages');
352 
353  // Add one cache row to remove and another one that shouldn't be removed
354  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
355  $cacheTableConnection->bulkInsert(
356  'cache_pages',
357  [
358  ['myIdentifier', ‪$GLOBALS['EXEC_TIME'] + 60, 'myCachedContent'],
359  ['otherIdentifier', ‪$GLOBALS['EXEC_TIME'] + 60, 'otherCachedContent'],
360  ],
361  ['identifier', 'expires', 'content'],
362  [
363  'content' => ‪Connection::PARAM_LOB,
364  ]
365  );
366  $subject = new ‪Typo3DatabaseBackend('Testing');
367  $subject->setCache($frontendProphecy->reveal());
368 
369  // Add a couple of tags
370  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
371  $tagsTableConnection->bulkInsert(
372  'cache_pages_tags',
373  [
374  ['myIdentifier', 'aTag'],
375  ['myIdentifier', 'otherTag'],
376  ['otherIdentifier', 'aTag'],
377  ['otherIdentifier', 'otherTag'],
378  ],
379  ['identifier', 'tag']
380  );
381 
382  $subject->remove('myIdentifier');
383 
384  // cache row with removed identifier has been removed, other one exists
385  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'myIdentifier']));
386  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'otherIdentifier']));
387 
388  // tags of myIdentifier should have been removed, others exist
389  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'myIdentifier']));
390  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'otherIdentifier']));
391  }
392 
397  {
398  $subject = $this->‪getSubjectObject();
399 
400  self::assertEquals(['idA' => 'idA'], $subject->findIdentifiersByTag('tagA'));
401  self::assertEquals(['idA' => 'idA', 'idB' => 'idB'], $subject->findIdentifiersByTag('tagB'));
402  self::assertEquals(['idB' => 'idB', 'idC' => 'idC'], $subject->findIdentifiersByTag('tagC'));
403  }
404 
413  {
414  $subject = $this->‪getSubjectObject(true);
415  $subject->flushByTag('tagB');
416  }
417 
426  {
427  $subject = $this->‪getSubjectObject(true);
428  $subject->flushByTags(['tagB']);
429  }
430 
439  {
440  $subject = $this->‪getSubjectObject(true);
441  $subject->flushByTag('tagB');
442 
443  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
444  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
445  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
446  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idC']));
447  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
448  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
449  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
450  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
451  }
452 
461  {
462  $subject = $this->‪getSubjectObject(true);
463  $subject->flushByTags(['tagC', 'tagD']);
464 
465  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
466  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
467  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
468  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idC']));
469  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
470  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
471  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
472  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
473  }
474 
479  {
480  $subject = $this->‪getSubjectObject(true, false);
481  $subject->flushByTag('tagB');
482  }
483 
488  {
489  $subject = $this->‪getSubjectObject(true, false);
490  $subject->flushByTags(['tagB', 'tagC']);
491  }
492 
497  {
498  $subject = $this->‪getSubjectObject(true, false);
499  $subject->flushByTag('tagB');
500 
501  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
502  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
503  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
504  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idC']));
505  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
506  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
507  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
508  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
509  }
510 
515  {
516  $subject = $this->‪getSubjectObject(true, false);
517  $subject->flushByTags(['tagC', 'tagD']);
518 
519  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
520  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
521  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
522  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idC']));
523  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
524  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
525  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
526  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
527  }
528 
536  public function ‪collectGarbageWorksWithEmptyTableWithMysql(): void
537  {
538  $subject = $this->‪getSubjectObject(true);
539  $subject->collectGarbage();
540  }
541 
550  {
551  $frontendProphecy = $this->prophesize(FrontendInterface::class);
552  $frontendProphecy->getIdentifier()->willReturn('pages');
553 
554  // Must be mocked here to test for "mysql" version implementation
555  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
556  ->onlyMethods(['isConnectionMysql'])
557  ->setConstructorArgs(['Testing'])
558  ->getMock();
559  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(true);
560  $subject->setCache($frontendProphecy->reveal());
561 
562  // idA should be expired after EXEC_TIME manipulation, idB should stay
563  $subject->set('idA', 'dataA', [], 60);
564  $subject->set('idB', 'dataB', [], 240);
565 
566  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
567 
568  $subject->collectGarbage();
569 
570  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
571  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
572  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
573  }
574 
583  {
584  $frontendProphecy = $this->prophesize(FrontendInterface::class);
585  $frontendProphecy->getIdentifier()->willReturn('pages');
586 
587  // Must be mocked here to test for "mysql" version implementation
588  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
589  ->onlyMethods(['isConnectionMysql'])
590  ->setConstructorArgs(['Testing'])
591  ->getMock();
592  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(true);
593  $subject->setCache($frontendProphecy->reveal());
594 
595  // tag rows tagA and tagB should be removed by garbage collector after EXEC_TIME manipulation
596  $subject->set('idA', 'dataA', ['tagA', 'tagB'], 60);
597  $subject->set('idB', 'dataB', ['tagB', 'tagC'], 240);
598 
599  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
600 
601  $subject->collectGarbage();
602 
603  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
604  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
605  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
606  }
607 
616  {
617  $frontendProphecy = $this->prophesize(FrontendInterface::class);
618  $frontendProphecy->getIdentifier()->willReturn('pages');
619 
620  // Must be mocked here to test for "mysql" version implementation
621  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
622  ->onlyMethods(['isConnectionMysql'])
623  ->setConstructorArgs(['Testing'])
624  ->getMock();
625  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(true);
626  $subject->setCache($frontendProphecy->reveal());
627 
628  // tag rows tagA and tagB should be removed by garbage collector after EXEC_TIME manipulation
629  $subject->set('idA', 'dataA', ['tagA', 'tagB'], 60);
630  $subject->set('idB', 'dataB', ['tagB', 'tagC'], 240);
631 
632  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
633 
634  // Push two orphaned tag row into db - tags that have no related cache record anymore for whatever reason
635  $tagsTableConnection->insert(
636  'cache_pages_tags',
637  [
638  'identifier' => 'idC',
639  'tag' => 'tagC',
640  ]
641  );
642  $tagsTableConnection->insert(
643  'cache_pages_tags',
644  [
645  'identifier' => 'idC',
646  'tag' => 'tagD',
647  ]
648  );
649 
650  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
651 
652  $subject->collectGarbage();
653 
654  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
655  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
656  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
657  }
658 
663  {
664  $frontendProphecy = $this->prophesize(FrontendInterface::class);
665  $frontendProphecy->getIdentifier()->willReturn('pages');
666 
667  // Must be mocked here to test for "mysql" version implementation
668  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
669  ->onlyMethods(['isConnectionMysql'])
670  ->setConstructorArgs(['Testing'])
671  ->getMock();
672  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(false);
673  $subject->setCache($frontendProphecy->reveal());
674 
675  $subject->collectGarbage();
676  }
677 
682  {
683  $frontendProphecy = $this->prophesize(FrontendInterface::class);
684  $frontendProphecy->getIdentifier()->willReturn('pages');
685 
686  // Must be mocked here to test for "mysql" version implementation
687  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
688  ->onlyMethods(['isConnectionMysql'])
689  ->setConstructorArgs(['Testing'])
690  ->getMock();
691  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(false);
692  $subject->setCache($frontendProphecy->reveal());
693 
694  // idA should be expired after EXEC_TIME manipulation, idB should stay
695  $subject->set('idA', 'dataA', [], 60);
696  $subject->set('idB', 'dataB', [], 240);
697 
698  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
699 
700  $subject->collectGarbage();
701 
702  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
703  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idA']));
704  self::assertSame(1, $cacheTableConnection->count('*', 'cache_pages', ['identifier' => 'idB']));
705  }
706 
711  {
712  $frontendProphecy = $this->prophesize(FrontendInterface::class);
713  $frontendProphecy->getIdentifier()->willReturn('pages');
714 
715  // Must be mocked here to test for "mysql" version implementation
716  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
717  ->onlyMethods(['isConnectionMysql'])
718  ->setConstructorArgs(['Testing'])
719  ->getMock();
720  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(false);
721  $subject->setCache($frontendProphecy->reveal());
722 
723  // tag rows tagA and tagB should be removed by garbage collector after EXEC_TIME manipulation
724  $subject->set('idA', 'dataA', ['tagA', 'tagB'], 60);
725  $subject->set('idB', 'dataB', ['tagB', 'tagC'], 240);
726 
727  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
728 
729  $subject->collectGarbage();
730 
731  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
732  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
733  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
734  }
735 
740  {
741  $frontendProphecy = $this->prophesize(FrontendInterface::class);
742  $frontendProphecy->getIdentifier()->willReturn('pages');
743 
744  // Must be mocked here to test for "mysql" version implementation
745  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
746  ->onlyMethods(['isConnectionMysql'])
747  ->setConstructorArgs(['Testing'])
748  ->getMock();
749  $subject->expects(self::once())->method('isConnectionMysql')->willReturn(false);
750  $subject->setCache($frontendProphecy->reveal());
751 
752  // tag rows tagA and tagB should be removed by garbage collector after EXEC_TIME manipulation
753  $subject->set('idA', 'dataA', ['tagA', 'tagB'], 60);
754  $subject->set('idB', 'dataB', ['tagB', 'tagC'], 240);
755 
756  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
757 
758  // Push two orphaned tag row into db - tags that have no related cache record anymore for whatever reason
759  $tagsTableConnection->insert(
760  'cache_pages_tags',
761  [
762  'identifier' => 'idC',
763  'tag' => 'tagC',
764  ]
765  );
766  $tagsTableConnection->insert(
767  'cache_pages_tags',
768  [
769  'identifier' => 'idC',
770  'tag' => 'tagD',
771  ]
772  );
773 
774  ‪$GLOBALS['EXEC_TIME'] = ‪$GLOBALS['EXEC_TIME'] + 120;
775 
776  $subject->collectGarbage();
777 
778  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idA']));
779  self::assertSame(2, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idB']));
780  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', ['identifier' => 'idC']));
781  }
782 
786  public function ‪flushLeavesCacheAndTagsTableEmpty(): void
787  {
788  $frontendProphecy = $this->prophesize(FrontendInterface::class);
789  $frontendProphecy->getIdentifier()->willReturn('pages');
790 
791  $subject = new ‪Typo3DatabaseBackend('Testing');
792  $subject->setCache($frontendProphecy->reveal());
793 
794  $subject->set('idA', 'dataA', ['tagA', 'tagB']);
795 
796  $subject->flush();
797 
798  $cacheTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages');
799  $tagsTableConnection = (new ‪ConnectionPool())->getConnectionForTable('cache_pages_tags');
800  self::assertSame(0, $cacheTableConnection->count('*', 'cache_pages', []));
801  self::assertSame(0, $tagsTableConnection->count('*', 'cache_pages_tags', []));
802  }
803 
810  protected function ‪getSubjectObject($returnMockObject = false, $isConnectionMysql = true): ‪Typo3DatabaseBackend
811  {
812  $frontendProphecy = $this->prophesize(FrontendInterface::class);
813  $frontendProphecy->getIdentifier()->willReturn('pages');
814 
815  if (!$returnMockObject) {
816  $subject = new ‪Typo3DatabaseBackend('Testing');
817  } else {
818  $subject = $this->getMockBuilder(Typo3DatabaseBackend::class)
819  ->onlyMethods(['isConnectionMysql'])
820  ->setConstructorArgs(['Testing'])
821  ->getMock();
822  $subject->expects(self::once())->method('isConnectionMysql')->willReturn($isConnectionMysql);
823  }
824  $subject->setCache($frontendProphecy->reveal());
825 
826  $subject->set('idA', 'dataA', ['tagA', 'tagB']);
827  $subject->set('idB', 'dataB', ['tagB', 'tagC']);
828  $subject->set('idC', 'dataC', ['tagC', 'tagD']);
829 
830  return $subject;
831  }
832 }
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsFalseIfNoCacheEntryExists
‪getReturnsFalseIfNoCacheEntryExists()
Definition: Typo3DatabaseBackendTest.php:112
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\hasReturnsNotExpiredCacheEntry
‪hasReturnsNotExpiredCacheEntry()
Definition: Typo3DatabaseBackendTest.php:279
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsNotExpiredCacheEntry
‪getReturnsNotExpiredCacheEntry()
Definition: Typo3DatabaseBackendTest.php:153
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend
Definition: MemcachedBackendTest.php:18
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\removeRemovesCorrectEntriesFromDatabase
‪removeRemovesCorrectEntriesFromDatabase()
Definition: Typo3DatabaseBackendTest.php:347
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesCacheEntryWithExpiredLifetimeWithNonMysql
‪collectGarbageRemovesCacheEntryWithExpiredLifetimeWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:680
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\findIdentifiersByTagReturnsIdentifierTaggedWithGivenTag
‪findIdentifiersByTagReturnsIdentifierTaggedWithGivenTag()
Definition: Typo3DatabaseBackendTest.php:395
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsEmptyStringUnzipped
‪getReturnsEmptyStringUnzipped()
Definition: Typo3DatabaseBackendTest.php:209
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagRemovesCorrectRowsFromDatabaseWithMysql
‪flushByTagRemovesCorrectRowsFromDatabaseWithMysql()
Definition: Typo3DatabaseBackendTest.php:437
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\removeReturnsFalseIfNoEntryHasBeenRemoved
‪removeReturnsFalseIfNoEntryHasBeenRemoved()
Definition: Typo3DatabaseBackendTest.php:306
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsUnzipsNotExpiredCacheEntry
‪getReturnsUnzipsNotExpiredCacheEntry()
Definition: Typo3DatabaseBackendTest.php:180
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsFalseForExpiredCacheEntry
‪getReturnsFalseForExpiredCacheEntry()
Definition: Typo3DatabaseBackendTest.php:126
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagWorksWithEmptyCacheTablesWithMysql
‪flushByTagWorksWithEmptyCacheTablesWithMysql()
Definition: Typo3DatabaseBackendTest.php:411
‪TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend
Definition: Typo3DatabaseBackend.php:30
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\hasReturnsFalseForExpiredCacheEntry
‪hasReturnsFalseForExpiredCacheEntry()
Definition: Typo3DatabaseBackendTest.php:252
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsPreviouslySetEntryWithNewContentIfSetWasCalledMultipleTimes
‪getReturnsPreviouslySetEntryWithNewContentIfSetWasCalledMultipleTimes()
Definition: Typo3DatabaseBackendTest.php:49
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagRemovesCorrectRowsFromDatabaseWithNonMysql
‪flushByTagRemovesCorrectRowsFromDatabaseWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:495
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesTagEntriesForCacheEntriesWithExpiredLifetimeWithMysql
‪collectGarbageRemovesTagEntriesForCacheEntriesWithExpiredLifetimeWithMysql()
Definition: Typo3DatabaseBackendTest.php:581
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagsRemovesCorrectRowsFromDatabaseWithNonMysql
‪flushByTagsRemovesCorrectRowsFromDatabaseWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:513
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getReturnsPreviouslySetEntry
‪getReturnsPreviouslySetEntry()
Definition: Typo3DatabaseBackendTest.php:34
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushLeavesCacheAndTagsTableEmpty
‪flushLeavesCacheAndTagsTableEmpty()
Definition: Typo3DatabaseBackendTest.php:785
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesCacheEntryWithExpiredLifetimeWithMysql
‪collectGarbageRemovesCacheEntryWithExpiredLifetimeWithMysql()
Definition: Typo3DatabaseBackendTest.php:548
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagsRemovesCorrectRowsFromDatabaseWithMysql
‪flushByTagsRemovesCorrectRowsFromDatabaseWithMysql()
Definition: Typo3DatabaseBackendTest.php:459
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\setInsertsDataWithTagsIntoCacheTable
‪setInsertsDataWithTagsIntoCacheTable()
Definition: Typo3DatabaseBackendTest.php:65
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagWorksWithEmptyCacheTablesWithNonMysql
‪flushByTagWorksWithEmptyCacheTablesWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:477
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesOrphanedTagEntriesFromTagsTableWithNonMysql
‪collectGarbageRemovesOrphanedTagEntriesFromTagsTableWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:738
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesTagEntriesForCacheEntriesWithExpiredLifetimeWithNonMysql
‪collectGarbageRemovesTagEntriesForCacheEntriesWithExpiredLifetimeWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:709
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\getSubjectObject
‪Typo3DatabaseBackend getSubjectObject($returnMockObject=false, $isConnectionMysql=true)
Definition: Typo3DatabaseBackendTest.php:809
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageWorksWithEmptyTableWithNonMysql
‪collectGarbageWorksWithEmptyTableWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:661
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagsWorksWithEmptyCacheTablesWithMysql
‪flushByTagsWorksWithEmptyCacheTablesWithMysql()
Definition: Typo3DatabaseBackendTest.php:424
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageRemovesOrphanedTagEntriesFromTagsTableWithMysql
‪collectGarbageRemovesOrphanedTagEntriesFromTagsTableWithMysql()
Definition: Typo3DatabaseBackendTest.php:614
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\collectGarbageWorksWithEmptyTableWithMysql
‪collectGarbageWorksWithEmptyTableWithMysql()
Definition: Typo3DatabaseBackendTest.php:535
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\setStoresCompressedContent
‪setStoresCompressedContent()
Definition: Typo3DatabaseBackendTest.php:85
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest
Definition: Typo3DatabaseBackendTest.php:30
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\flushByTagsWorksWithEmptyCacheTablesWithNonMysql
‪flushByTagsWorksWithEmptyCacheTablesWithNonMysql()
Definition: Typo3DatabaseBackendTest.php:486
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\hasReturnsFalseIfNoCacheEntryExists
‪hasReturnsFalseIfNoCacheEntryExists()
Definition: Typo3DatabaseBackendTest.php:238
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:59
‪TYPO3\CMS\Core\Tests\Functional\Cache\Backend\Typo3DatabaseBackendTest\removeReturnsTrueIfAnEntryHasBeenRemoved
‪removeReturnsTrueIfAnEntryHasBeenRemoved()
Definition: Typo3DatabaseBackendTest.php:320