Remove Memcache, improve test coverage, fix bugs
Some checks failed
Gitea - aviat/banker/master There was a failure building this commit

This commit is contained in:
Timothy Warren 2018-11-15 16:37:50 -05:00
parent edea686f4c
commit 65fd726e2c
18 changed files with 274 additions and 424 deletions

5
CHANGELOG.md Normal file
View File

@ -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

View File

@ -8,7 +8,6 @@ backends
## Cache Backends ## Cache Backends
* Apcu * Apcu
* Memcache
* Memcached * Memcached
* Redis * Redis
* Null - no persistence * Null - no persistence
@ -46,7 +45,7 @@ structure is like so:
```php ```php
<?php <?php
$config = [ $config = [
'driver' => 'null', // null, apcu, redis, memcache, memcached 'driver' => 'null', // null, apcu, redis, memcached
'connection' => [ 'connection' => [
// Optional (For some drivers): // Optional (For some drivers):
// driver setup, see below for the structure for each // driver setup, see below for the structure for each
@ -62,7 +61,7 @@ $config = [
Below are the connection arrays for each backend: Below are the connection arrays for each backend:
Memcache / Memcached: Memcached:
```php ```php
<?php <?php
$config['connection'] = [ $config['connection'] = [

View File

@ -3,12 +3,12 @@
* *
* A Caching library implementing psr/cache * A Caching library implementing psr/cache
* *
* PHP version 7.0 * PHP version 7.1
* *
* @package Banker * @package Banker
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2016 - 2017 Timothy J. Warren * @copyright 2016 - 2018 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @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 * @link https://git.timshomepage.net/timw4mail/banker
*/ */

View File

@ -5,7 +5,6 @@
"keywords": [ "keywords": [
"cache", "cache",
"redis", "redis",
"memcache",
"memcached", "memcached",
"psr-6", "psr-6",
"psr6" "psr6"
@ -24,6 +23,8 @@
} }
}, },
"require": { "require": {
"php": "^7.1",
"ext-json": "*",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"psr/log": "^1.0", "psr/log": "^1.0",
"psr/cache": "^1.0.1" "psr/cache": "^1.0.1"
@ -42,7 +43,7 @@
}, },
"suggest": { "suggest": {
"monolog/monolog": "A good standard logging library", "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-memcached": "Required for Memcached backend",
"ext-phpiredis": "Improves speed of Redis driver" "ext-phpiredis": "Improves speed of Redis driver"
}, },

View File

@ -25,13 +25,6 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
use LoggerTrait; use LoggerTrait;
/**
* The object encapsulating the connection to the cache backend
*
* @var mixed
*/
protected $conn;
/** /**
* Data to be stored later * Data to be stored later
* *
@ -51,4 +44,25 @@ abstract class AbstractDriver implements DriverInterface, LoggerAwareInterface {
* Common destructor * Common destructor
*/ */
abstract public function __destruct(); 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;
}
} }

View File

@ -29,7 +29,7 @@ use Aviat\Banker\Exception\CacheException;
* Memcached cache backend * Memcached cache backend
*/ */
class ApcuDriver extends AbstractDriver { class ApcuDriver extends AbstractDriver {
/** /**
* Constructor * Constructor
* *
@ -40,7 +40,7 @@ class ApcuDriver extends AbstractDriver {
{ {
// noop // noop
} }
/** /**
* Destructor * Destructor
*/ */
@ -80,14 +80,7 @@ class ApcuDriver extends AbstractDriver {
public function getMultiple(array $keys = []): array public function getMultiple(array $keys = []): array
{ {
$status = FALSE; $status = FALSE;
$output = apcu_fetch($keys, $status); return apcu_fetch($keys, $status);
if ($status === FALSE || !is_array($output))
{
return [];
}
return $output;
} }
/** /**
@ -120,7 +113,7 @@ class ApcuDriver extends AbstractDriver {
*/ */
public function delete(string $key): bool 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 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); 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; return FALSE;
} }

View File

@ -1,162 +0,0 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache
*
* PHP version 7.0
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @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;
}
}

View File

@ -28,18 +28,19 @@ class MemcachedDriver extends AbstractDriver {
/** /**
* Driver for PHP Memcache extension * Driver for PHP Memcache extension
* *
* @codeCoverageIgnore
* @param array $config * @param array $config
* @param array $options * @param array $options
* @throws CacheException * @throws CacheException
*/ */
public function __construct( public function __construct(
array $config = ['host' => '127.0.0.1', 'port' => '11211'], array $config = ['host' => '127.0.0.1', 'port' => '11211'],
array $options = [] array $options = []
) )
{ {
if ( ! class_exists('Memcached')) if ( ! class_exists('Memcached'))
{ {
throw new CacheException("Memcached driver requires memcached extensions"); throw new CacheException('Memcached driver requires memcached extension');
} }
try try
@ -133,7 +134,7 @@ class MemcachedDriver extends AbstractDriver {
*/ */
public function delete(string $key): bool 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 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); 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; return FALSE;
} }

View File

@ -67,29 +67,11 @@ class NullDriver extends AbstractDriver {
*/ */
public function get(string $key) public function get(string $key)
{ {
return ($this->exists($key)) return $this->exists($key)
? $this->store[$key] ? $this->store[$key]
: NULL; : 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 * Set a cached value
* *
@ -155,6 +137,6 @@ class NullDriver extends AbstractDriver {
public function expiresAt(string $key, int $expires): bool public function expiresAt(string $key, int $expires): bool
{ {
//noop //noop
return TRUE; return array_key_exists($key, $this->store);
} }
} }

View File

@ -15,7 +15,6 @@
*/ */
namespace Aviat\Banker\Driver; namespace Aviat\Banker\Driver;
use Aviat\Banker\Exception\CacheException;
use Predis\Client; use Predis\Client;
/** /**
@ -33,6 +32,7 @@ class RedisDriver extends AbstractDriver {
/** /**
* RedisDriver constructor. * RedisDriver constructor.
* *
* @codeCoverageIgnore
* @param array $config * @param array $config
* @param array $options - Predis library connection options * @param array $options - Predis library connection options
* @throws CacheException * @throws CacheException
@ -78,24 +78,6 @@ class RedisDriver extends AbstractDriver {
return unserialize($raw); 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 * Set a cached value
* *
@ -110,7 +92,7 @@ class RedisDriver extends AbstractDriver {
if ($expires !== 0) if ($expires !== 0)
{ {
$this->conn->set($key, $value, "EX", $expires); $this->conn->set($key, $value, 'EX', $expires);
} }
else else
{ {
@ -140,7 +122,7 @@ class RedisDriver extends AbstractDriver {
public function deleteMultiple(array $keys = []): bool public function deleteMultiple(array $keys = []): bool
{ {
$res = $this->conn->del(...$keys); $res = $this->conn->del(...$keys);
return $res === count($keys); return $res === \count($keys);
} }
/** /**

View File

@ -101,7 +101,7 @@ class Item implements CacheItemInterface {
{ {
if ($this->isHit()) if ($this->isHit())
{ {
return $this->driver->get($this->key); return $this->value ?? $this->driver->get($this->key);
} }
return NULL; return NULL;
@ -118,7 +118,7 @@ class Item implements CacheItemInterface {
*/ */
public function isHit(): bool 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; 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); return (bool) $this->driver->set($this->key, $this->value, $this->ttl);
} }

View File

@ -17,13 +17,16 @@ namespace Aviat\Banker;
use Psr\Cache\CacheItemInterface; 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.arrayiterator.php
* @see http://php.net/manual/en/class.jsonserializable.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 * The raw CacheItemInterface objects

View File

@ -35,7 +35,7 @@ trait LoggerTrait {
* *
* @return LoggerInterface * @return LoggerInterface
*/ */
protected function getLogger() protected function getLogger(): LoggerInterface
{ {
if ($this->logger === NULL) if ($this->logger === NULL)
{ {
@ -50,7 +50,7 @@ trait LoggerTrait {
* @param LoggerInterface $logger * @param LoggerInterface $logger
* @return self * @return self
*/ */
public function setLogger(LoggerInterface $logger) public function setLogger(LoggerInterface $logger): self
{ {
$this->logger = $logger; $this->logger = $logger;

View File

@ -24,7 +24,7 @@ use Psr\Log\{LoggerAwareInterface, LoggerInterface};
/** /**
* The main cache manager * The main cache manager
*/ */
class Pool implements CacheItemPoolInterface, LoggerAwareInterface { final class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
use LoggerTrait; use LoggerTrait;
@ -46,12 +46,13 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* Set up the cache backend * Set up the cache backend
* *
* @param array $config * @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); $this->driver = $this->loadDriver($config);
if ( ! is_null($logger)) if ($logger !== NULL)
{ {
$this->setLogger($logger); $this->setLogger($logger);
} }
@ -75,7 +76,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function getItem($key): CacheItemInterface public function getItem($key): CacheItemInterface
{ {
if ( ! is_string($key)) if ( ! \is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -86,8 +87,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
return $this->deferred[$key]; return $this->deferred[$key];
} }
$item = new Item($this->driver, $key); return new Item($this->driver, $key);
return $item;
} }
/** /**
@ -113,27 +113,18 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
return new ItemCollection([]); return new ItemCollection([]);
} }
// Get the set of items selected
$items = [];
foreach($keys as $key) foreach($keys as $key)
{ {
if ( ! is_string($key)) if ( ! \is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
}
// Get the set of items selected $items[$key] = array_key_exists($key, $this->deferred)
$items = []; ? $this->deferred[$key]
$rawItems = $this->driver->getMultiple($keys); : new Item($this->driver, $key);
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);
}
} }
return new ItemCollection($items); return new ItemCollection($items);
@ -156,9 +147,9 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @return bool * @return bool
* True if item exists in the cache, false otherwise. * 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(); throw new InvalidArgumentException();
} }
@ -198,7 +189,7 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function deleteItem($key): bool public function deleteItem($key): bool
{ {
if ( ! is_string($key)) if ( ! \is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -207,10 +198,8 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
{ {
return FALSE; 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) foreach ($keys as $key)
{ {
if ( ! is_string($key)) if ( ! \is_string($key))
{ {
throw new InvalidArgumentException(); throw new InvalidArgumentException();
} }
@ -264,7 +253,9 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
*/ */
public function saveDeferred(CacheItemInterface $item): bool public function saveDeferred(CacheItemInterface $item): bool
{ {
$this->deferred[$item->getKey()] = $item; $key = $item->getKey();
$this->deferred[$key] = $item;
return TRUE; return TRUE;
} }
@ -302,11 +293,11 @@ class Pool implements CacheItemPoolInterface, LoggerAwareInterface {
* @param array $driverConfig * @param array $driverConfig
* @return DriverInterface * @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"; $class = __NAMESPACE__ . "\\Driver\\${driver}Driver";
$driverConfig['connection'] = $driverConfig['connection'] ?? []; $driverConfig['connection'] = $driverConfig['connection'] ?? [];
$driverConfig['options'] = $driverConfig['options'] ?? []; $driverConfig['options'] = $driverConfig['options'] ?? [];

View File

@ -21,14 +21,15 @@ class DriverTestBase extends TestCase {
protected $driver; protected $driver;
public function tearDown() public function tearDown(): void
{ {
$this->driver->__destruct(); $this->driver->__destruct();
} }
public function testGetSet() public function testGetSet(): void
{ {
$this->driver->set('foo', 'bar'); $this->driver->set('foo', 'bar');
$this->assertTrue($this->driver->exists('foo'));
$this->assertEquals('bar', $this->driver->get('foo')); $this->assertEquals('bar', $this->driver->get('foo'));
$bar = [ $bar = [
@ -42,7 +43,13 @@ class DriverTestBase extends TestCase {
$this->assertEquals($bar, $this->driver->get('bar')); $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('foo', ['bar']);
$this->driver->set('bar', (object) [ $this->driver->set('bar', (object) [
@ -69,9 +76,46 @@ class DriverTestBase extends TestCase {
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }
public function testSetWithExpires() public function testSetWithExpires(): void
{ {
$this->driver->set('foo', 'bar', 30); $this->driver->set('foo', 'bar', 30);
$this->assertEquals('bar', $this->driver->get('foo')); $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);
}
} }

View File

@ -1,39 +0,0 @@
<?php declare(strict_types=1);
/**
* Banker
*
* A Caching library implementing psr/cache
*
* PHP version 7.0
*
* @package Banker
* @author Timothy J. Warren <tim@timshomepage.net>
* @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();
}
}
}

View File

@ -76,6 +76,7 @@ class ItemTest extends TestCase {
$interval2 = 500; $interval2 = 500;
$this->item->expiresAfter($interval2); $this->item->expiresAfter($interval2);
$this->item->save();
$friend2 = new Friend($this->item); $friend2 = new Friend($this->item);
$this->assertEquals($interval2, $friend2->ttl); $this->assertEquals($interval2, $friend2->ttl);
} }

View File

@ -23,9 +23,9 @@ use PHPUnit\Framework\TestCase;
use Psr\Log\{LoggerInterface, NullLogger}; use Psr\Log\{LoggerInterface, NullLogger};
class PoolTest extends TestCase { class PoolTest extends TestCase {
protected $pool; protected $pool;
public function setUp() public function setUp()
{ {
$this->pool = new Pool([ $this->pool = new Pool([
@ -33,141 +33,176 @@ class PoolTest extends TestCase {
'connection' => [] 'connection' => []
]); ]);
} }
public function testGetDefaultLogger() public function testGetDefaultLogger(): void
{ {
$friend = new Friend($this->pool); $friend = new Friend($this->pool);
$driverFriend = new Friend($friend->driver); $driverFriend = new Friend($friend->driver);
// Check that a valid logger is set // Check that a valid logger is set
$this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being 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"); $this->assertInstanceOf(LoggerInterface::class, $driverFriend->getLogger(), "Logger exists on driver after being set");
// Make sure we get the default Null logger // Make sure we get the default Null logger
$this->assertTrue(is_a($friend->getLogger(), NullLogger::class)); $this->assertTrue(is_a($friend->getLogger(), NullLogger::class));
$this->assertTrue(is_a($driverFriend->getLogger(), NullLogger::class)); $this->assertTrue(is_a($driverFriend->getLogger(), NullLogger::class));
} }
public function testSetLoggerInConstructor() public function testSetLoggerInConstructor(): void
{ {
$logger = new Logger('test'); $logger = new Logger('test');
$logger->pushHandler(new SyslogHandler(Logger::WARNING)); $logger->pushHandler(new SyslogHandler(Logger::WARNING));
$pool = new Pool([ $pool = new Pool([
'driver' => 'null', 'driver' => 'null',
'connection' => [], 'connection' => [],
], $logger); ], $logger);
$friend = new Friend($pool); $friend = new Friend($pool);
$driverFriend = new Friend($friend->driver); $driverFriend = new Friend($friend->driver);
// Check that a valid logger is set // Check that a valid logger is set
$this->assertInstanceOf(LoggerInterface::class, $friend->getLogger(), "Logger exists after being 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"); $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 // Make sure we aren't just getting the default Null logger
$this->assertFalse(is_a($friend->getLogger(), NullLogger::class)); $this->assertFalse(is_a($friend->getLogger(), NullLogger::class));
$this->assertFalse(is_a($driverFriend->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'); $item = $this->pool->getItem('foo');
$this->assertInstanceOf(Item::class, $item); $this->assertInstanceOf(Item::class, $item);
} }
public function testItemBadKey() public function testItemBadKey(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Cache key must be a string."); $this->expectExceptionMessage('Cache key must be a string.');
$this->pool->getItem([]); $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']); $collection = $this->pool->getItems(['foo', 'bar', 'baz']);
$this->assertInstanceOf(ItemCollection::class, $collection); $this->assertInstanceOf(ItemCollection::class, $collection);
foreach($collection as $item) foreach($collection as $item)
{ {
$this->assertInstanceOf(Item::class, $item); $this->assertInstanceOf(Item::class, $item);
} }
} }
public function testEmptyGetItems() public function testGetItemsDeferredItems(): void
{ {
$collection = $this->pool->getItems(); $this->pool->clear();
$this->assertInstanceOf(ItemCollection::class, $collection); $deferredValues = ['x' => 1, 'y' => 2, 'z' => 3];
$this->assertEquals(0, count($collection)); $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 // The key doesn't exist yet
$this->assertFalse($this->pool->hasItem('foobar')); $this->assertFalse($this->pool->hasItem('foobar'));
// Create the item // Create the item
$item = $this->pool->getItem('foobar') $item = $this->pool->getItem('foobar')
->set('baz') ->set('baz')
->save(); ->save();
// The item exists now // The item exists now
$this->assertTrue($this->pool->hasItem('foobar')); $this->assertTrue($this->pool->hasItem('foobar'));
} }
public function testHasItemBadKey() public function testHasItemBadKey(): void
{ {
$this->pool->clear();
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Cache key must be a string."); $this->expectExceptionMessage('Cache key must be a string.');
$this->pool->hasItem(34); $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 // Call clear to make sure we are working from a clean slate to start
$this->pool->clear(); $this->pool->clear();
$data = [ $data = [
'foo' => 'bar', 'foo' => 'bar',
'bar' => 'baz', 'bar' => 'baz',
'foobar' => 'foobarbaz' 'foobar' => 'foobarbaz'
]; ];
// Set up some data // Set up some data
$this->setupDataInCache($data); $this->setupDataInCache($data);
foreach($data as $key => $val) foreach($data as $key => $val)
{ {
$this->assertTrue($this->pool->hasItem($key)); $this->assertTrue($this->pool->hasItem($key));
$item = $this->pool->getItem($key); $item = $this->pool->getItem($key);
$this->assertEquals($val, $item->get()); $this->assertEquals($val, $item->get());
} }
// Now we clear it all! // Now we clear it all!
$this->pool->clear(); $this->pool->clear();
foreach($data as $key => $val) foreach($data as $key => $val)
{ {
$this->assertFalse($this->pool->hasItem($key)); $this->assertFalse($this->pool->hasItem($key));
@ -175,41 +210,41 @@ class PoolTest extends TestCase {
$this->assertNull($item->get()); $this->assertNull($item->get());
} }
} }
public function testDeleteItemBadKey() public function testDeleteItemBadKey(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Cache key must be a string."); $this->expectExceptionMessage("Cache key must be a string.");
$this->pool->deleteItem(34); $this->pool->deleteItem(34);
} }
public function testDeleteItemThatDoesNotExist() public function testDeleteItemThatDoesNotExist(): void
{ {
$this->pool->clear(); $this->pool->clear();
$this->assertFalse($this->pool->deleteItem('foo')); $this->assertFalse($this->pool->deleteItem('foo'));
} }
public function testDeleteItem() public function testDeleteItem(): void
{ {
// Start with a clean slate // Start with a clean slate
$this->pool->clear(); $this->pool->clear();
$data = [ $data = [
'foo' => 'bar', 'foo' => 'bar',
'bar' => 'baz', 'bar' => 'baz',
'foobar' => 'foobarbaz' 'foobar' => 'foobarbaz'
]; ];
$this->setupDataInCache($data); $this->setupDataInCache($data);
$this->pool->deleteItem('foo'); $this->pool->deleteItem('foo');
// The item no longer exists // The item no longer exists
$this->assertFalse($this->pool->hasItem('foo')); $this->assertFalse($this->pool->hasItem('foo'));
$item = $this->pool->getItem('foo'); $item = $this->pool->getItem('foo');
$this->assertNull($item->get()); $this->assertNull($item->get());
// The other items still exist // The other items still exist
foreach(['bar', 'foobar'] as $key) foreach(['bar', 'foobar'] as $key)
{ {
@ -218,21 +253,21 @@ class PoolTest extends TestCase {
$this->assertFalse(is_null($item->get())); $this->assertFalse(is_null($item->get()));
} }
} }
public function testDeleteItems() public function testDeleteItems(): void
{ {
$this->pool->clear(); $this->pool->clear();
$data = [ $data = [
'foo' => 'bar', 'foo' => 'bar',
'bar' => 'baz', 'bar' => 'baz',
'foobar' => 'foobarbaz' 'foobar' => 'foobarbaz'
]; ];
$this->setupDataInCache($data); $this->setupDataInCache($data);
$this->pool->deleteItems(['foo', 'bar']); $this->pool->deleteItems(['foo', 'bar']);
foreach(['foo', 'bar'] as $key) foreach(['foo', 'bar'] as $key)
{ {
$this->assertFalse($this->pool->hasItem($key)); $this->assertFalse($this->pool->hasItem($key));
@ -240,58 +275,56 @@ class PoolTest extends TestCase {
$this->assertNull($item->get()); $this->assertNull($item->get());
} }
} }
public function testSaveDeferred() public function testSaveDeferred(): void
{ {
$this->pool->clear(); $this->pool->clear();
$data = [ $data = [
'foo' => 'bar', 'foo' => 'bar',
'bar' => 'baz', 'bar' => 'baz',
'foobar' => 'foobarbaz' 'foobar' => 'foobarbaz'
]; ];
$this->setupDeferredData($data); $this->setupDeferredData($data);
// See that the data is returned by the pool // See that the data is returned by the pool
foreach($data as $key => $val) foreach($data as $key => $val)
{ {
$this->assertTrue($this->pool->hasItem($key)); $this->assertTrue($this->pool->hasItem($key));
$item = $this->pool->getItem($key); $item = $this->pool->getItem($key);
// The cache hasn't been updated yet, even // Since the value has been deferred,
// though the pool data has // the pool will return the updated value,
$this->assertNotEquals($data[$key], $item->get()); // 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(); $this->pool->clear();
// If there are no deferred items, this will return true // If there are no deferred items, this will return true
$this->assertTrue($this->pool->commit()); $this->assertTrue($this->pool->commit());
$data = [ $data = [
'foo' => 'bar', 'foo' => 'bar',
'bar' => 'baz', 'bar' => 'baz',
'foobar' => 'foobarbaz' 'foobar' => 'foobarbaz'
]; ];
$this->setupDeferredData($data); $this->setupDeferredData($data);
// See that the data is returned by the pool // See that the data is returned by the pool
foreach($this->pool->getItems(array_keys($data)) as $key => $item) foreach($this->pool->getItems(array_keys($data)) as $key => $item)
{ {
$this->assertTrue($this->pool->hasItem($key)); $this->assertTrue($this->pool->hasItem($key));
$this->assertEquals($data[$key], $item->get());
// The cache hasn't been updated yet, even
// though the pool data has
$this->assertNotEquals($data[$key], $item->get());
} }
$this->pool->commit(); $this->pool->commit();
// See that the data is saved in the cache backend // See that the data is saved in the cache backend
foreach($this->pool->getItems(array_keys($data)) as $key => $item) foreach($this->pool->getItems(array_keys($data)) as $key => $item)
{ {
@ -299,25 +332,25 @@ class PoolTest extends TestCase {
$this->assertEquals($data[$key], $item->get()); $this->assertEquals($data[$key], $item->get());
} }
} }
protected function setupDeferredData($data) protected function setupDeferredData($data): void
{ {
foreach($data as $key => $val) foreach($data as $key => $val)
{ {
$item = $this->pool->getItem($key) $item = $this->pool->getItem($key)
->set($val); ->set($val);
$this->assertTrue($this->pool->saveDeferred($item)); $this->assertTrue($this->pool->saveDeferred($item));
} }
} }
protected function setupDataInCache($data) protected function setupDataInCache($data): void
{ {
foreach($data as $key => $val) foreach($data as $key => $val)
{ {
$item = $this->pool->getItem($key) $item = $this->pool->getItem($key)
->set($val); ->set($val);
$this->pool->save($item); $this->pool->save($item);
} }
} }