diff --git a/bin/auth_ejabberd.php b/bin/auth_ejabberd.php index a097febbc..206e48447 100755 --- a/bin/auth_ejabberd.php +++ b/bin/auth_ejabberd.php @@ -32,6 +32,7 @@ * */ +use Dice\Dice; use Friendica\App\Mode; use Friendica\BaseObject; use Friendica\Util\ExAuth; @@ -52,8 +53,7 @@ chdir($directory); require dirname(__DIR__) . '/vendor/autoload.php'; -$dice = new \Dice\Dice(); -$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php'); +$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); BaseObject::setDependencyInjection($dice); $appMode = $dice->create(Mode::class); diff --git a/bin/console.php b/bin/console.php index 3a64d1d2a..4c396854d 100755 --- a/bin/console.php +++ b/bin/console.php @@ -1,9 +1,10 @@ #!/usr/bin/env php addRules(include __DIR__ . '/../static/dependencies.config.php'); +$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); (new Friendica\Core\Console($dice, $argv))->execute(); diff --git a/bin/daemon.php b/bin/daemon.php index ac6385cbb..8ea60fa9a 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -7,6 +7,7 @@ * This script was taken from http://php.net/manual/en/function.pcntl-fork.php */ +use Dice\Dice; use Friendica\Core\Config; use Friendica\Core\Logger; use Friendica\Core\Worker; @@ -31,8 +32,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; -$dice = new \Dice\Dice(); -$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php'); +$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); \Friendica\BaseObject::setDependencyInjection($dice); $a = \Friendica\BaseObject::getApp(); diff --git a/bin/worker.php b/bin/worker.php index e630ee234..f6b2d90a5 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -5,7 +5,9 @@ * @brief Starts the background processing */ +use Dice\Dice; use Friendica\App; +use Friendica\BaseObject; use Friendica\Core\Config; use Friendica\Core\Update; use Friendica\Core\Worker; @@ -29,11 +31,10 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; -$dice = new \Dice\Dice(); -$dice = $dice->addRules(include __DIR__ . '/../static/dependencies.config.php'); +$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -\Friendica\BaseObject::setDependencyInjection($dice); -$a = \Friendica\BaseObject::getApp(); +BaseObject::setDependencyInjection($dice); +$a = BaseObject::getApp(); // Check the database structure and possibly fixes it Update::check($a->getBasePath(), true, $a->getMode()); diff --git a/index.php b/index.php index 3e5609708..50e553bcd 100644 --- a/index.php +++ b/index.php @@ -4,14 +4,15 @@ * Friendica */ +use Dice\Dice; + if (!file_exists(__DIR__ . '/vendor/autoload.php')) { die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.'); } require __DIR__ . '/vendor/autoload.php'; -$dice = new \Dice\Dice(); -$dice = $dice->addRules(include __DIR__ . '/static/dependencies.config.php'); +$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php'); \Friendica\BaseObject::setDependencyInjection($dice); diff --git a/src/Console/Cache.php b/src/Console/Cache.php index e2e1dba6c..afb549f4d 100644 --- a/src/Console/Cache.php +++ b/src/Console/Cache.php @@ -4,7 +4,8 @@ namespace Friendica\Console; use Asika\SimpleConsole\CommandArgsException; use Friendica\App; -use Friendica\Core; +use Friendica\Core\Cache\Cache as CacheClass; +use Friendica\Core\Cache\ICache; use RuntimeException; /** @@ -25,6 +26,11 @@ class Cache extends \Asika\SimpleConsole\Console */ private $appMode; + /** + * @var ICache + */ + private $cache; + protected function getHelp() { $help = <<appMode = $appMode; + $this->cache = $cache; } protected function doExecute() @@ -79,11 +86,9 @@ HELP; $this->out('Database isn\'t ready or populated yet, database cache won\'t be available'); } - Core\Cache::init(); - if ($this->getOption('v')) { - $this->out('Cache Driver Name: ' . Core\Cache::$driver_name); - $this->out('Cache Driver Class: ' . Core\Cache::$driver_class); + $this->out('Cache Driver Name: ' . $this->cache->getName()); + $this->out('Cache Driver Class: ' . get_class($this->cache)); } switch ($this->getArgument(0)) { @@ -115,7 +120,7 @@ HELP; private function executeList() { $prefix = $this->getArgument(1); - $keys = Core\Cache::getAllKeys($prefix); + $keys = $this->cache->getAllKeys($prefix); if (empty($prefix)) { $this->out('Listing all cache keys:'); @@ -135,8 +140,8 @@ HELP; private function executeGet() { if (count($this->args) >= 2) { - $key = $this->getArgument(1); - $value = Core\Cache::get($key); + $key = $this->getArgument(1); + $value = $this->cache->get($key); $this->out("{$key} => " . var_export($value, true)); } else { @@ -147,17 +152,17 @@ HELP; private function executeSet() { if (count($this->args) >= 3) { - $key = $this->getArgument(1); - $value = $this->getArgument(2); - $duration = intval($this->getArgument(3, Core\Cache::FIVE_MINUTES)); + $key = $this->getArgument(1); + $value = $this->getArgument(2); + $duration = intval($this->getArgument(3, CacheClass::FIVE_MINUTES)); - if (is_array(Core\Cache::get($key))) { + if (is_array($this->cache->get($key))) { throw new RuntimeException("$key is an array and can't be set using this command."); } - $result = Core\Cache::set($key, $value, $duration); + $result = $this->cache->set($key, $value, $duration); if ($result) { - $this->out("{$key} <= " . Core\Cache::get($key)); + $this->out("{$key} <= " . $this->cache->get($key)); } else { $this->out("Unable to set {$key}"); } @@ -168,7 +173,7 @@ HELP; private function executeFlush() { - $result = Core\Cache::clear(); + $result = $this->cache->clear(); if ($result) { $this->out('Cache successfully flushed'); } else { @@ -178,7 +183,7 @@ HELP; private function executeClear() { - $result = Core\Cache::clear(false); + $result = $this->cache->clear(false); if ($result) { $this->out('Cache successfully cleared'); } else { diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 7a8f7367e..7a952ff8a 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -4,50 +4,33 @@ */ namespace Friendica\Core; -use Friendica\Factory\CacheDriverFactory; +use Friendica\BaseObject; +use Friendica\Core\Cache\Cache as CacheClass; +use Friendica\Core\Cache\ICache; /** * @brief Class for storing data for a short time */ -class Cache extends \Friendica\BaseObject +class Cache extends BaseObject { - const MONTH = 2592000; - const WEEK = 604800; - const DAY = 86400; - const HOUR = 3600; - const HALF_HOUR = 1800; - const QUARTER_HOUR = 900; - const FIVE_MINUTES = 300; - const MINUTE = 60; - const INFINITE = 0; - - /** - * @var Cache\ICacheDriver - */ - private static $driver = null; - public static $driver_class = null; - public static $driver_name = null; - - public static function init() - { - self::$driver_name = Config::get('system', 'cache_driver', 'database'); - self::$driver = CacheDriverFactory::create(self::$driver_name); - self::$driver_class = get_class(self::$driver); - } - - /** - * Returns the current cache driver - * - * @return Cache\ICacheDriver - */ - private static function getDriver() - { - if (self::$driver === null) { - self::init(); - } - - return self::$driver; - } + /** @deprecated Use CacheClass::MONTH */ + const MONTH = CacheClass::MONTH; + /** @deprecated Use CacheClass::WEEK */ + const WEEK = CacheClass::WEEK; + /** @deprecated Use CacheClass::DAY */ + const DAY = CacheClass::DAY; + /** @deprecated Use CacheClass::HOUR */ + const HOUR = CacheClass::HOUR; + /** @deprecated Use CacheClass::HALF_HOUR */ + const HALF_HOUR = CacheClass::HALF_HOUR; + /** @deprecated Use CacheClass::QUARTER_HOUR */ + const QUARTER_HOUR = CacheClass::QUARTER_HOUR; + /** @deprecated Use CacheClass::FIVE_MINUTES */ + const FIVE_MINUTES = CacheClass::FIVE_MINUTES; + /** @deprecated Use CacheClass::MINUTE */ + const MINUTE = CacheClass::MINUTE; + /** @deprecated Use CacheClass::INFINITE */ + const INFINITE = CacheClass::INFINITE; /** * @brief Returns all the cache keys sorted alphabetically @@ -59,13 +42,7 @@ class Cache extends \Friendica\BaseObject */ public static function getAllKeys($prefix = null) { - $time = microtime(true); - - $return = self::getDriver()->getAllKeys($prefix); - - self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack()); - - return $return; + return self::getClass(ICache::class)->getAllKeys($prefix); } /** @@ -78,13 +55,7 @@ class Cache extends \Friendica\BaseObject */ public static function get($key) { - $time = microtime(true); - - $return = self::getDriver()->get($key); - - self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack()); - - return $return; + return self::getClass(ICache::class)->get($key); } /** @@ -99,15 +70,9 @@ class Cache extends \Friendica\BaseObject * @return bool * @throws \Exception */ - public static function set($key, $value, $duration = self::MONTH) + public static function set($key, $value, $duration = CacheClass::MONTH) { - $time = microtime(true); - - $return = self::getDriver()->set($key, $value, $duration); - - self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack()); - - return $return; + return self::getClass(ICache::class)->set($key, $value, $duration); } /** @@ -120,13 +85,7 @@ class Cache extends \Friendica\BaseObject */ public static function delete($key) { - $time = microtime(true); - - $return = self::getDriver()->delete($key); - - self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack()); - - return $return; + return self::getClass(ICache::class)->delete($key); } /** @@ -135,9 +94,10 @@ class Cache extends \Friendica\BaseObject * @param boolean $outdated just remove outdated values * * @return bool + * @throws \Exception */ public static function clear($outdated = true) { - return self::getDriver()->clear($outdated); + return self::getClass(ICache::class)->clear($outdated); } } diff --git a/src/Core/Cache/APCuCache.php b/src/Core/Cache/APCuCache.php index f658424cd..48880fe98 100644 --- a/src/Core/Cache/APCuCache.php +++ b/src/Core/Cache/APCuCache.php @@ -3,14 +3,13 @@ namespace Friendica\Core\Cache; use Exception; -use Friendica\Core\Cache; /** - * APCu Cache Driver. + * APCu Cache. * * @author Philipp Holzer */ -class APCuCache extends AbstractCacheDriver implements IMemoryCacheDriver +class APCuCache extends Cache implements IMemoryCache { use TraitCompareSet; use TraitCompareDelete; @@ -18,11 +17,13 @@ class APCuCache extends AbstractCacheDriver implements IMemoryCacheDriver /** * @throws Exception */ - public function __construct() + public function __construct(string $hostname) { if (!self::isAvailable()) { throw new Exception('APCu is not available.'); } + + parent::__construct($hostname); } /** @@ -151,4 +152,12 @@ class APCuCache extends AbstractCacheDriver implements IMemoryCacheDriver return true; } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_APCU; + } } diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php index a99b05788..5add98cc2 100644 --- a/src/Core/Cache/ArrayCache.php +++ b/src/Core/Cache/ArrayCache.php @@ -2,17 +2,14 @@ namespace Friendica\Core\Cache; - -use Friendica\Core\Cache; - /** - * Implementation of the IMemoryCacheDriver mainly for testing purpose + * Implementation of the IMemoryCache mainly for testing purpose * * Class ArrayCache * * @package Friendica\Core\Cache */ -class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver +class ArrayCache extends Cache implements IMemoryCache { use TraitCompareDelete; @@ -93,4 +90,12 @@ class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver return false; } } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_ARRAY; + } } diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/Cache.php similarity index 67% rename from src/Core/Cache/AbstractCacheDriver.php rename to src/Core/Cache/Cache.php index f238a7819..b40c129ae 100644 --- a/src/Core/Cache/AbstractCacheDriver.php +++ b/src/Core/Cache/Cache.php @@ -1,18 +1,43 @@ hostName = $hostName; + } + /** * Returns the prefix (to avoid namespace conflicts) * @@ -22,7 +47,7 @@ abstract class AbstractCacheDriver extends BaseObject protected function getPrefix() { // We fetch with the hostname as key to avoid problems with other applications - return self::getApp()->getHostName(); + return $this->hostName; } /** @@ -46,7 +71,7 @@ abstract class AbstractCacheDriver extends BaseObject } else { // Keys are prefixed with the node hostname, let's remove it array_walk($keys, function (&$value) { - $value = preg_replace('/^' . self::getApp()->getHostName() . ':/', '', $value); + $value = preg_replace('/^' . $this->hostName . ':/', '', $value); }); sort($keys); @@ -79,6 +104,5 @@ abstract class AbstractCacheDriver extends BaseObject return $result; } - } } diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCache.php similarity index 61% rename from src/Core/Cache/DatabaseCacheDriver.php rename to src/Core/Cache/DatabaseCache.php index f6f5b6486..7fbbdb5e3 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCache.php @@ -2,17 +2,28 @@ namespace Friendica\Core\Cache; -use Friendica\Core\Cache; -use Friendica\Database\DBA; +use Friendica\Database\Database; use Friendica\Util\DateTimeFormat; /** - * Database Cache Driver + * Database Cache * * @author Hypolite Petovan */ -class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver +class DatabaseCache extends Cache implements ICache { + /** + * @var Database + */ + private $dba; + + public function __construct(string $hostname, Database $dba) + { + parent::__construct($hostname); + + $this->dba = $dba; + } + /** * (@inheritdoc) */ @@ -24,13 +35,13 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix]; } - $stmt = DBA::select('cache', ['k'], $where); + $stmt = $this->dba->select('cache', ['k'], $where); $keys = []; - while ($key = DBA::fetch($stmt)) { + while ($key = $this->dba->fetch($stmt)) { array_push($keys, $key['k']); } - DBA::close($stmt); + $this->dba->close($stmt); return $keys; } @@ -40,9 +51,9 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver */ public function get($key) { - $cache = DBA::selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]); + $cache = $this->dba->selectFirst('cache', ['v'], ['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()]); - if (DBA::isResult($cache)) { + if ($this->dba->isResult($cache)) { $cached = $cache['v']; $value = @unserialize($cached); @@ -76,7 +87,7 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver ]; } - return DBA::update('cache', $fields, ['k' => $key], true); + return $this->dba->update('cache', $fields, ['k' => $key], true); } /** @@ -84,7 +95,7 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver */ public function delete($key) { - return DBA::delete('cache', ['k' => $key]); + return $this->dba->delete('cache', ['k' => $key]); } /** @@ -93,9 +104,17 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver public function clear($outdated = true) { if ($outdated) { - return DBA::delete('cache', ['`expires` < NOW()']); + return $this->dba->delete('cache', ['`expires` < NOW()']); } else { - return DBA::delete('cache', ['`k` IS NOT NULL ']); + return $this->dba->delete('cache', ['`k` IS NOT NULL ']); } } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_DATABASE; + } } diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICache.php similarity index 89% rename from src/Core/Cache/ICacheDriver.php rename to src/Core/Cache/ICache.php index 1188e5187..f8e98c568 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICache.php @@ -2,14 +2,12 @@ namespace Friendica\Core\Cache; -use Friendica\Core\Cache; - /** - * Cache Driver Interface + * Cache Interface * * @author Hypolite Petovan */ -interface ICacheDriver +interface ICache { /** * Lists all cache keys @@ -56,4 +54,11 @@ interface ICacheDriver * @return bool */ public function clear($outdated = true); + + /** + * Returns the name of the current cache + * + * @return string + */ + public function getName(); } diff --git a/src/Core/Cache/IMemoryCacheDriver.php b/src/Core/Cache/IMemoryCache.php similarity index 91% rename from src/Core/Cache/IMemoryCacheDriver.php rename to src/Core/Cache/IMemoryCache.php index 0c5146f43..339f72d04 100644 --- a/src/Core/Cache/IMemoryCacheDriver.php +++ b/src/Core/Cache/IMemoryCache.php @@ -1,16 +1,15 @@ */ -class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver +class MemcacheCache extends Cache implements IMemoryCache { use TraitCompareSet; use TraitCompareDelete; @@ -23,18 +22,21 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri private $memcache; /** - * @param string $memcache_host - * @param int $memcache_port * @throws Exception */ - public function __construct($memcache_host, $memcache_port) + public function __construct(string $hostname, Configuration $config) { if (!class_exists('Memcache', false)) { throw new Exception('Memcache class isn\'t available'); } + parent::__construct($hostname); + $this->memcache = new Memcache(); + $memcache_host = $config->get('system', 'memcache_host'); + $memcache_port = $config->get('system', 'memcache_port'); + if (!$this->memcache->connect($memcache_host, $memcache_port)) { throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available'); } @@ -45,7 +47,7 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri */ public function getAllKeys($prefix = null) { - $keys = []; + $keys = []; $allSlabs = $this->memcache->getExtendedStats('slabs'); foreach ($allSlabs as $slabs) { foreach (array_keys($slabs) as $slabId) { @@ -69,7 +71,7 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri */ public function get($key) { - $return = null; + $return = null; $cachekey = $this->getCacheKey($key); // We fetch with the hostname as key to avoid problems with other applications @@ -145,4 +147,12 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri $cachekey = $this->getCacheKey($key); return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl); } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_MEMCACHE; + } } diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCache.php similarity index 77% rename from src/Core/Cache/MemcachedCacheDriver.php rename to src/Core/Cache/MemcachedCache.php index 687e67416..ac0648a6c 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCache.php @@ -2,18 +2,17 @@ namespace Friendica\Core\Cache; -use Friendica\Core\Cache; -use Friendica\Core\Logger; - use Exception; +use Friendica\Core\Config\Configuration; use Memcached; +use Psr\Log\LoggerInterface; /** - * Memcached Cache Driver + * Memcached Cache * * @author Hypolite Petovan */ -class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver +class MemcachedCache extends Cache implements IMemoryCache { use TraitCompareSet; use TraitCompareDelete; @@ -23,6 +22,11 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr */ private $memcached; + /** + * @var LoggerInterface + */ + private $logger; + /** * Due to limitations of the INI format, the expected configuration for Memcached servers is the following: * array { @@ -31,16 +35,23 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr * } * * @param array $memcached_hosts + * * @throws \Exception */ - public function __construct(array $memcached_hosts) + public function __construct(string $hostname, Configuration $config, LoggerInterface $logger) { if (!class_exists('Memcached', false)) { throw new Exception('Memcached class isn\'t available'); } + parent::__construct($hostname); + + $this->logger = $logger; + $this->memcached = new Memcached(); + $memcached_hosts = $config->get('system', 'memcached_hosts'); + array_walk($memcached_hosts, function (&$value) { if (is_string($value)) { $value = array_map('trim', explode(',', $value)); @@ -64,7 +75,7 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr if ($this->memcached->getResultCode() == Memcached::RES_SUCCESS) { return $this->filterArrayKeysByPrefix($keys, $prefix); } else { - Logger::log('Memcached \'getAllKeys\' failed with ' . $this->memcached->getResultMessage(), Logger::ALL); + $this->logger->debug('Memcached \'getAllKeys\' failed', ['result' => $this->memcached->getResultMessage()]); return []; } } @@ -74,7 +85,7 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr */ public function get($key) { - $return = null; + $return = null; $cachekey = $this->getCacheKey($key); // We fetch with the hostname as key to avoid problems with other applications @@ -83,7 +94,7 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr if ($this->memcached->getResultCode() === Memcached::RES_SUCCESS) { $return = $value; } else { - Logger::log('Memcached \'get\' failed with ' . $this->memcached->getResultMessage(), Logger::ALL); + $this->logger->debug('Memcached \'get\' failed', ['result' => $this->memcached->getResultMessage()]); } return $return; @@ -140,4 +151,12 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr $cachekey = $this->getCacheKey($key); return $this->memcached->add($cachekey, $value, $ttl); } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_MEMCACHED; + } } diff --git a/src/Core/Cache/ProfilerCache.php b/src/Core/Cache/ProfilerCache.php new file mode 100644 index 000000000..d59b88560 --- /dev/null +++ b/src/Core/Cache/ProfilerCache.php @@ -0,0 +1,162 @@ +cache = $cache; + $this->profiler = $profiler; + } + + /** + * {@inheritDoc} + */ + public function getAllKeys($prefix = null) + { + $time = microtime(true); + + $return = $this->cache->getAllKeys($prefix); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } + + /** + * {@inheritDoc} + */ + public function get($key) + { + $time = microtime(true); + + $return = $this->cache->get($key); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } + + /** + * {@inheritDoc} + */ + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) + { + $time = microtime(true); + + $return = $this->cache->set($key, $value, $ttl); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } + + /** + * {@inheritDoc} + */ + public function delete($key) + { + $time = microtime(true); + + $return = $this->cache->delete($key); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } + + /** + * {@inheritDoc} + */ + public function clear($outdated = true) + { + $time = microtime(true); + + $return = $this->cache->clear($outdated); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } + + /** + * {@inheritDoc} + */ + public function add($key, $value, $ttl = Cache::FIVE_MINUTES) + { + if ($this->cache instanceof IMemoryCache) { + $time = microtime(true); + + $return = $this->cache->add($key, $value, $ttl); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) + { + if ($this->cache instanceof IMemoryCache) { + $time = microtime(true); + + $return = $this->cache->compareSet($key, $oldValue, $newValue, $ttl); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + public function compareDelete($key, $value) + { + if ($this->cache instanceof IMemoryCache) { + $time = microtime(true); + + $return = $this->cache->compareDelete($key, $value); + + $this->profiler->saveTimestamp($time, 'cache', System::callstack()); + + return $return; + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + public function GetName() + { + return $this->cache->getName() . ' (with profiler)'; + } +} diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCache.php similarity index 86% rename from src/Core/Cache/RedisCacheDriver.php rename to src/Core/Cache/RedisCache.php index ea4eb4390..5f8fd7e4c 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCache.php @@ -3,16 +3,16 @@ namespace Friendica\Core\Cache; use Exception; -use Friendica\Core\Cache; +use Friendica\Core\Config\Configuration; use Redis; /** - * Redis Cache Driver. This driver is based on Memcache driver + * Redis Cache. This driver is based on Memcache driver * * @author Hypolite Petovan * @author Roland Haeder */ -class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver +class RedisCache extends Cache implements IMemoryCache { /** * @var Redis @@ -20,20 +20,23 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver private $redis; /** - * @param string $redis_host - * @param int $redis_port - * @param int $redis_db (Default = 0, maximum is 15) - * @param string? $redis_pw * @throws Exception */ - public function __construct($redis_host, $redis_port, $redis_db = 0, $redis_pw = null) + public function __construct(string $hostname, Configuration $config) { if (!class_exists('Redis', false)) { throw new Exception('Redis class isn\'t available'); } + parent::__construct($hostname); + $this->redis = new Redis(); + $redis_host = $config->get('system', 'redis_host'); + $redis_port = $config->get('system', 'redis_port'); + $redis_pw = $config->get('system', 'redis_password'); + $redis_db = $config->get('system', 'redis_db', 0); + if (!$this->redis->connect($redis_host, $redis_port)) { throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available'); } @@ -188,4 +191,12 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver $this->redis->unwatch(); return false; } + + /** + * {@inheritDoc} + */ + public function getName() + { + return self::TYPE_REDIS; + } } diff --git a/src/Core/Cache/TraitCompareDelete.php b/src/Core/Cache/TraitCompareDelete.php index ef59f69cd..a553f8751 100644 --- a/src/Core/Cache/TraitCompareDelete.php +++ b/src/Core/Cache/TraitCompareDelete.php @@ -2,8 +2,6 @@ namespace Friendica\Core\Cache; -use Friendica\Core\Cache; - /** * Trait TraitCompareSetDelete * diff --git a/src/Core/Cache/TraitCompareSet.php b/src/Core/Cache/TraitCompareSet.php index 77a602835..9c192d952 100644 --- a/src/Core/Cache/TraitCompareSet.php +++ b/src/Core/Cache/TraitCompareSet.php @@ -2,8 +2,6 @@ namespace Friendica\Core\Cache; -use Friendica\Core\Cache; - /** * Trait TraitCompareSetDelete * diff --git a/src/Core/Lock.php b/src/Core/Lock.php index a45490bf3..ef62bc8f7 100644 --- a/src/Core/Lock.php +++ b/src/Core/Lock.php @@ -7,116 +7,28 @@ namespace Friendica\Core; -use Friendica\Factory\CacheDriverFactory; -use Friendica\Core\Cache\IMemoryCacheDriver; +use Friendica\BaseObject; +use Friendica\Core\Cache\Cache; +use Friendica\Core\Lock\ILock; /** - * @brief This class contain Functions for preventing parallel execution of functions + * This class contain Functions for preventing parallel execution of functions */ -class Lock +class Lock extends BaseObject { - /** - * @var Lock\ILockDriver; - */ - static $driver = null; - - public static function init() - { - $lock_driver = Config::get('system', 'lock_driver', 'default'); - - try { - switch ($lock_driver) { - case 'memcache': - case 'memcached': - case 'redis': - $cache_driver = CacheDriverFactory::create($lock_driver); - if ($cache_driver instanceof IMemoryCacheDriver) { - self::$driver = new Lock\CacheLockDriver($cache_driver); - } - break; - - case 'database': - self::$driver = new Lock\DatabaseLockDriver(); - break; - - case 'semaphore': - self::$driver = new Lock\SemaphoreLockDriver(); - break; - - default: - self::useAutoDriver(); - } - } catch (\Exception $exception) { - Logger::log('Driver \'' . $lock_driver . '\' failed - Fallback to \'useAutoDriver()\''); - self::useAutoDriver(); - } - } - - /** - * @brief This method tries to find the best - local - locking method for Friendica - * - * The following sequence will be tried: - * 1. Semaphore Locking - * 2. Cache Locking - * 3. Database Locking - * - */ - private static function useAutoDriver() { - - // 1. Try to use Semaphores for - local - locking - if (function_exists('sem_get')) { - try { - self::$driver = new Lock\SemaphoreLockDriver(); - return; - } catch (\Exception $exception) { - Logger::log('Using Semaphore driver for locking failed: ' . $exception->getMessage()); - } - } - - // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!) - $cache_driver = Config::get('system', 'cache_driver', 'database'); - if ($cache_driver != 'database') { - try { - $lock_driver = CacheDriverFactory::create($cache_driver); - if ($lock_driver instanceof IMemoryCacheDriver) { - self::$driver = new Lock\CacheLockDriver($lock_driver); - } - return; - } catch (\Exception $exception) { - Logger::log('Using Cache driver for locking failed: ' . $exception->getMessage()); - } - } - - // 3. Use Database Locking as a Fallback - self::$driver = new Lock\DatabaseLockDriver(); - } - - /** - * Returns the current cache driver - * - * @return Lock\ILockDriver; - */ - private static function getDriver() - { - if (self::$driver === null) { - self::init(); - } - - return self::$driver; - } - /** * @brief Acquires a lock for a given name * - * @param string $key Name of the lock + * @param string $key Name of the lock * @param integer $timeout Seconds until we give up - * @param integer $ttl The Lock lifespan, must be one of the Cache constants + * @param integer $ttl The Lock lifespan, must be one of the Cache constants * * @return boolean Was the lock successful? + * @throws \Exception */ public static function acquire($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { - return self::getDriver()->acquireLock($key, $timeout, $ttl); + return self::getClass(ILock::class)->acquireLock($key, $timeout, $ttl); } /** @@ -124,19 +36,22 @@ class Lock * * @param string $key Name of the lock * @param bool $override Overrides the lock to get releases + * * @return void + * @throws \Exception */ public static function release($key, $override = false) { - self::getDriver()->releaseLock($key, $override); + return self::getClass(ILock::class)->releaseLock($key, $override); } /** * @brief Releases all lock that were set by us * @return void + * @throws \Exception */ public static function releaseAll() { - self::getDriver()->releaseAll(); + self::getClass(ILock::class)->releaseAll(); } } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLock.php similarity index 74% rename from src/Core/Lock/CacheLockDriver.php rename to src/Core/Lock/CacheLock.php index 6f34a0d6a..36a7b4edf 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLock.php @@ -3,21 +3,21 @@ namespace Friendica\Core\Lock; use Friendica\Core\Cache; -use Friendica\Core\Cache\IMemoryCacheDriver; +use Friendica\Core\Cache\IMemoryCache; -class CacheLockDriver extends AbstractLockDriver +class CacheLock extends Lock { /** - * @var \Friendica\Core\Cache\ICacheDriver; + * @var \Friendica\Core\Cache\ICache; */ private $cache; /** - * CacheLockDriver constructor. + * CacheLock constructor. * - * @param IMemoryCacheDriver $cache The CacheDriver for this type of lock + * @param IMemoryCache $cache The CacheDriver for this type of lock */ - public function __construct(IMemoryCacheDriver $cache) + public function __construct(IMemoryCache $cache) { $this->cache = $cache; } @@ -28,7 +28,7 @@ class CacheLockDriver extends AbstractLockDriver public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { $got_lock = false; - $start = time(); + $start = time(); $cachekey = self::getLockKey($key); @@ -65,8 +65,6 @@ class CacheLockDriver extends AbstractLockDriver { $cachekey = self::getLockKey($key); - $return = false; - if ($override) { $return = $this->cache->delete($cachekey); } else { @@ -83,15 +81,17 @@ class CacheLockDriver extends AbstractLockDriver public function isLocked($key) { $cachekey = self::getLockKey($key); - $lock = $this->cache->get($cachekey); + $lock = $this->cache->get($cachekey); return isset($lock) && ($lock !== false); } /** - * @param string $key The original key - * @return string The cache key used for the cache + * @param string $key The original key + * + * @return string The cache key used for the cache */ - private static function getLockKey($key) { + private static function getLockKey($key) + { return "lock:" . $key; } } diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLock.php similarity index 59% rename from src/Core/Lock/DatabaseLockDriver.php rename to src/Core/Lock/DatabaseLock.php index a8269bc92..e5274b9b9 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLock.php @@ -3,13 +3,13 @@ namespace Friendica\Core\Lock; use Friendica\Core\Cache; -use Friendica\Database\DBA; +use Friendica\Database\Database; use Friendica\Util\DateTimeFormat; /** * Locking driver that stores the locks in the database */ -class DatabaseLockDriver extends AbstractLockDriver +class DatabaseLock extends Lock { /** * The current ID of the process @@ -18,11 +18,17 @@ class DatabaseLockDriver extends AbstractLockDriver */ private $pid; + /** + * @var Database The database connection of Friendica + */ + private $dba; + /** * @param null|int $pid The Id of the current process (null means determine automatically) */ - public function __construct($pid = null) + public function __construct(Database $dba, $pid = null) { + $this->dba = $dba; $this->pid = isset($pid) ? $pid : getmypid(); } @@ -32,13 +38,13 @@ class DatabaseLockDriver extends AbstractLockDriver public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { $got_lock = false; - $start = time(); + $start = time(); do { - DBA::lock('locks'); - $lock = DBA::selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); + $this->dba->lock('locks'); + $lock = $this->dba->selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); - if (DBA::isResult($lock)) { + if ($this->dba->isResult($lock)) { if ($lock['locked']) { // We want to lock something that was already locked by us? So we got the lock. if ($lock['pid'] == $this->pid) { @@ -46,16 +52,16 @@ class DatabaseLockDriver extends AbstractLockDriver } } if (!$lock['locked']) { - DBA::update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]); + $this->dba->update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]); $got_lock = true; } } else { - DBA::insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]); + $this->dba->insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]); $got_lock = true; $this->markAcquire($key); } - DBA::unlock(); + $this->dba->unlock(); if (!$got_lock && ($timeout > 0)) { usleep(rand(100000, 2000000)); @@ -76,7 +82,7 @@ class DatabaseLockDriver extends AbstractLockDriver $where = ['name' => $key, 'pid' => $this->pid]; } - $return = DBA::delete('locks', $where); + $return = $this->dba->delete('locks', $where); $this->markRelease($key); @@ -88,7 +94,7 @@ class DatabaseLockDriver extends AbstractLockDriver */ public function releaseAll() { - $return = DBA::delete('locks', ['pid' => $this->pid]); + $return = $this->dba->delete('locks', ['pid' => $this->pid]); $this->acquiredLocks = []; @@ -100,9 +106,9 @@ class DatabaseLockDriver extends AbstractLockDriver */ public function isLocked($key) { - $lock = DBA::selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); + $lock = $this->dba->selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); - if (DBA::isResult($lock)) { + if ($this->dba->isResult($lock)) { return $lock['locked'] !== false; } else { return false; diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILock.php similarity index 67% rename from src/Core/Lock/ILockDriver.php rename to src/Core/Lock/ILock.php index 7df5b3f87..0b91daeb5 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILock.php @@ -1,19 +1,21 @@ */ -interface ILockDriver +interface ILock { /** * Checks, if a key is currently locked to a or my process * - * @param string $key The name of the lock + * @param string $key The name of the lock + * * @return bool */ public function isLocked($key); @@ -22,13 +24,13 @@ interface ILockDriver * * Acquires a lock for a given name * - * @param string $key The Name of the lock - * @param integer $timeout Seconds until we give up - * @param integer $ttl Seconds The lock lifespan, must be one of the Cache constants + * @param string $key The Name of the lock + * @param integer $timeout Seconds until we give up + * @param integer $ttl Seconds The lock lifespan, must be one of the Cache constants * * @return boolean Was the lock successful? */ - public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES); + public function acquireLock($key, $timeout = 120, $ttl = Cache\Cache::FIVE_MINUTES); /** * Releases a lock if it was set by us diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/Lock.php similarity index 90% rename from src/Core/Lock/AbstractLockDriver.php rename to src/Core/Lock/Lock.php index 0aedeeb1b..4418fee27 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/Lock.php @@ -1,16 +1,15 @@ getBaseURL($ssl); + return self::getClass(BaseURL::class)->get($ssl); } /** diff --git a/src/Factory/CacheDriverFactory.php b/src/Factory/CacheDriverFactory.php deleted file mode 100644 index 390534a70..000000000 --- a/src/Factory/CacheDriverFactory.php +++ /dev/null @@ -1,57 +0,0 @@ -hostname = $baseURL->getHostname(); + $this->config = $config; + $this->dba = $dba; + $this->profiler = $profiler; + $this->logger = $logger; + } + + /** + * This method creates a CacheDriver for the given cache driver name + * + * @param string $type The cache type to create (default is per config) + * + * @return ICache The instance of the CacheDriver + * @throws \Exception The exception if something went wrong during the CacheDriver creation + */ + public function create(string $type = null) + { + if (empty($type)) { + $type = $this->config->get('system', 'cache_driver', self::DEFAULT_TYPE); + } + + switch ($type) { + case Cache\Cache::TYPE_MEMCACHE: + $cache = new Cache\MemcacheCache($this->hostname, $this->config); + break; + case Cache\Cache::TYPE_MEMCACHED: + $cache = new Cache\MemcachedCache($this->hostname, $this->config, $this->logger); + break; + case Cache\Cache::TYPE_REDIS: + $cache = new Cache\RedisCache($this->hostname, $this->config); + break; + case Cache\Cache::TYPE_APCU: + $cache = new Cache\APCuCache($this->hostname); + break; + default: + $cache = new Cache\DatabaseCache($this->hostname, $this->dba); + } + + $profiling = $this->config->get('system', 'profiling', false); + + // In case profiling is enabled, wrap the ProfilerCache around the current cache + if (isset($profiling) && $profiling !== false) { + return new Cache\ProfilerCache($cache, $this->profiler); + } else { + return $cache; + } + } +} diff --git a/src/Factory/LockFactory.php b/src/Factory/LockFactory.php new file mode 100644 index 000000000..fef6708d2 --- /dev/null +++ b/src/Factory/LockFactory.php @@ -0,0 +1,132 @@ +cacheFactory = $cacheFactory; + $this->config = $config; + $this->dba = $dba; + $this->logger = $logger; + } + + public function create() + { + $lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER); + + try { + switch ($lock_type) { + case Cache::TYPE_MEMCACHE: + case Cache::TYPE_MEMCACHED: + case Cache::TYPE_REDIS: + case Cache::TYPE_APCU: + $cache = $this->cacheFactory->create($lock_type); + if ($cache instanceof IMemoryCache) { + return new Lock\CacheLock($cache); + } else { + throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type)); + } + break; + + case 'database': + return new Lock\DatabaseLock($this->dba); + break; + + case 'semaphore': + return new Lock\SemaphoreLock(); + break; + + default: + return self::useAutoDriver(); + } + } catch (\Exception $exception) { + $this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]); + return self::useAutoDriver(); + } + } + + /** + * @brief This method tries to find the best - local - locking method for Friendica + * + * The following sequence will be tried: + * 1. Semaphore Locking + * 2. Cache Locking + * 3. Database Locking + * + * @return Lock\ILock + */ + private function useAutoDriver() + { + // 1. Try to use Semaphores for - local - locking + if (function_exists('sem_get')) { + try { + return new Lock\SemaphoreLock(); + } catch (\Exception $exception) { + $this->logger->debug('Using Semaphore driver for locking failed.', ['exception' => $exception]); + } + } + + // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!) + $cache_type = $this->config->get('system', 'cache_driver', 'database'); + if ($cache_type != Cache::TYPE_DATABASE) { + try { + $cache = $this->cacheFactory->create($cache_type); + if ($cache instanceof IMemoryCache) { + return new Lock\CacheLock($cache); + } + } catch (\Exception $exception) { + $this->logger->debug('Using Cache driver for locking failed.', ['exception' => $exception]); + } + } + + // 3. Use Database Locking as a Fallback + return new Lock\DatabaseLock($this->dba); + } +} diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 475f5ccee..1d0908f32 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -2,7 +2,9 @@ use Dice\Dice; use Friendica\App; +use Friendica\Core\Cache; use Friendica\Core\Config; +use Friendica\Core\Lock\ILock; use Friendica\Database\Database; use Friendica\Factory; use Friendica\Util; @@ -104,16 +106,34 @@ return [ * $app = $dice->create(App::class, [], ['$channel' => 'index']); * and is automatically passed as an argument with the same name */ - LoggerInterface::class => [ + LoggerInterface::class => [ 'instanceOf' => Factory\LoggerFactory::class, 'call' => [ ['create', [], Dice::CHAIN_CALL], ], ], - '$devLogger' => [ + '$devLogger' => [ 'instanceOf' => Factory\LoggerFactory::class, 'call' => [ ['createDev', [], Dice::CHAIN_CALL], ] ], + Cache\ICache::class => [ + 'instanceOf' => Factory\CacheFactory::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], + ], + ], + Cache\IMemoryCache::class => [ + 'instanceOf' => Factory\CacheFactory::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], + ], + ], + ILock::class => [ + 'instanceOf' => Factory\LockFactory::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], + ], + ], ]; diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 4f0275493..7421f16a0 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -5,56 +5,10 @@ namespace Friendica\Test; -use Friendica\Database\Database; -use Friendica\Test\Util\Database\StaticDatabase; - /** * Abstract class used by tests that need a database. */ abstract class DatabaseTest extends MockedTest { - protected function setUp() - { - parent::setUp(); - - StaticDatabase::statConnect($_SERVER); - // Rollbacks every DB usage (in case the test couldn't call tearDown) - StaticDatabase::statRollback(); - // Start the first, outer transaction - StaticDatabase::getGlobConnection()->beginTransaction(); - } - - protected function tearDown() - { - // Rollbacks every DB usage so we don't commit anything into the DB - StaticDatabase::statRollback(); - - parent::tearDown(); - } - - /** - * Loads a given DB fixture for this DB test - * - * @param string $fixture The path to the fixture - * @param Database $dba The DB connection - * - * @throws \Exception - */ - protected function loadFixture(string $fixture, Database $dba) - { - $this->assertFileExists($fixture); - - $data = include $fixture; - - foreach ($data as $tableName => $rows) { - if (!is_array($rows)) { - $dba->p('TRUNCATE TABLE `' . $tableName . '``'); - continue; - } - - foreach ($rows as $row) { - $dba->insert($tableName, $row); - } - } - } + use DatabaseTestTrait; } diff --git a/tests/DatabaseTestTrait.php b/tests/DatabaseTestTrait.php new file mode 100644 index 000000000..49dc999b6 --- /dev/null +++ b/tests/DatabaseTestTrait.php @@ -0,0 +1,58 @@ +beginTransaction(); + + parent::setUp(); + } + + protected function tearDown() + { + // Rollbacks every DB usage so we don't commit anything into the DB + StaticDatabase::statRollback(); + + parent::tearDown(); + } + + /** + * Loads a given DB fixture for this DB test + * + * @param string $fixture The path to the fixture + * @param Database $dba The DB connection + * + * @throws \Exception + */ + protected function loadFixture(string $fixture, Database $dba) + { + $data = include $fixture; + + foreach ($data as $tableName => $rows) { + if (!is_array($rows)) { + $dba->p('TRUNCATE TABLE `' . $tableName . '``'); + continue; + } + + foreach ($rows as $row) { + $dba->insert($tableName, $row); + } + } + } +} diff --git a/tests/Util/DbaCacheMockTrait.php b/tests/Util/DbaCacheMockTrait.php index 87ab450c9..95e7cbcb1 100644 --- a/tests/Util/DbaCacheMockTrait.php +++ b/tests/Util/DbaCacheMockTrait.php @@ -4,8 +4,14 @@ namespace Friendica\Test\Util; trait DbaCacheMockTrait { - use DBAMockTrait; - use DateTimeFormatMockTrait; + /** + * @var + */ + protected $dba; + + public function __construct() + { + } protected function mockDelete($key, $return = true, $times = null) { diff --git a/tests/Util/DbaLockMockTrait.php b/tests/Util/DbaLockMockTrait.php index 3f76edb88..5b405dcfc 100644 --- a/tests/Util/DbaLockMockTrait.php +++ b/tests/Util/DbaLockMockTrait.php @@ -3,7 +3,7 @@ namespace Friendica\Test\Util; use Friendica\Core\Cache; -use Friendica\Core\Lock\DatabaseLockDriver; +use Friendica\Core\Lock\DatabaseLock; trait DbaLockMockTrait { @@ -12,7 +12,6 @@ trait DbaLockMockTrait /** * Mocking acquireLock with DBA-backend - * @see DatabaseLockDriver::acquireLock() * * @param mixed $key The key to lock * @param int $ttl The TimeToLive @@ -22,6 +21,9 @@ trait DbaLockMockTrait * @param bool $rowExists True, if a row already exists in the lock table * @param null $time The current timestamp * @param null|int $times How often the method will get used + * + *@see DatabaseLock::acquireLock() + * */ public function mockAcquireLock($key, $ttl = Cache::FIVE_MINUTES, $locked = false, $pid = null, $rowExists = true, $time = null, $times = null) { @@ -55,12 +57,14 @@ trait DbaLockMockTrait /** * Mocking isLocked with DBA-backend - * @see DatabaseLockDriver::isLocked() * * @param mixed $key The key of the lock * @param null|bool $return True, if the key is already locked - * @param null $time The current timestamp + * @param null $time The current timestamp * @param null|int $times How often the method will get used + * + *@see DatabaseLock::isLocked() + * */ public function mockIsLocked($key, $return = true, $time = null, $times = null) { @@ -76,10 +80,12 @@ trait DbaLockMockTrait /** * Mocking releaseAll with DBA-backend - * @see DatabaseLockDriver::releaseAll() * - * @param null $pid The PID which was set - * @param null|int $times How often the method will get used + * @param null $pid The PID which was set + * @param null|int $times How often the method will get used + * + *@see DatabaseLock::releaseAll() + * */ public function mockReleaseAll($pid = null, $times = null) { @@ -92,11 +98,13 @@ trait DbaLockMockTrait /** * Mocking ReleaseLock with DBA-backend - * @see DatabaseLockDriver::releaseLock() * * @param mixed $key The key to release * @param null|int $pid The PID which was set * @param null|int $times How often the method will get used + * + *@see DatabaseLock::releaseLock() + * */ public function mockReleaseLock($key, $pid = null, $times = null) { diff --git a/tests/Util/VFSTrait.php b/tests/Util/VFSTrait.php index 110f24a61..565e693c9 100644 --- a/tests/Util/VFSTrait.php +++ b/tests/Util/VFSTrait.php @@ -28,6 +28,7 @@ trait VFSTrait // create a virtual directory and copy all needed files and folders to it $this->root = vfsStream::setup('friendica', 0777, $structure); + $this->setConfigFile('dbstructure.config.php', true); $this->setConfigFile('defaults.config.php', true); $this->setConfigFile('settings.config.php', true); $this->setConfigFile('local.config.php'); diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 9fe469d5e..6de2dc647 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -4,8 +4,11 @@ namespace functional; use Dice\Dice; use Friendica\App; +use Friendica\Core\Cache\ICache; +use Friendica\Core\Cache\IMemoryCache; use Friendica\Core\Config\Cache\ConfigCache; use Friendica\Core\Config\Configuration; +use Friendica\Core\Lock\ILock; use Friendica\Database\Database; use Friendica\Test\Util\VFSTrait; use Friendica\Util\BasePath; @@ -29,8 +32,8 @@ class dependencyCheck extends TestCase $this->setUpVfsDir(); - $this->dice = new Dice(); - $this->dice = $this->dice->addRules(include __DIR__ . '/../../static/dependencies.config.php'); + $this->dice = (new Dice()) + ->addRules(include __DIR__ . '/../../static/dependencies.config.php'); } /** @@ -84,7 +87,7 @@ class dependencyCheck extends TestCase ]); // create new DI-library because of shared instance rule (so the Profiler wouldn't get created twice) - $this->dice = new Dice(include __DIR__ . '/../../static/dependencies.config.php'); + $this->dice = new Dice(); $profiler = $this->dice->create(Profiler::class, [$configCache]); $this->assertInstanceOf(Profiler::class, $profiler); @@ -133,6 +136,31 @@ class dependencyCheck extends TestCase /** @var LoggerInterface $logger */ $logger = $this->dice->create('$devLogger', ['dev']); - self::assertInstanceOf(LoggerInterface::class, $logger); + $this->assertInstanceOf(LoggerInterface::class, $logger); + } + + public function testCache() + { + /** @var ICache $cache */ + $cache = $this->dice->create(ICache::class); + + $this->assertInstanceOf(ICache::class, $cache); + } + + public function testMemoryCache() + { + /** @var IMemoryCache $cache */ + $cache = $this->dice->create(IMemoryCache::class); + + // We need to check "just" ICache, because the default Cache is DB-Cache, which isn't a memorycache + $this->assertInstanceOf(ICache::class, $cache); + } + + public function testLock() + { + /** @var ILock $cache */ + $lock = $this->dice->create(ILock::class); + + $this->assertInstanceOf(ILock::class, $lock); } } diff --git a/tests/include/ApiTest.php b/tests/include/ApiTest.php index 465641af2..3410f3049 100644 --- a/tests/include/ApiTest.php +++ b/tests/include/ApiTest.php @@ -8,8 +8,8 @@ namespace Friendica\Test; use Dice\Dice; use Friendica\App; use Friendica\BaseObject; -use Friendica\Core\Config; -use Friendica\Core\PConfig; +use Friendica\Core\Config\Configuration; +use Friendica\Core\Config\PConfiguration; use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Database\Database; @@ -44,6 +44,12 @@ class ApiTest extends DatabaseTest /** @var App */ protected $app; + /** @var Configuration */ + protected $config; + + /** @var Dice */ + protected $dice; + /** * Create variables used by tests. */ @@ -51,17 +57,32 @@ class ApiTest extends DatabaseTest { parent::setUp(); - $dice = new Dice(); - $dice = $dice->addRules(include __DIR__ . '/../../static/dependencies.config.php'); - $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); - BaseObject::setDependencyInjection($dice); + $this->dice = (new Dice()) + ->addRules(include __DIR__ . '/../../static/dependencies.config.php') + ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); + BaseObject::setDependencyInjection($this->dice); /** @var Database $dba */ - $dba = $dice->create(Database::class); + $dba = $this->dice->create(Database::class); + + /** @var Configuration $config */ + $this->config = $this->dice->create(Configuration::class); + + $this->config->set('system', 'url', 'http://localhost'); + $this->config->set('system', 'hostname', 'localhost'); + $this->config->set('system', 'worker_dont_fork', true); + + // Default config + $this->config->set('config', 'hostname', 'localhost'); + $this->config->set('system', 'throttle_limit_day', 100); + $this->config->set('system', 'throttle_limit_week', 100); + $this->config->set('system', 'throttle_limit_month', 100); + $this->config->set('system', 'theme', 'system_theme'); // Load the API dataset for the whole API $this->loadFixture(__DIR__ . '/../datasets/api.fixture.php', $dba); + /** @var App app */ $this->app = BaseObject::getApp(); $this->app->argc = 1; @@ -100,17 +121,6 @@ class ApiTest extends DatabaseTest $_POST = []; $_GET = []; $_SERVER = []; - - Config::set('system', 'url', 'http://localhost'); - Config::set('system', 'hostname', 'localhost'); - Config::set('system', 'worker_dont_fork', true); - - // Default config - Config::set('config', 'hostname', 'localhost'); - Config::set('system', 'throttle_limit_day', 100); - Config::set('system', 'throttle_limit_week', 100); - Config::set('system', 'throttle_limit_month', 100); - Config::set('system', 'theme', 'system_theme'); } /** @@ -441,8 +451,8 @@ class ApiTest extends DatabaseTest } ]; $_SERVER['REQUEST_METHOD'] = 'method'; - Config::set('system', 'profiler', true); - Config::set('rendertime', 'callstack', true); + $this->config->set('system', 'profiler', true); + $this->config->set('rendertime', 'callstack', true); $this->app->callstack = [ 'database' => ['some_function' => 200], 'database_write' => ['some_function' => 200], @@ -790,7 +800,8 @@ class ApiTest extends DatabaseTest */ public function testApiGetUserWithFrioSchema() { - PConfig::set($this->selfUser['id'], 'frio', 'schema', 'red'); + $pConfig = $this->dice->create(PConfiguration::class); + $pConfig->set($this->selfUser['id'], 'frio', 'schema', 'red'); $user = api_get_user($this->app); $this->assertSelfUser($user); $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']); @@ -805,10 +816,11 @@ class ApiTest extends DatabaseTest */ public function testApiGetUserWithCustomFrioSchema() { - $ret1 = PConfig::set($this->selfUser['id'], 'frio', 'schema', '---'); - $ret2 = PConfig::set($this->selfUser['id'], 'frio', 'nav_bg', '#123456'); - $ret3 = PConfig::set($this->selfUser['id'], 'frio', 'link_color', '#123456'); - $ret4 = PConfig::set($this->selfUser['id'], 'frio', 'background_color', '#123456'); + $pConfig = $this->dice->create(PConfiguration::class); + $pConfig->set($this->selfUser['id'], 'frio', 'schema', '---'); + $pConfig->set($this->selfUser['id'], 'frio', 'nav_bg', '#123456'); + $pConfig->set($this->selfUser['id'], 'frio', 'link_color', '#123456'); + $pConfig->set($this->selfUser['id'], 'frio', 'background_color', '#123456'); $user = api_get_user($this->app); $this->assertSelfUser($user); $this->assertEquals('123456', $user['profile_sidebar_fill_color']); @@ -823,7 +835,8 @@ class ApiTest extends DatabaseTest */ public function testApiGetUserWithEmptyFrioSchema() { - PConfig::set($this->selfUser['id'], 'frio', 'schema', '---'); + $pConfig = $this->dice->create(PConfiguration::class); + $pConfig->set($this->selfUser['id'], 'frio', 'schema', '---'); $user = api_get_user($this->app); $this->assertSelfUser($user); $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']); diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php index 3affe4e77..6938f8ed5 100644 --- a/tests/src/Content/Text/BBCodeTest.php +++ b/tests/src/Content/Text/BBCodeTest.php @@ -7,6 +7,7 @@ use Friendica\Core\L10n\L10n; use Friendica\Test\MockedTest; use Friendica\Test\Util\AppMockTrait; use Friendica\Test\Util\VFSTrait; +use Friendica\Util\BaseURL; class BBCodeTest extends MockedTest { @@ -44,6 +45,12 @@ class BBCodeTest extends MockedTest $this->dice->shouldReceive('create') ->with(L10n::class) ->andReturn($l10nMock); + + $baseUrlMock = \Mockery::mock(BaseURL::class); + $baseUrlMock->shouldReceive('get')->withAnyArgs()->andReturn('friendica.local'); + $this->dice->shouldReceive('create') + ->with(BaseURL::class) + ->andReturn($baseUrlMock); } public function dataLinks() diff --git a/tests/src/Core/Cache/APCuCacheDriverTest.php b/tests/src/Core/Cache/APCuCacheTest.php similarity index 81% rename from tests/src/Core/Cache/APCuCacheDriverTest.php rename to tests/src/Core/Cache/APCuCacheTest.php index eac00f559..1b90be574 100644 --- a/tests/src/Core/Cache/APCuCacheDriverTest.php +++ b/tests/src/Core/Cache/APCuCacheTest.php @@ -4,7 +4,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\APCuCache; -class APCuCacheDriverTest extends MemoryCacheTest +class APCuCacheTest extends MemoryCacheTest { protected function setUp() { @@ -17,7 +17,7 @@ class APCuCacheDriverTest extends MemoryCacheTest protected function getInstance() { - $this->cache = new APCuCache(); + $this->cache = new APCuCache('localhost'); return $this->cache; } diff --git a/tests/src/Core/Cache/ArrayCacheDriverTest.php b/tests/src/Core/Cache/ArrayCacheTest.php similarity index 78% rename from tests/src/Core/Cache/ArrayCacheDriverTest.php rename to tests/src/Core/Cache/ArrayCacheTest.php index c92fb98da..60ca2761e 100644 --- a/tests/src/Core/Cache/ArrayCacheDriverTest.php +++ b/tests/src/Core/Cache/ArrayCacheTest.php @@ -4,11 +4,11 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\ArrayCache; -class ArrayCacheDriverTest extends MemoryCacheTest +class ArrayCacheTest extends MemoryCacheTest { protected function getInstance() { - $this->cache = new ArrayCache(); + $this->cache = new ArrayCache('localhost'); return $this->cache; } diff --git a/tests/src/Core/Cache/CacheTest.php b/tests/src/Core/Cache/CacheTest.php index ef97f5a17..92fdaffa3 100644 --- a/tests/src/Core/Cache/CacheTest.php +++ b/tests/src/Core/Cache/CacheTest.php @@ -2,34 +2,30 @@ namespace Friendica\Test\src\Core\Cache; -use Friendica\Core\Cache\MemcachedCacheDriver; +use Friendica\Core\Cache\MemcachedCache; use Friendica\Test\MockedTest; -use Friendica\Test\Util\AppMockTrait; -use Friendica\Test\Util\VFSTrait; use Friendica\Util\PidFile; abstract class CacheTest extends MockedTest { - use VFSTrait; - use AppMockTrait; - /** * @var int Start time of the mock (used for time operations) */ protected $startTime = 1417011228; /** - * @var \Friendica\Core\Cache\ICacheDriver + * @var \Friendica\Core\Cache\ICache */ protected $instance; /** - * @var \Friendica\Core\Cache\IMemoryCacheDriver + * @var \Friendica\Core\Cache\IMemoryCache */ protected $cache; /** * Dataset for test setting different types in the cache + * * @return array */ public function dataTypesInCache() @@ -48,6 +44,7 @@ abstract class CacheTest extends MockedTest /** * Dataset for simple value sets/gets + * * @return array */ public function dataSimple() @@ -66,12 +63,6 @@ abstract class CacheTest extends MockedTest protected function setUp() { - $this->setUpVfsDir(); - $this->mockApp($this->root); - $this->app - ->shouldReceive('getHostname') - ->andReturn('friendica.local'); - parent::setUp(); $this->instance = $this->getInstance(); @@ -82,10 +73,12 @@ abstract class CacheTest extends MockedTest /** * @small * @dataProvider dataSimple + * * @param mixed $value1 a first * @param mixed $value2 a second */ - function testSimple($value1, $value2) { + function testSimple($value1, $value2) + { $this->assertNull($this->instance->get('value1')); $this->instance->set('value1', $value1); @@ -110,12 +103,14 @@ abstract class CacheTest extends MockedTest /** * @small * @dataProvider dataSimple + * * @param mixed $value1 a first * @param mixed $value2 a second * @param mixed $value3 a third * @param mixed $value4 a fourth */ - function testClear($value1, $value2, $value3, $value4) { + function testClear($value1, $value2, $value3, $value4) + { $value = 'ipsum lorum'; $this->instance->set('1_value1', $value1); $this->instance->set('1_value2', $value2); @@ -166,7 +161,8 @@ abstract class CacheTest extends MockedTest /** * @medium */ - function testTTL() { + function testTTL() + { $this->markTestSkipped('taking too much time without mocking'); $this->assertNull($this->instance->get('value1')); @@ -183,10 +179,13 @@ abstract class CacheTest extends MockedTest /** * @small + * * @param $data mixed the data to store in the cache + * * @dataProvider dataTypesInCache */ - function testDifferentTypesInCache($data) { + function testDifferentTypesInCache($data) + { $this->instance->set('val', $data); $received = $this->instance->get('val'); $this->assertEquals($data, $received, 'Value type changed from ' . gettype($data) . ' to ' . gettype($received)); @@ -194,13 +193,16 @@ abstract class CacheTest extends MockedTest /** * @small + * * @param mixed $value1 a first * @param mixed $value2 a second * @param mixed $value3 a third + * * @dataProvider dataSimple */ - public function testGetAllKeys($value1, $value2, $value3) { - if ($this->cache instanceof MemcachedCacheDriver) { + public function testGetAllKeys($value1, $value2, $value3) + { + if ($this->cache instanceof MemcachedCache) { $this->markTestSkipped('Memcached doesn\'t support getAllKeys anymore'); } diff --git a/tests/src/Core/Cache/DatabaseCacheDriverTest.php b/tests/src/Core/Cache/DatabaseCacheDriverTest.php deleted file mode 100644 index 2d29c2ad9..000000000 --- a/tests/src/Core/Cache/DatabaseCacheDriverTest.php +++ /dev/null @@ -1,141 +0,0 @@ -mockUtcNow($this->startTime); - - $this->mockConnected(); - $this->mockConnect(); - - // The first "clear" at setup - $this->mockClear(false, true, 2); - - parent::setUp(); - } - - protected function getInstance() - { - $this->cache = CacheDriverFactory::create('database'); - return $this->cache; - } - - public function tearDown() - { - $this->cache->clear(false); - parent::tearDown(); - } - - /** - * {@inheritdoc} - * @dataProvider dataSimple - */ - public function testSimple($value1, $value2) - { - // assertNull - $this->mockGet('value1', null, $this->startTime, 1); - - // assertEquals - $this->mockSet('value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockGet('value1', $value1, $this->startTime, 1); - - // assertEquals - $this->mockSet('value1', $value2, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockGet('value1', $value2, $this->startTime, 1); - - // assertEquals - $this->mockSet('value2', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockGet('value2', $value1, $this->startTime, 1); - - // assertNull - $this->mockGet('not_set', null, $this->startTime, 1); - - // assertNull - $this->mockDelete('value1', true, 1); - $this->mockGet('value1', null, $this->startTime, 1); - - parent::testSimple($value1, $value2); - } - - /** - * {@inheritdoc} - * @dataProvider dataSimple - */ - public function testClear($value1, $value2, $value3, $value4) - { - // assert Equals - $this->mockSet('1_value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockSet('1_value2', $value2, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockSet('2_value1', $value3, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockSet('3_value1', $value4, Cache::FIVE_MINUTES, $this->startTime, true, 1); - - $this->mockGet('1_value1', $value1, $this->startTime, 2); - $this->mockGet('1_value2', $value2, $this->startTime, 2); - $this->mockGet('2_value1', $value3, $this->startTime, 2); - $this->mockGet('3_value1', $value4, $this->startTime, 2); - - // assertTrue - $this->mockClear(true, true, 1); - $this->mockClear(false, true, 1); - - // assertEquals - $this->mockGet('1_value1', null, $this->startTime, 1); - $this->mockGet('1_value2', null, $this->startTime, 1); - $this->mockGet('2_value3', null, $this->startTime, 1); - $this->mockGet('3_value4', null, $this->startTime, 1); - - parent::testClear($value1, $value2, $value3, $value4); - } - - /** - * {@inheritdoc} - * @dataProvider dataTypesInCache - */ - public function testDifferentTypesInCache($data) - { - $this->mockSet('val', $data, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockGet('val', $data, $this->startTime, 1); - - parent::testDifferentTypesInCache($data); - } - - /** - * {@inheritdoc} - * @dataProvider dataSimple - */ - public function testGetAllKeys($value1, $value2, $value3) - { - $this->mockSet('value1', $value1, Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockSet('value2', $value2,Cache::FIVE_MINUTES, $this->startTime, true, 1); - $this->mockSet('test_value3', $value3, Cache::FIVE_MINUTES, $this->startTime, true, 1); - - $result = [ - ['k' => 'value1'], - ['k' => 'value2'], - ['k' => 'test_value3'], - ]; - - $this->mockGetAllKeys(null, $result, $this->startTime, 1); - - $result = [ - ['k' => 'test_value3'], - ]; - - $this->mockGetAllKeys('test', $result, $this->startTime, 1); - - parent::testGetAllKeys($value1, $value2, $value3); - } -} diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php new file mode 100644 index 000000000..dbc98bcf4 --- /dev/null +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -0,0 +1,48 @@ +setUpVfsDir(); + + parent::setUp(); + } + + protected function getInstance() + { + $logger = new NullLogger(); + $profiler = \Mockery::mock(Profiler::class); + $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true); + + // load real config to avoid mocking every config-entry which is related to the Database class + $configFactory = new ConfigFactory(); + $loader = new ConfigFileLoader($this->root->url()); + $configCache = $configFactory->createCache($loader); + + $dba = new StaticDatabase($configCache, $profiler, $logger); + + $this->cache = new Cache\DatabaseCache('database', $dba); + return $this->cache; + } + + public function tearDown() + { + $this->cache->clear(false); + parent::tearDown(); + } +} diff --git a/tests/src/Core/Cache/MemcacheCacheDriverTest.php b/tests/src/Core/Cache/MemcacheCacheTest.php similarity index 60% rename from tests/src/Core/Cache/MemcacheCacheDriverTest.php rename to tests/src/Core/Cache/MemcacheCacheTest.php index f8de88ac9..ccc372315 100644 --- a/tests/src/Core/Cache/MemcacheCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcacheCacheTest.php @@ -1,30 +1,30 @@ configMock + $configMock = \Mockery::mock(Configuration::class); + + $configMock ->shouldReceive('get') ->with('system', 'memcache_host') ->andReturn('localhost'); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'memcache_port') ->andReturn(11211); - $this->cache = CacheDriverFactory::create('memcache'); + $this->cache = new MemcacheCache('localhost', $configMock); return $this->cache; - } public function tearDown() diff --git a/tests/src/Core/Cache/MemcachedCacheDriverTest.php b/tests/src/Core/Cache/MemcachedCacheTest.php similarity index 52% rename from tests/src/Core/Cache/MemcachedCacheDriverTest.php rename to tests/src/Core/Cache/MemcachedCacheTest.php index 9f0ed8d4f..d88725019 100644 --- a/tests/src/Core/Cache/MemcachedCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcachedCacheTest.php @@ -3,21 +3,27 @@ namespace Friendica\Test\src\Core\Cache; -use Friendica\Factory\CacheDriverFactory; +use Friendica\Core\Cache\MemcachedCache; +use Friendica\Core\Config\Configuration; +use Psr\Log\NullLogger; /** * @requires extension memcached */ -class MemcachedCacheDriverTest extends MemoryCacheTest +class MemcachedCacheTest extends MemoryCacheTest { protected function getInstance() { - $this->configMock + $configMock = \Mockery::mock(Configuration::class); + + $configMock ->shouldReceive('get') ->with('system', 'memcached_hosts') ->andReturn([0 => 'localhost, 11211']); - $this->cache = CacheDriverFactory::create('memcached'); + $logger = new NullLogger(); + + $this->cache = new MemcachedCache('localhost', $configMock, $logger); return $this->cache; } diff --git a/tests/src/Core/Cache/MemoryCacheTest.php b/tests/src/Core/Cache/MemoryCacheTest.php index 6688153b0..19c102396 100644 --- a/tests/src/Core/Cache/MemoryCacheTest.php +++ b/tests/src/Core/Cache/MemoryCacheTest.php @@ -2,14 +2,12 @@ namespace Friendica\Test\src\Core\Cache; -use Friendica\Core\Cache\IMemoryCacheDriver; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; +use Friendica\Core\Cache\IMemoryCache; abstract class MemoryCacheTest extends CacheTest { /** - * @var \Friendica\Core\Cache\IMemoryCacheDriver + * @var \Friendica\Core\Cache\IMemoryCache */ protected $instance; @@ -17,12 +15,7 @@ abstract class MemoryCacheTest extends CacheTest { parent::setUp(); - $logger = new NullLogger(); - $this->dice->shouldReceive('create') - ->with(LoggerInterface::class) - ->andReturn($logger); - - if (!($this->instance instanceof IMemoryCacheDriver)) { + if (!($this->instance instanceof IMemoryCache)) { throw new \Exception('MemoryCacheTest unsupported'); } } @@ -31,7 +24,8 @@ abstract class MemoryCacheTest extends CacheTest * @small * @dataProvider dataSimple */ - function testCompareSet($value1, $value2) { + function testCompareSet($value1, $value2) + { $this->assertNull($this->instance->get('value1')); $this->instance->add('value1', $value1); @@ -47,7 +41,8 @@ abstract class MemoryCacheTest extends CacheTest * @small * @dataProvider dataSimple */ - function testNegativeCompareSet($value1, $value2) { + function testNegativeCompareSet($value1, $value2) + { $this->assertNull($this->instance->get('value1')); $this->instance->add('value1', $value1); @@ -64,7 +59,8 @@ abstract class MemoryCacheTest extends CacheTest * @small * @dataProvider dataSimple */ - function testCompareDelete($data) { + function testCompareDelete($data) + { $this->assertNull($this->instance->get('value1')); $this->instance->add('value1', $data); @@ -78,7 +74,8 @@ abstract class MemoryCacheTest extends CacheTest * @small * @dataProvider dataSimple */ - function testNegativeCompareDelete($data) { + function testNegativeCompareDelete($data) + { $this->assertNull($this->instance->get('value1')); $this->instance->add('value1', $data); @@ -95,7 +92,8 @@ abstract class MemoryCacheTest extends CacheTest * @small * @dataProvider dataSimple */ - function testAdd($value1, $value2) { + function testAdd($value1, $value2) + { $this->assertNull($this->instance->get('value1')); $this->instance->add('value1', $value1); @@ -111,4 +109,4 @@ abstract class MemoryCacheTest extends CacheTest $this->assertEquals($value2, $received, 'Value was not overwritten by add'); $this->assertNotEquals($value1, $received, 'Value was not overwritten by any other value'); } -} \ No newline at end of file +} diff --git a/tests/src/Core/Cache/RedisCacheDriverTest.php b/tests/src/Core/Cache/RedisCacheTest.php similarity index 62% rename from tests/src/Core/Cache/RedisCacheDriverTest.php rename to tests/src/Core/Cache/RedisCacheTest.php index 6e11c3b8a..df353252d 100644 --- a/tests/src/Core/Cache/RedisCacheDriverTest.php +++ b/tests/src/Core/Cache/RedisCacheTest.php @@ -3,36 +3,37 @@ namespace Friendica\Test\src\Core\Cache; -use Friendica\Factory\CacheDriverFactory; +use Friendica\Core\Cache\RedisCache; +use Friendica\Core\Config\Configuration; /** * @requires extension redis */ -class RedisCacheDriverTest extends MemoryCacheTest +class RedisCacheTest extends MemoryCacheTest { protected function getInstance() { - $this->configMock + $configMock = \Mockery::mock(Configuration::class); + + $configMock ->shouldReceive('get') ->with('system', 'redis_host') ->andReturn('localhost'); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'redis_port') ->andReturn(null); - $this->configMock + $configMock ->shouldReceive('get') - ->with('system', 'redis_db') + ->with('system', 'redis_db', 0) ->andReturn(3); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'redis_password') ->andReturn(null); - $this->cache = CacheDriverFactory::create('redis'); + $this->cache = new RedisCache('localhost', $configMock); return $this->cache; } diff --git a/tests/src/Core/Lock/APCuCacheLockDriverTest.php b/tests/src/Core/Lock/APCuCacheLockTest.php similarity index 66% rename from tests/src/Core/Lock/APCuCacheLockDriverTest.php rename to tests/src/Core/Lock/APCuCacheLockTest.php index 6e185d6b9..3fbb3605a 100644 --- a/tests/src/Core/Lock/APCuCacheLockDriverTest.php +++ b/tests/src/Core/Lock/APCuCacheLockTest.php @@ -2,11 +2,10 @@ namespace Friendica\Test\src\Core\Lock; - use Friendica\Core\Cache\APCuCache; -use Friendica\Core\Lock\CacheLockDriver; +use Friendica\Core\Lock\CacheLock; -class APCuCacheLockDriverTest extends LockTest +class APCuCacheLockTest extends LockTest { protected function setUp() { @@ -19,6 +18,6 @@ class APCuCacheLockDriverTest extends LockTest protected function getInstance() { - return new CacheLockDriver(new APCuCache()); + return new CacheLock(new APCuCache('localhost')); } } diff --git a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php b/tests/src/Core/Lock/ArrayCacheLockTest.php similarity index 61% rename from tests/src/Core/Lock/ArrayCacheLockDriverTest.php rename to tests/src/Core/Lock/ArrayCacheLockTest.php index 671341718..cc35d7f5e 100644 --- a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php +++ b/tests/src/Core/Lock/ArrayCacheLockTest.php @@ -2,15 +2,14 @@ namespace Friendica\Test\src\Core\Lock; - use Friendica\Core\Cache\ArrayCache; -use Friendica\Core\Lock\CacheLockDriver; +use Friendica\Core\Lock\CacheLock; -class ArrayCacheLockDriverTest extends LockTest +class ArrayCacheLockTest extends LockTest { protected function getInstance() { - return new CacheLockDriver(new ArrayCache()); + return new CacheLock(new ArrayCache('localhost')); } public function testLockTTL() diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php deleted file mode 100644 index 297e76d50..000000000 --- a/tests/src/Core/Lock/DatabaseLockDriverTest.php +++ /dev/null @@ -1,118 +0,0 @@ -mockConnected(); - $this->mockConnect(); - - $this->mockReleaseAll($this->pid, 2); - - parent::setUp(); - } - - protected function getInstance() - { - return new DatabaseLockDriver($this->pid); - } - - public function testLock() - { - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockIsLocked('foo', true, $this->startTime, 1); - $this->mockIsLocked('bar', false, $this->startTime, 1); - - parent::testLock(); - } - - public function testDoubleLock() - { - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockIsLocked('foo', true, $this->startTime, 1); - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, true, $this->pid, true, $this->startTime, 1); - - parent::testDoubleLock(); - } - - public function testReleaseLock() - { - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockIsLocked('foo', true, $this->startTime, 1); - $this->mockReleaseLock('foo', $this->pid, 1); - $this->mockIsLocked('foo', false, $this->startTime, 1); - - parent::testReleaseLock(); - } - - public function testReleaseAll() - { - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockAcquireLock('bar', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockAcquireLock('nice', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - - $this->mockIsLocked('foo', true, $this->startTime, 1); - $this->mockIsLocked('bar', true, $this->startTime, 1); - $this->mockIsLocked('nice', true, $this->startTime, 1); - - $this->mockReleaseAll($this->pid, 1); - - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockIsLocked('bar', false, $this->startTime, 1); - $this->mockIsLocked('nice', false, $this->startTime, 1); - - parent::testReleaseAll(); - } - - public function testReleaseAfterUnlock() - { - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockIsLocked('bar', false, $this->startTime, 1); - $this->mockIsLocked('nice', false, $this->startTime, 1); - - $this->mockAcquireLock('foo', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockAcquireLock('bar', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - $this->mockAcquireLock('nice', Cache::FIVE_MINUTES, false, $this->pid, false, $this->startTime, 1); - - $this->mockReleaseLock('foo', $this->pid, 1); - - $this->mockIsLocked('foo', false, $this->startTime, 1); - $this->mockIsLocked('bar', true, $this->startTime, 1); - $this->mockIsLocked('nice', true, $this->startTime, 1); - - $this->mockReleaseAll($this->pid, 1); - - $this->mockIsLocked('bar', false, $this->startTime, 1); - $this->mockIsLocked('nice', false, $this->startTime, 1); - - parent::testReleaseAfterUnlock(); - } - - public function testReleaseWitTTL() - { - $this->mockIsLocked('test', false, $this->startTime, 1); - $this->mockAcquireLock('test', 10, false, $this->pid, false, $this->startTime, 1); - $this->mockIsLocked('test', true, $this->startTime, 1); - $this->mockReleaseLock('test', $this->pid, 1); - $this->mockIsLocked('test', false, $this->startTime, 1); - - parent::testReleaseWitTTL(); - } -} diff --git a/tests/src/Core/Lock/DatabaseLockTest.php b/tests/src/Core/Lock/DatabaseLockTest.php new file mode 100644 index 000000000..2b20b2c10 --- /dev/null +++ b/tests/src/Core/Lock/DatabaseLockTest.php @@ -0,0 +1,43 @@ +setUpVfsDir(); + + parent::setUp(); + } + + protected function getInstance() + { + $logger = new NullLogger(); + $profiler = \Mockery::mock(Profiler::class); + $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true); + + // load real config to avoid mocking every config-entry which is related to the Database class + $configFactory = new ConfigFactory(); + $loader = new ConfigFileLoader($this->root->url()); + $configCache = $configFactory->createCache($loader); + + $dba = new StaticDatabase($configCache, $profiler, $logger); + + return new DatabaseLock($dba, $this->pid); + } +} diff --git a/tests/src/Core/Lock/LockTest.php b/tests/src/Core/Lock/LockTest.php index 59d6ee2d5..0c231713a 100644 --- a/tests/src/Core/Lock/LockTest.php +++ b/tests/src/Core/Lock/LockTest.php @@ -3,23 +3,16 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\Test\MockedTest; -use Friendica\Test\Util\AppMockTrait; -use Friendica\Test\Util\VFSTrait; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; abstract class LockTest extends MockedTest { - use VFSTrait; - use AppMockTrait; - /** * @var int Start time of the mock (used for time operations) */ protected $startTime = 1417011228; /** - * @var \Friendica\Core\Lock\ILockDriver + * @var \Friendica\Core\Lock\ILock */ protected $instance; @@ -27,19 +20,8 @@ abstract class LockTest extends MockedTest protected function setUp() { - // Reusable App object - $this->setUpVfsDir(); - $this->mockApp($this->root); - $this->app - ->shouldReceive('getHostname') - ->andReturn('friendica.local'); - - $logger = new NullLogger(); - $this->dice->shouldReceive('create') - ->with(LoggerInterface::class) - ->andReturn($logger); - parent::setUp(); + $this->instance = $this->getInstance(); $this->instance->releaseAll(); } @@ -53,7 +35,8 @@ abstract class LockTest extends MockedTest /** * @small */ - public function testLock() { + public function testLock() + { $this->assertFalse($this->instance->isLocked('foo')); $this->assertTrue($this->instance->acquireLock('foo', 1)); $this->assertTrue($this->instance->isLocked('foo')); @@ -63,7 +46,8 @@ abstract class LockTest extends MockedTest /** * @small */ - public function testDoubleLock() { + public function testDoubleLock() + { $this->assertFalse($this->instance->isLocked('foo')); $this->assertTrue($this->instance->acquireLock('foo', 1)); $this->assertTrue($this->instance->isLocked('foo')); @@ -74,7 +58,8 @@ abstract class LockTest extends MockedTest /** * @small */ - public function testReleaseLock() { + public function testReleaseLock() + { $this->assertFalse($this->instance->isLocked('foo')); $this->assertTrue($this->instance->acquireLock('foo', 1)); $this->assertTrue($this->instance->isLocked('foo')); @@ -85,7 +70,8 @@ abstract class LockTest extends MockedTest /** * @small */ - public function testReleaseAll() { + public function testReleaseAll() + { $this->assertTrue($this->instance->acquireLock('foo', 1)); $this->assertTrue($this->instance->acquireLock('bar', 1)); $this->assertTrue($this->instance->acquireLock('nice', 1)); @@ -104,7 +90,8 @@ abstract class LockTest extends MockedTest /** * @small */ - public function testReleaseAfterUnlock() { + public function testReleaseAfterUnlock() + { $this->assertFalse($this->instance->isLocked('foo')); $this->assertFalse($this->instance->isLocked('bar')); $this->assertFalse($this->instance->isLocked('nice')); @@ -139,7 +126,8 @@ abstract class LockTest extends MockedTest /** * @medium */ - function testLockTTL() { + function testLockTTL() + { $this->markTestSkipped('taking too much time without mocking'); $this->assertFalse($this->instance->isLocked('foo')); diff --git a/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php b/tests/src/Core/Lock/MemcacheCacheLockTest.php similarity index 50% rename from tests/src/Core/Lock/MemcacheCacheLockDriverTest.php rename to tests/src/Core/Lock/MemcacheCacheLockTest.php index 8d32ad527..f550ac51a 100644 --- a/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php +++ b/tests/src/Core/Lock/MemcacheCacheLockTest.php @@ -3,26 +3,28 @@ namespace Friendica\Test\src\Core\Lock; -use Friendica\Factory\CacheDriverFactory; -use Friendica\Core\Lock\CacheLockDriver; +use Friendica\Core\Cache\MemcacheCache; +use Friendica\Core\Config\Configuration; +use Friendica\Core\Lock\CacheLock; /** * @requires extension Memcache */ -class MemcacheCacheLockDriverTest extends LockTest +class MemcacheCacheLockTest extends LockTest { protected function getInstance() { - $this->configMock + $configMock = \Mockery::mock(Configuration::class); + + $configMock ->shouldReceive('get') ->with('system', 'memcache_host') ->andReturn('localhost'); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'memcache_port') ->andReturn(11211); - return new CacheLockDriver(CacheDriverFactory::create('memcache')); + return new CacheLock(new MemcacheCache('localhost', $configMock)); } } diff --git a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php deleted file mode 100644 index f08ffa381..000000000 --- a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php +++ /dev/null @@ -1,23 +0,0 @@ -configMock - ->shouldReceive('get') - ->with('system', 'memcached_hosts') - ->andReturn([0 => 'localhost, 11211']); - - return new CacheLockDriver(CacheDriverFactory::create('memcached')); - } -} diff --git a/tests/src/Core/Lock/MemcachedCacheLockTest.php b/tests/src/Core/Lock/MemcachedCacheLockTest.php new file mode 100644 index 000000000..8b59f91bb --- /dev/null +++ b/tests/src/Core/Lock/MemcachedCacheLockTest.php @@ -0,0 +1,29 @@ +shouldReceive('get') + ->with('system', 'memcached_hosts') + ->andReturn([0 => 'localhost, 11211']); + + $logger = new NullLogger(); + + return new CacheLock(new MemcachedCache('localhost', $configMock, $logger)); + } +} diff --git a/tests/src/Core/Lock/RedisCacheLockDriverTest.php b/tests/src/Core/Lock/RedisCacheLockTest.php similarity index 54% rename from tests/src/Core/Lock/RedisCacheLockDriverTest.php rename to tests/src/Core/Lock/RedisCacheLockTest.php index 21bace501..0ebc02160 100644 --- a/tests/src/Core/Lock/RedisCacheLockDriverTest.php +++ b/tests/src/Core/Lock/RedisCacheLockTest.php @@ -3,36 +3,37 @@ namespace Friendica\Test\src\Core\Lock; -use Friendica\Core\Lock\CacheLockDriver; -use Friendica\Factory\CacheDriverFactory; +use Friendica\Core\Cache\RedisCache; +use Friendica\Core\Config\Configuration; +use Friendica\Core\Lock\CacheLock; /** * @requires extension redis */ -class RedisCacheLockDriverTest extends LockTest +class RedisCacheLockTest extends LockTest { protected function getInstance() { - $this->configMock + $configMock = \Mockery::mock(Configuration::class); + + $configMock ->shouldReceive('get') ->with('system', 'redis_host') ->andReturn('localhost'); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'redis_port') ->andReturn(null); - $this->configMock + $configMock ->shouldReceive('get') - ->with('system', 'redis_db') + ->with('system', 'redis_db', 0) ->andReturn(3); - - $this->configMock + $configMock ->shouldReceive('get') ->with('system', 'redis_password') ->andReturn(null); - return new CacheLockDriver(CacheDriverFactory::create('redis')); + return new CacheLock(new RedisCache('localhost', $configMock)); } } diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php deleted file mode 100644 index a37fbffbe..000000000 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ /dev/null @@ -1,31 +0,0 @@ -app->shouldReceive('getHostname')->andReturn('friendica.local'); - - $this->configMock - ->shouldReceive('get') - ->with('system', 'temppath') - ->andReturn('/tmp/'); - } - - protected function getInstance() - { - return new SemaphoreLockDriver(); - } - - function testLockTTL() - { - // Semaphore doesn't work with TTL - return true; - } -} diff --git a/tests/src/Core/Lock/SemaphoreLockTest.php b/tests/src/Core/Lock/SemaphoreLockTest.php new file mode 100644 index 000000000..7b9b03d72 --- /dev/null +++ b/tests/src/Core/Lock/SemaphoreLockTest.php @@ -0,0 +1,44 @@ +makePartial(); + + $app = \Mockery::mock(App::class); + $app->shouldReceive('getHostname')->andReturn('friendica.local'); + $dice->shouldReceive('create')->with(App::class)->andReturn($app); + + $configMock = \Mockery::mock(Configuration::class); + $configMock + ->shouldReceive('get') + ->with('system', 'temppath', NULL, false) + ->andReturn('/tmp/'); + $dice->shouldReceive('create')->with(Configuration::class)->andReturn($configMock); + + // @todo Because "get_temppath()" is using static methods, we have to initialize the BaseObject + BaseObject::setDependencyInjection($dice); + } + + protected function getInstance() + { + return new SemaphoreLock(); + } + + function testLockTTL() + { + // Semaphore doesn't work with TTL + return true; + } +} diff --git a/tests/src/Database/DBATest.php b/tests/src/Database/DBATest.php index 6d52581a9..9b2a2f122 100644 --- a/tests/src/Database/DBATest.php +++ b/tests/src/Database/DBATest.php @@ -15,9 +15,9 @@ class DBATest extends DatabaseTest { parent::setUp(); - $dice = new Dice(); - $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php'); - $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); + $dice = (new Dice()) + ->addRules(include __DIR__ . '/../../../static/dependencies.config.php') + ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); BaseObject::setDependencyInjection($dice); // Default config diff --git a/tests/src/Database/DBStructureTest.php b/tests/src/Database/DBStructureTest.php index e2938e304..38c621d4c 100644 --- a/tests/src/Database/DBStructureTest.php +++ b/tests/src/Database/DBStructureTest.php @@ -15,9 +15,9 @@ class DBStructureTest extends DatabaseTest { parent::setUp(); - $dice = new Dice(); - $dice = $dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php'); - $dice = $dice->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); + $dice = (new Dice()) + ->addRules(include __DIR__ . '/../../../static/dependencies.config.php') + ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]); BaseObject::setDependencyInjection($dice); }