bug #38635 [Cache] Use correct expiry in ChainAdapter (Nyholm)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Cache] Use correct expiry in ChainAdapter

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #38632
| License       | MIT
| Doc PR        | n/a

When we are syncing the chain, Let's use expiry if we have it. If not, fallback to defaultLifetime.

TODO:
- [x] Add tests

Commits
-------

17e0167798 [Cache] Use correct expiry in ChainAdapter
This commit is contained in:
Nicolas Grekas 2020-10-21 11:34:34 +02:00
commit 5a4be6841d
2 changed files with 52 additions and 1 deletions

View File

@ -73,7 +73,9 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$item->isHit = $sourceItem->isHit;
$item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata;
if (0 < $defaultLifetime) {
if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) {
$item->expiresAt(\DateTime::createFromFormat('U.u', $item->metadata[CacheItem::METADATA_EXPIRY]));
} elseif (0 < $defaultLifetime) {
$item->expiresAfter($defaultLifetime);
}

View File

@ -16,8 +16,10 @@ use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter;
use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter;
use Symfony\Contracts\Cache\ItemInterface;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
@ -34,6 +36,11 @@ class ChainAdapterTest extends AdapterTestCase
return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter($defaultLifetime), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime);
}
public static function tearDownAfterClass(): void
{
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
public function testEmptyAdaptersException()
{
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
@ -187,6 +194,48 @@ class ChainAdapterTest extends AdapterTestCase
$this->assertFalse($item->isHit());
}
public function testExpirationOnAllAdapters()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$itemValidator = function (CacheItem $item) {
$refl = new \ReflectionObject($item);
$propExpiry = $refl->getProperty('expiry');
$propExpiry->setAccessible(true);
$expiry = $propExpiry->getValue($item);
$this->assertGreaterThan(10, $expiry - time(), 'Item should be saved with the given ttl, not the default for the adapter.');
return true;
};
$adapter1 = $this->getMockBuilder(FilesystemAdapter::class)
->setConstructorArgs(['', 2])
->setMethods(['save'])
->getMock();
$adapter1->expects($this->once())
->method('save')
->with($this->callback($itemValidator))
->willReturn(true);
$adapter2 = $this->getMockBuilder(FilesystemAdapter::class)
->setConstructorArgs(['', 4])
->setMethods(['save'])
->getMock();
$adapter2->expects($this->once())
->method('save')
->with($this->callback($itemValidator))
->willReturn(true);
$cache = new ChainAdapter([$adapter1, $adapter2], 6);
$cache->get('test_key', function (ItemInterface $item) {
$item->expiresAfter(15);
return 'chain';
});
}
private function getPruneableMock(): AdapterInterface
{
$pruneable = $this->createMock(PrunableAdapter::class);