From 65fd726e2cf51401bba4f0beb49ea37930bd31ad Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Thu, 15 Nov 2018 16:37:50 -0500 Subject: [PATCH] Remove Memcache, improve test coverage, fix bugs --- CHANGELOG.md | 5 + README.md | 5 +- build/header_comment.txt | 6 +- composer.json | 5 +- src/Driver/AbstractDriver.php | 28 +++- src/Driver/ApcuDriver.php | 19 +-- src/Driver/MemcacheDriver.php | 162 ------------------- src/Driver/MemcachedDriver.php | 12 +- src/Driver/NullDriver.php | 22 +-- src/Driver/RedisDriver.php | 24 +-- src/Item.php | 7 +- src/ItemCollection.php | 7 +- src/LoggerTrait.php | 4 +- src/Pool.php | 57 +++---- tests/Driver/DriverTestBase.php | 52 +++++- tests/Driver/MemcacheDriverTest.php | 39 ----- tests/ItemTest.php | 1 + tests/PoolTest.php | 243 ++++++++++++++++------------ 18 files changed, 274 insertions(+), 424 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 src/Driver/MemcacheDriver.php delete mode 100644 tests/Driver/MemcacheDriverTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1bdad32 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 2.0.0 +* Removed `Memcache` integration, as the extension does not seem to be maintained +* Increased required PHP version to 7.1 \ No newline at end of file diff --git a/README.md b/README.md index 9d4e777..e42c697 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ backends ## Cache Backends * Apcu -* Memcache * Memcached * Redis * Null - no persistence @@ -46,7 +45,7 @@ structure is like so: ```php 'null', // null, apcu, redis, memcache, memcached + 'driver' => 'null', // null, apcu, redis, memcached 'connection' => [ // Optional (For some drivers): // driver setup, see below for the structure for each @@ -62,7 +61,7 @@ $config = [ Below are the connection arrays for each backend: -Memcache / Memcached: +Memcached: ```php - * @copyright 2016 - 2017 Timothy J. Warren + * @copyright 2016 - 2018 Timothy J. Warren * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0.1 + * @version 2.0.0 * @link https://git.timshomepage.net/timw4mail/banker */ diff --git a/composer.json b/composer.json index 24b246b..69250ae 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,6 @@ "keywords": [ "cache", "redis", - "memcache", "memcached", "psr-6", "psr6" @@ -24,6 +23,8 @@ } }, "require": { + "php": "^7.1", + "ext-json": "*", "predis/predis": "^1.1", "psr/log": "^1.0", "psr/cache": "^1.0.1" @@ -42,7 +43,7 @@ }, "suggest": { "monolog/monolog": "A good standard logging library", - "ext-memcache": "Required for Memcache backend", + "ext-apcu": "Required for apcu driver", "ext-memcached": "Required for Memcached backend", "ext-phpiredis": "Improves speed of Redis driver" }, diff --git a/src/Driver/AbstractDriver.php b/src/Driver/AbstractDriver.php index 4fdc5d7..636ed18 100644 --- a/src/Driver/AbstractDriver.php +++ b/src/Driver/AbstractDriver.php @@ -25,13 +25,6 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface { use LoggerTrait; - /** - * The object encapsulating the connection to the cache backend - * - * @var mixed - */ - protected $conn; - /** * Data to be stored later * @@ -51,4 +44,25 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface { * Common destructor */ abstract public function __destruct(); + + /** + * Retrieve a set of values by their cache key + * + * @param string[] $keys + * @return array + */ + public function getMultiple(array $keys = []): array + { + $output = []; + + foreach ($keys as $key) + { + if ($this->exists($key)) + { + $output[$key] = $this->get($key); + } + } + + return $output; + } } \ No newline at end of file diff --git a/src/Driver/ApcuDriver.php b/src/Driver/ApcuDriver.php index abd2ccc..b3943f9 100644 --- a/src/Driver/ApcuDriver.php +++ b/src/Driver/ApcuDriver.php @@ -29,7 +29,7 @@ use Aviat\Banker\Exception\CacheException; * Memcached cache backend */ class ApcuDriver extends AbstractDriver { - + /** * Constructor * @@ -40,7 +40,7 @@ class ApcuDriver extends AbstractDriver { { // noop } - + /** * Destructor */ @@ -80,14 +80,7 @@ class ApcuDriver extends AbstractDriver { public function getMultiple(array $keys = []): array { $status = FALSE; - $output = apcu_fetch($keys, $status); - - if ($status === FALSE || !is_array($output)) - { - return []; - } - - return $output; + return apcu_fetch($keys, $status); } /** @@ -120,7 +113,7 @@ class ApcuDriver extends AbstractDriver { */ public function delete(string $key): bool { - return apcu_delete($key); + return (bool) apcu_delete($key); } /** @@ -131,7 +124,7 @@ class ApcuDriver extends AbstractDriver { */ public function deleteMultiple(array $keys = []): bool { - return apcu_delete($keys); + return (bool) apcu_delete($keys); } /** @@ -159,7 +152,7 @@ class ApcuDriver extends AbstractDriver { return apcu_store($key, $value, $expires); } - $this->getLogger()->warn("Tried to set expiration on a key that does not exist"); + $this->getLogger()->log('warning', 'Tried to set expiration on a key that does not exist'); return FALSE; } diff --git a/src/Driver/MemcacheDriver.php b/src/Driver/MemcacheDriver.php deleted file mode 100644 index 4666e37..0000000 --- a/src/Driver/MemcacheDriver.php +++ /dev/null @@ -1,162 +0,0 @@ - - * @copyright 2016 - 2017 Timothy J. Warren - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0.1 - * @link https://git.timshomepage.net/timw4mail/banker - */ -namespace Aviat\Banker\Driver; - -use Aviat\Banker\Exception\CacheException; -use Memcache; - -/** - * Redis cache backend - */ -class MemcacheDriver extends AbstractDriver { - - /** - * Driver for PHP Memcache extension - * - * @param array $config - * @param array $options - * @throws CacheException - */ - public function __construct(array $config = [], array $options = []) - { - if ( ! class_exists('Memcache')) - { - throw new CacheException('Memcache driver requires the PHP memcache extension'); - } - - $this->conn = new Memcache(); - - $method = ($config['persistent'] === TRUE) ? 'pconnect' : 'connect'; - - $this->conn->$method($config['host'], (int) $config['port']); - } - - /** - * Disconnect from memcached server - */ - public function __destruct() - { - $this->conn->close(); - } - - /** - * See if a key currently exists in the cache - * - * @param string $key - * @return bool - */ - public function exists(string $key): bool - { - return $this->conn->get($key) !== FALSE; - } - - /** - * Get the value for the selected cache key - * - * @param string $key - * @return mixed - */ - public function get(string $key) - { - return $this->conn->get($key); - } - - /** - * Retrieve a set of values by their cache key - * - * @param string[] $keys - * @return array - */ - public function getMultiple(array $keys = []): array - { - return $this->conn->get($keys); - } - - /** - * Set a cached value - * - * @param string $key - * @param mixed $value - * @param int $expires - * @return DriverInterface - */ - public function set(string $key, $value, int $expires = 0): DriverInterface - { - if ($this->exists($key)) - { - $this->conn->replace($key, $value, 0, $expires); - } - else - { - $this->conn->set($key, $value, 0, $expires); - } - - return $this; - } - - /** - * Remove an item from the cache - * - * @param string $key - * @return boolean - */ - public function delete(string $key): bool - { - return $this->conn->delete($key); - } - - /** - * Remove multiple items from the cache - * - * @param string[] $keys - * @return boolean - */ - public function deleteMultiple(array $keys = []): bool - { - // Iteratively delete each item, using a boolean - // 'and' operation to return false if any deletion fails - return \array_reduce($keys, function($prev, $key) { - return $prev && $this->conn->delete($key); - }, TRUE); - } - - /** - * Empty the cache - * - * @return boolean - */ - public function flush(): bool - { - return $this->conn->flush(); - } - - /** - * Set the specified key to expire at the given time - * - * @param string $key - * @param int $expires - * @return boolean - */ - public function expiresAt(string $key, int $expires): bool - { - $value = $this->get($key); - $timediff = $expires - time(); - - $this->set($key, $value, $timediff); - - return TRUE; - } -} \ No newline at end of file diff --git a/src/Driver/MemcachedDriver.php b/src/Driver/MemcachedDriver.php index a9348c2..162ef58 100644 --- a/src/Driver/MemcachedDriver.php +++ b/src/Driver/MemcachedDriver.php @@ -28,18 +28,19 @@ class MemcachedDriver extends AbstractDriver { /** * Driver for PHP Memcache extension * + * @codeCoverageIgnore * @param array $config * @param array $options * @throws CacheException */ public function __construct( - array $config = ['host' => '127.0.0.1', 'port' => '11211'], + array $config = ['host' => '127.0.0.1', 'port' => '11211'], array $options = [] ) { if ( ! class_exists('Memcached')) { - throw new CacheException("Memcached driver requires memcached extensions"); + throw new CacheException('Memcached driver requires memcached extension'); } try @@ -133,7 +134,7 @@ class MemcachedDriver extends AbstractDriver { */ public function delete(string $key): bool { - return $this->conn->delete($key); + return (bool) $this->conn->delete($key); } /** @@ -144,7 +145,8 @@ class MemcachedDriver extends AbstractDriver { */ public function deleteMultiple(array $keys = []): bool { - return $this->conn->deleteMulti($keys); + $deleted = $this->conn->deleteMulti($keys); + return ($keys <=> $deleted) === 0; } /** @@ -171,7 +173,7 @@ class MemcachedDriver extends AbstractDriver { return $this->conn->touch($key, $expires); } - $this->getLogger()->warn("Tried to set expiration on a key that does not exist"); + $this->getLogger()->log('warning','Tried to set expiration on a key that does not exist'); return FALSE; } diff --git a/src/Driver/NullDriver.php b/src/Driver/NullDriver.php index fc741ae..a4447d8 100644 --- a/src/Driver/NullDriver.php +++ b/src/Driver/NullDriver.php @@ -67,29 +67,11 @@ class NullDriver extends AbstractDriver { */ public function get(string $key) { - return ($this->exists($key)) + return $this->exists($key) ? $this->store[$key] : NULL; } - /** - * Retrieve a set of values by their cache key - * - * @param string[] $keys - * @return array - */ - public function getMultiple(array $keys = []): array - { - $output = []; - - foreach($keys as $key) - { - $output[$key] = $this->get($key); - } - - return $output; - } - /** * Set a cached value * @@ -155,6 +137,6 @@ class NullDriver extends AbstractDriver { public function expiresAt(string $key, int $expires): bool { //noop - return TRUE; + return array_key_exists($key, $this->store); } } \ No newline at end of file diff --git a/src/Driver/RedisDriver.php b/src/Driver/RedisDriver.php index e293c7f..8657391 100644 --- a/src/Driver/RedisDriver.php +++ b/src/Driver/RedisDriver.php @@ -15,7 +15,6 @@ */ namespace Aviat\Banker\Driver; -use Aviat\Banker\Exception\CacheException; use Predis\Client; /** @@ -33,6 +32,7 @@ class RedisDriver extends AbstractDriver { /** * RedisDriver constructor. * + * @codeCoverageIgnore * @param array $config * @param array $options - Predis library connection options * @throws CacheException @@ -78,24 +78,6 @@ class RedisDriver extends AbstractDriver { return unserialize($raw); } - /** - * Retrieve a set of values by their cache key - * - * @param string[] $keys - * @return array - */ - public function getMultiple(array $keys = []): array - { - $output = []; - - foreach($keys as $key) - { - $output[$key] = $this->get($key); - } - - return $output; - } - /** * Set a cached value * @@ -110,7 +92,7 @@ class RedisDriver extends AbstractDriver { if ($expires !== 0) { - $this->conn->set($key, $value, "EX", $expires); + $this->conn->set($key, $value, 'EX', $expires); } else { @@ -140,7 +122,7 @@ class RedisDriver extends AbstractDriver { public function deleteMultiple(array $keys = []): bool { $res = $this->conn->del(...$keys); - return $res === count($keys); + return $res === \count($keys); } /** diff --git a/src/Item.php b/src/Item.php index c4c0a6a..4aab05b 100644 --- a/src/Item.php +++ b/src/Item.php @@ -101,7 +101,7 @@ class Item implements CacheItemInterface { { if ($this->isHit()) { - return $this->driver->get($this->key); + return $this->value ?? $this->driver->get($this->key); } return NULL; @@ -118,7 +118,7 @@ class Item implements CacheItemInterface { */ public function isHit(): bool { - return $this->driver->exists($this->key); + return isset($this->value) || $this->driver->exists($this->key); } /** @@ -202,7 +202,8 @@ class Item implements CacheItemInterface { return $setResult && $expResult; } - else if ($this->ttl !== NULL && $this->ttl !== 0) + + if ($this->ttl !== NULL && $this->ttl !== 0) { return (bool) $this->driver->set($this->key, $this->value, $this->ttl); } diff --git a/src/ItemCollection.php b/src/ItemCollection.php index 735eb56..e45ba6e 100644 --- a/src/ItemCollection.php +++ b/src/ItemCollection.php @@ -17,13 +17,16 @@ namespace Aviat\Banker; use Psr\Cache\CacheItemInterface; +use ArrayIterator; +use JsonSerializable; + /** - * Collection of Psr\Cache\CacheItemIterface objects to be returned by getItems + * Collection of Psr\Cache\CacheItemInterface objects to be returned by getItems * * @see http://php.net/manual/en/class.arrayiterator.php * @see http://php.net/manual/en/class.jsonserializable.php */ -class ItemCollection extends \ArrayIterator implements \JsonSerializable { +class ItemCollection extends ArrayIterator implements JsonSerializable { /** * The raw CacheItemInterface objects diff --git a/src/LoggerTrait.php b/src/LoggerTrait.php index 81a0d1f..b725c75 100644 --- a/src/LoggerTrait.php +++ b/src/LoggerTrait.php @@ -35,7 +35,7 @@ trait LoggerTrait { * * @return LoggerInterface */ - protected function getLogger() + protected function getLogger(): LoggerInterface { if ($this->logger === NULL) { @@ -50,7 +50,7 @@ trait LoggerTrait { * @param LoggerInterface $logger * @return self */ - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): self { $this->logger = $logger; diff --git a/src/Pool.php b/src/Pool.php index 2abc35c..74f0d50 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -24,7 +24,7 @@ use Psr\Log\{LoggerAwareInterface, LoggerInterface}; /** * The main cache manager */ -class Pool implements CacheItemPoolInterface, LoggerAwareInterface { +final class Pool implements CacheItemPoolInterface, LoggerAwareInterface { use LoggerTrait; @@ -46,12 +46,13 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * Set up the cache backend * * @param array $config + * @param LoggerInterface $logger */ - public function __construct(array $config, LoggerInterface $logger = NULL) + public function __construct(array $config, ?LoggerInterface $logger = NULL) { $this->driver = $this->loadDriver($config); - if ( ! is_null($logger)) + if ($logger !== NULL) { $this->setLogger($logger); } @@ -75,7 +76,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { */ public function getItem($key): CacheItemInterface { - if ( ! is_string($key)) + if ( ! \is_string($key)) { throw new InvalidArgumentException(); } @@ -86,8 +87,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { return $this->deferred[$key]; } - $item = new Item($this->driver, $key); - return $item; + return new Item($this->driver, $key); } /** @@ -113,27 +113,18 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { return new ItemCollection([]); } + // Get the set of items selected + $items = []; foreach($keys as $key) { - if ( ! is_string($key)) + if ( ! \is_string($key)) { throw new InvalidArgumentException(); } - } - // Get the set of items selected - $items = []; - $rawItems = $this->driver->getMultiple($keys); - foreach($rawItems as $key => $val) - { - if (array_key_exists($key, $this->deferred)) - { - $items[$key] = $this->deferred[$key]; - } - else - { - $items[$key] = new Item($this->driver, $key); - } + $items[$key] = array_key_exists($key, $this->deferred) + ? $this->deferred[$key] + : new Item($this->driver, $key); } return new ItemCollection($items); @@ -156,9 +147,9 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * @return bool * True if item exists in the cache, false otherwise. */ - public function hasItem($key) + public function hasItem($key): bool { - if ( ! is_string($key)) + if ( ! \is_string($key)) { throw new InvalidArgumentException(); } @@ -198,7 +189,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { */ public function deleteItem($key): bool { - if ( ! is_string($key)) + if ( ! \is_string($key)) { throw new InvalidArgumentException(); } @@ -207,10 +198,8 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { { return FALSE; } - else - { - return $this->driver->delete($key); - } + + return $this->driver->delete($key); } /** @@ -230,7 +219,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { { foreach ($keys as $key) { - if ( ! is_string($key)) + if ( ! \is_string($key)) { throw new InvalidArgumentException(); } @@ -264,7 +253,9 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { */ public function saveDeferred(CacheItemInterface $item): bool { - $this->deferred[$item->getKey()] = $item; + $key = $item->getKey(); + $this->deferred[$key] = $item; + return TRUE; } @@ -302,11 +293,11 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface { * @param array $driverConfig * @return DriverInterface */ - protected function loadDriver(array $driverConfig): DriverInterface + protected function loadDriver(array $driverConfig = []): DriverInterface { - $driver = ucfirst(strtolower($driverConfig['driver'])); + $driver = ucfirst(strtolower($driverConfig['driver'] ?? 'null')); $class = __NAMESPACE__ . "\\Driver\\${driver}Driver"; - + $driverConfig['connection'] = $driverConfig['connection'] ?? []; $driverConfig['options'] = $driverConfig['options'] ?? []; diff --git a/tests/Driver/DriverTestBase.php b/tests/Driver/DriverTestBase.php index debcb3b..0415a91 100644 --- a/tests/Driver/DriverTestBase.php +++ b/tests/Driver/DriverTestBase.php @@ -21,14 +21,15 @@ class DriverTestBase extends TestCase { protected $driver; - public function tearDown() + public function tearDown(): void { $this->driver->__destruct(); } - public function testGetSet() + public function testGetSet(): void { $this->driver->set('foo', 'bar'); + $this->assertTrue($this->driver->exists('foo')); $this->assertEquals('bar', $this->driver->get('foo')); $bar = [ @@ -42,7 +43,13 @@ class DriverTestBase extends TestCase { $this->assertEquals($bar, $this->driver->get('bar')); } - public function testGetMultiple() + public function testGetMultipleOnBadKey(): void + { + $actual = $this->driver->getMultiple(['x','y']); + $this->assertEquals([], $actual); + } + + public function testGetMultiple(): void { $this->driver->set('foo', ['bar']); $this->driver->set('bar', (object) [ @@ -69,9 +76,46 @@ class DriverTestBase extends TestCase { $this->assertEquals($expected, $actual); } - public function testSetWithExpires() + public function testSetWithExpires(): void { $this->driver->set('foo', 'bar', 30); $this->assertEquals('bar', $this->driver->get('foo')); } + + public function testDelete(): void + { + $this->driver->set('a1', 'b2'); + $this->assertTrue($this->driver->exists('a1')); + + $this->assertTrue($this->driver->delete('a1')); + + $this->assertFalse($this->driver->exists('a1')); + } + + public function testDeleteMultiple(): void + { + $this->driver->set('a', 1); + $this->driver->set('b', 2); + + $this->assertTrue($this->driver->exists('a')); + $this->assertTrue($this->driver->exists('b')); + + /*$this->assertTrue(*/$this->driver->deleteMultiple(['a', 'b']);//); + + $this->assertFalse($this->driver->exists('a')); + $this->assertFalse($this->driver->exists('b')); + } + + public function testExpiresAt(): void + { + $this->driver->set('abc', 'def'); + $result = $this->driver->expiresAt('abc', 30); + $this->assertTrue($result); + } + + public function testExpiresAtBadKey(): void + { + $result = $this->driver->expiresAt('q', 30); + $this->assertFalse($result); + } } \ No newline at end of file diff --git a/tests/Driver/MemcacheDriverTest.php b/tests/Driver/MemcacheDriverTest.php deleted file mode 100644 index 2e5ab4e..0000000 --- a/tests/Driver/MemcacheDriverTest.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @copyright 2016 - 2017 Timothy J. Warren - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 1.0.1 - * @link https://git.timshomepage.net/timw4mail/banker - */ -namespace Aviat\Banker\Tests\Driver; - -use Aviat\Banker\Driver\MemcacheDriver; -use Aviat\Banker\Exception\CacheException; - -class MemcacheDriverTest extends DriverTestBase { - - public function setup() - { - try - { - $this->driver = new MemcacheDriver([ - 'host' => 'localhost', - 'port' => '11211', - 'persistent' => false, - ]); - $this->driver->flush(); - } - catch (CacheException $e) - { - $this->markTestSkipped(); - } - } -} diff --git a/tests/ItemTest.php b/tests/ItemTest.php index 451e7f2..d20633d 100644 --- a/tests/ItemTest.php +++ b/tests/ItemTest.php @@ -76,6 +76,7 @@ class ItemTest extends TestCase { $interval2 = 500; $this->item->expiresAfter($interval2); + $this->item->save(); $friend2 = new Friend($this->item); $this->assertEquals($interval2, $friend2->ttl); } diff --git a/tests/PoolTest.php b/tests/PoolTest.php index f988ea6..1c2de02 100644 --- a/tests/PoolTest.php +++ b/tests/PoolTest.php @@ -23,9 +23,9 @@ use PHPUnit\Framework\TestCase; use Psr\Log\{LoggerInterface, NullLogger}; class PoolTest extends TestCase { - + protected $pool; - + public function setUp() { $this->pool = new Pool([ @@ -33,141 +33,176 @@ class PoolTest extends TestCase { 'connection' => [] ]); } - - public function testGetDefaultLogger() + + public function testGetDefaultLogger(): void { $friend = new Friend($this->pool); $driverFriend = new Friend($friend->driver); - + // Check that a valid logger is set $this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set"); $this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set"); - + // Make sure we get the default Null logger $this->assertTrue(is_a($friend->getLogger(), NullLogger::class)); $this->assertTrue(is_a($driverFriend->getLogger(), NullLogger::class)); } - - public function testSetLoggerInConstructor() + + public function testSetLoggerInConstructor(): void { $logger = new Logger('test'); $logger->pushHandler(new SyslogHandler(Logger::WARNING)); - + $pool = new Pool([ 'driver' => 'null', 'connection' => [], ], $logger); - + $friend = new Friend($pool); $driverFriend = new Friend($friend->driver); - + // Check that a valid logger is set $this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set"); $this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set"); - - // Make sure we aren't just getting the default Null logger - $this->assertFalse(is_a($friend->getLogger(), NullLogger::class)); - $this->assertFalse(is_a($driverFriend->getLogger(), NullLogger::class)); - } - - public function testGetSetLogger() - { - $logger = new Logger('test'); - $logger->pushHandler(new SyslogHandler(Logger::WARNING)); - - $this->pool->setLogger($logger); - - $friend = new Friend($this->pool); - $driverFriend = new Friend($friend->driver); - - // Check that a valid logger is set - $this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set"); - $this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set"); - + // Make sure we aren't just getting the default Null logger $this->assertFalse(is_a($friend->getLogger(), NullLogger::class)); $this->assertFalse(is_a($driverFriend->getLogger(), NullLogger::class)); } - public function testGetItem() + public function testGetSetLogger(): void + { + $logger = new Logger('test'); + $logger->pushHandler(new SyslogHandler(Logger::WARNING)); + + $this->pool->setLogger($logger); + + $friend = new Friend($this->pool); + $driverFriend = new Friend($friend->driver); + + // Check that a valid logger is set + $this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being set"); + $this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set"); + + // Make sure we aren't just getting the default Null logger + $this->assertFalse(is_a($friend->getLogger(), NullLogger::class)); + $this->assertFalse(is_a($driverFriend->getLogger(), NullLogger::class)); + } + + public function testGetItem(): void { $item = $this->pool->getItem('foo'); $this->assertInstanceOf(Item::class, $item); } - - public function testItemBadKey() + + public function testItemBadKey(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("Cache key must be a string."); - + $this->expectExceptionMessage('Cache key must be a string.'); + $this->pool->getItem([]); } - - public function testGetItems() + + public function testGetItemsBadKey(): void + { + $this->expectException(InvalidArgumentException::class); + $this->pool->getItems([1,3,2]); + } + + public function testGetItems(): void { $collection = $this->pool->getItems(['foo', 'bar', 'baz']); $this->assertInstanceOf(ItemCollection::class, $collection); - + foreach($collection as $item) { $this->assertInstanceOf(Item::class, $item); } } - - public function testEmptyGetItems() + + public function testGetItemsDeferredItems(): void { - $collection = $this->pool->getItems(); - - $this->assertInstanceOf(ItemCollection::class, $collection); - $this->assertEquals(0, count($collection)); + $this->pool->clear(); + + $deferredValues = ['x' => 1, 'y' => 2, 'z' => 3]; + $keys = ['x', 'y', 'z']; + + foreach ($deferredValues as $key => $value) + { + $item = $this->pool->getItem($key)->set($value); + $this->pool->saveDeferred($item); + } + + $collection = $this->pool->getItems($keys); + + foreach($collection as $key => $item) + { + $this->assertSame($deferredValues[$key], $item->get()); + } + + $this->assertCount(3, $collection); } - - public function testHasItem() + + public function testEmptyGetItems(): void { + $this->pool->clear(); + + $collection = $this->pool->getItems(); + + $this->assertInstanceOf(ItemCollection::class, $collection); + $this->assertCount(0, $collection); + } + + public function testHasItem(): void + { + $this->pool->clear(); + // The key doesn't exist yet $this->assertFalse($this->pool->hasItem('foobar')); - + // Create the item $item = $this->pool->getItem('foobar') ->set('baz') ->save(); - + // The item exists now $this->assertTrue($this->pool->hasItem('foobar')); } - - public function testHasItemBadKey() + + public function testHasItemBadKey(): void { + $this->pool->clear(); + $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("Cache key must be a string."); - + $this->expectExceptionMessage('Cache key must be a string.'); + $this->pool->hasItem(34); } - - public function testClear() + + public function testClear(): void { // Call clear to make sure we are working from a clean slate to start $this->pool->clear(); - + $data = [ 'foo' => 'bar', 'bar' => 'baz', 'foobar' => 'foobarbaz' ]; - + // Set up some data $this->setupDataInCache($data); - + foreach($data as $key => $val) { $this->assertTrue($this->pool->hasItem($key)); $item = $this->pool->getItem($key); $this->assertEquals($val, $item->get()); } - + // Now we clear it all! $this->pool->clear(); - + foreach($data as $key => $val) { $this->assertFalse($this->pool->hasItem($key)); @@ -175,41 +210,41 @@ class PoolTest extends TestCase { $this->assertNull($item->get()); } } - - public function testDeleteItemBadKey() + + public function testDeleteItemBadKey(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage("Cache key must be a string."); - + $this->pool->deleteItem(34); } - - public function testDeleteItemThatDoesNotExist() + + public function testDeleteItemThatDoesNotExist(): void { $this->pool->clear(); $this->assertFalse($this->pool->deleteItem('foo')); } - - public function testDeleteItem() + + public function testDeleteItem(): void { // Start with a clean slate $this->pool->clear(); - + $data = [ 'foo' => 'bar', 'bar' => 'baz', 'foobar' => 'foobarbaz' ]; - + $this->setupDataInCache($data); - + $this->pool->deleteItem('foo'); - + // The item no longer exists $this->assertFalse($this->pool->hasItem('foo')); $item = $this->pool->getItem('foo'); $this->assertNull($item->get()); - + // The other items still exist foreach(['bar', 'foobar'] as $key) { @@ -218,21 +253,21 @@ class PoolTest extends TestCase { $this->assertFalse(is_null($item->get())); } } - - public function testDeleteItems() + + public function testDeleteItems(): void { $this->pool->clear(); - + $data = [ 'foo' => 'bar', 'bar' => 'baz', 'foobar' => 'foobarbaz' ]; - + $this->setupDataInCache($data); - + $this->pool->deleteItems(['foo', 'bar']); - + foreach(['foo', 'bar'] as $key) { $this->assertFalse($this->pool->hasItem($key)); @@ -240,58 +275,56 @@ class PoolTest extends TestCase { $this->assertNull($item->get()); } } - - public function testSaveDeferred() + + public function testSaveDeferred(): void { $this->pool->clear(); - + $data = [ 'foo' => 'bar', 'bar' => 'baz', 'foobar' => 'foobarbaz' ]; - + $this->setupDeferredData($data); - + // See that the data is returned by the pool foreach($data as $key => $val) { $this->assertTrue($this->pool->hasItem($key)); $item = $this->pool->getItem($key); - - // The cache hasn't been updated yet, even - // though the pool data has - $this->assertNotEquals($data[$key], $item->get()); + + // Since the value has been deferred, + // the pool will return the updated value, + // even though the cache hasn't been updated yet + $this->assertEquals($data[$key], $item->get()); } } - - public function testCommit() + + public function testCommit(): void { $this->pool->clear(); - + // If there are no deferred items, this will return true $this->assertTrue($this->pool->commit()); - + $data = [ 'foo' => 'bar', 'bar' => 'baz', 'foobar' => 'foobarbaz' ]; - + $this->setupDeferredData($data); - + // See that the data is returned by the pool foreach($this->pool->getItems(array_keys($data)) as $key => $item) { $this->assertTrue($this->pool->hasItem($key)); - - // The cache hasn't been updated yet, even - // though the pool data has - $this->assertNotEquals($data[$key], $item->get()); + $this->assertEquals($data[$key], $item->get()); } - + $this->pool->commit(); - + // See that the data is saved in the cache backend foreach($this->pool->getItems(array_keys($data)) as $key => $item) { @@ -299,25 +332,25 @@ class PoolTest extends TestCase { $this->assertEquals($data[$key], $item->get()); } } - - protected function setupDeferredData($data) + + protected function setupDeferredData($data): void { foreach($data as $key => $val) { $item = $this->pool->getItem($key) ->set($val); - + $this->assertTrue($this->pool->saveDeferred($item)); } } - - protected function setupDataInCache($data) + + protected function setupDataInCache($data): void { foreach($data as $key => $val) { $item = $this->pool->getItem($key) ->set($val); - + $this->pool->save($item); } }