]> git.mxchange.org Git - friendica.git/commitdiff
Add a bunch of tests for StatsCaching
authorPhilipp <admin@philipp.info>
Sat, 26 Apr 2025 23:36:30 +0000 (01:36 +0200)
committerPhilipp <admin@philipp.info>
Sun, 27 Apr 2025 19:26:48 +0000 (21:26 +0200)
15 files changed:
composer.json
composer.lock
src/Module/StatsCaching.php
tests/CacheLockTestCase.php [new file with mode: 0644]
tests/LockTestCase.php
tests/src/Core/Cache/ArrayCacheTest.php
tests/src/Core/Cache/ProfilerCacheDecoratorTest.php [new file with mode: 0644]
tests/src/Core/Lock/APCuCacheLockTest.php
tests/src/Core/Lock/ArrayCacheLockTest.php
tests/src/Core/Lock/DatabaseLockDriverTest.php
tests/src/Core/Lock/MemcacheCacheLockTest.php
tests/src/Core/Lock/MemcachedCacheLockTest.php
tests/src/Core/Lock/RedisCacheLockTest.php
tests/src/Core/Lock/SemaphoreLockTest.php
tests/src/Module/StatsCachingTest.php [new file with mode: 0644]

index a2c9eea3c9d8bb7914aaa8b0c4621c17df30d846..655f987df91ebf1bc70b310eba46670db83a1941 100644 (file)
                "dms/phpunit-arraysubset-asserts": "^0.3.1",
                "mikey179/vfsstream": "^1.6",
                "mockery/mockery": "^1.3",
+               "php-mock/php-mock-mockery": "^1.5",
                "php-mock/php-mock-phpunit": "^2.10",
                "phpmd/phpmd": "^2.15",
                "phpstan/phpstan": "^2.0",
index e12cc6533c666b0b632961af94195856e1d0d1f0..bae30155dd9d4be194435fb7919449c60d8c8aee 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "b77bf714197f04022a5feb001bf07852",
+    "content-hash": "32af97f73ec49df2a6cfe98f11bc1d60",
     "packages": [
         {
             "name": "asika/simple-console",
             ],
             "time": "2024-02-10T21:37:25+00:00"
         },
+        {
+            "name": "php-mock/php-mock-mockery",
+            "version": "1.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-mock/php-mock-mockery.git",
+                "reference": "291994acdc26daf1e3c659cfbe58b01eeb180b7f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-mock/php-mock-mockery/zipball/291994acdc26daf1e3c659cfbe58b01eeb180b7f",
+                "reference": "291994acdc26daf1e3c659cfbe58b01eeb180b7f",
+                "shasum": ""
+            },
+            "require": {
+                "mockery/mockery": "^1",
+                "php": ">=5.6",
+                "php-mock/php-mock-integration": "^2.2.1 || ^3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4|^5|^8"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "phpmock\\mockery\\": "classes/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "WTFPL"
+            ],
+            "authors": [
+                {
+                    "name": "Markus Malkusch",
+                    "email": "markus@malkusch.de",
+                    "homepage": "http://markus.malkusch.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Mock built-in PHP functions (e.g. time()) with Mockery. This package relies on PHP's namespace fallback policy. No further extension is needed.",
+            "homepage": "https://github.com/php-mock/php-mock-mockery",
+            "keywords": [
+                "BDD",
+                "TDD",
+                "function",
+                "mock",
+                "mockery",
+                "stub",
+                "test",
+                "test double",
+                "testing"
+            ],
+            "support": {
+                "issues": "https://github.com/php-mock/php-mock-mockery/issues",
+                "source": "https://github.com/php-mock/php-mock-mockery/tree/1.5.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/michalbundyra",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-03-08T19:46:20+00:00"
+        },
         {
             "name": "php-mock/php-mock-phpunit",
             "version": "2.10.0",
index 6247eca9c19ca4413cdb99d33bfbc4f221dedade..668d26e0219533150f75d39d97697a5298e638f3 100644 (file)
@@ -15,6 +15,7 @@ use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\L10n;
 use Friendica\Core\Lock\Capability\ICanLock;
 use Friendica\Core\Lock\Type\CacheLock;
+use Friendica\Network\HTTPException\NotFoundException;
 use Friendica\Util\Profiler;
 use Psr\Log\LoggerInterface;
 use Friendica\Network\HTTPException;
@@ -41,9 +42,12 @@ class StatsCaching extends BaseModule
 
        private function isAllowed(array $request): bool
        {
-               return empty(!$request['key']) && $request['key'] == $this->config->get('system', 'stats_key');
+               return !empty($request['key']) && $request['key'] == $this->config->get('system', 'stats_key');
        }
 
+       /**
+        * @throws NotFoundException In case the rquest isn't allowed
+        */
        protected function content(array $request = []): string
        {
                if (!$this->isAllowed($request)) {
@@ -98,6 +102,7 @@ class StatsCaching extends BaseModule
                        ];
                }
 
-               $this->jsonExit($data);
+               $this->response->setType('json', 'application/json; charset=utf-8');
+               $this->response->addContent(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
        }
 }
diff --git a/tests/CacheLockTestCase.php b/tests/CacheLockTestCase.php
new file mode 100644 (file)
index 0000000..1599391
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Friendica\Test;
+
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
+use Friendica\Core\Lock\Capability\ICanLock;
+
+abstract class CacheLockTestCase extends LockTestCase
+{
+       abstract protected function getCache(): ICanCacheInMemory;
+
+       abstract protected function getInstance(): ICanLock;
+
+       /**
+        * Test if the getStats() result is identically to the getCacheStats()
+        */
+       public function testGetStats()
+       {
+               self::assertSame(array_keys($this->getCache()->getStats()), array_keys($this->instance->getCacheStats()));
+       }
+}
index 9ce86497b717a6d17a71619149b1a1aaec2a679e..1b80e575ef7120edaee0db9b79807e8151b1c2bc 100644 (file)
@@ -7,22 +7,21 @@
 
 namespace Friendica\Test;
 
+use Friendica\Core\Cache\Capability\ICanCache;
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Lock\Capability\ICanLock;
-use Friendica\Test\MockedTestCase;
+use Friendica\Core\Lock\Type\CacheLock;
 
 abstract class LockTestCase extends MockedTestCase
 {
        /**
-        * @var int Start time of the mock (used for time operations)
+        * Start time of the mock (used for time operations)
         */
-       protected $startTime = 1417011228;
+       protected int $startTime = 1417011228;
+       protected ICanLock $instance;
 
-       /**
-        * @var ICanLock
-        */
-       protected $instance;
+       abstract protected function getInstance(): ICanLock;
 
-       abstract protected function getInstance();
 
        protected function setUp(): void
        {
@@ -205,4 +204,6 @@ abstract class LockTestCase extends MockedTestCase
                self::assertFalse($this->instance->isLocked('wrongLock'));
                self::assertFalse($this->instance->release('wrongLock'));
        }
+
+
 }
index 967cb07bce17ebca147c22bb197899527c591f59..50226b09071955ec8e31df46490d7b2789ce6500 100644 (file)
@@ -33,4 +33,12 @@ class ArrayCacheTest extends MemoryCacheTestCase
                self::markTestSkipped("Array Cache doesn't support TTL");
                return true;
        }
+
+       /**
+        * @small
+        */
+       public function testGetStats()
+       {
+               self::assertEmpty($this->cache->getStats());
+       }
 }
diff --git a/tests/src/Core/Cache/ProfilerCacheDecoratorTest.php b/tests/src/Core/Cache/ProfilerCacheDecoratorTest.php
new file mode 100644 (file)
index 0000000..3f44bcd
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Core\Cache;
+
+use Friendica\Core\Cache\Type\ArrayCache;
+use Friendica\Core\Cache\Type\ProfilerCacheDecorator;
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Test\MemoryCacheTestCase;
+use Friendica\Util\Profiler;
+
+class ProfilerCacheDecoratorTest extends MemoryCacheTestCase
+{
+       protected function getInstance()
+       {
+               $config = \Mockery::mock(IManageConfigValues::class);
+               $config->shouldReceive('get')->with('system', 'profiler')->once()->andReturn(false);
+               $config->shouldReceive('get')->with('rendertime', 'callstack')->once()->andReturn(false);
+
+               $this->cache = new ProfilerCacheDecorator(new ArrayCache('localhost'), new Profiler($config));
+               return $this->cache;
+       }
+
+       protected function tearDown(): void
+       {
+               $this->cache->clear(false);
+               parent::tearDown();
+       }
+
+       /**
+        * @doesNotPerformAssertions
+        */
+       public function testTTL()
+       {
+               // Array Cache doesn't support TTL
+               self::markTestSkipped("Array Cache doesn't support TTL");
+               return true;
+       }
+
+       /**
+        * @small
+        */
+       public function testGetStats()
+       {
+               self::assertEmpty($this->cache->getStats());
+       }
+
+       public function testGetName()
+       {
+               self::assertStringEndsWith(' (with profiler)', $this->instance->getName());
+       }
+}
index 3ee0d09661aa4899e669c8a912ec64bb2cceb7d8..42a1fc72d534f45f003a0cd04c7ba44dc7dc1fc4 100644 (file)
@@ -7,26 +7,39 @@
 
 namespace Friendica\Test\src\Core\Lock;
 
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Cache\Type\APCuCache;
+use Friendica\Core\Lock\Capability\ICanLock;
 use Friendica\Core\Lock\Type\CacheLock;
-use Friendica\Test\LockTestCase;
+use Friendica\Test\CacheLockTestCase;
 
 /**
  * @group APCU
  */
-class APCuCacheLockTest extends LockTestCase
+class APCuCacheLockTest extends CacheLockTestCase
 {
+       private APCuCache $cache;
+       private ICanLock $lock;
+
        protected function setUp(): void
        {
                if (!APCuCache::isAvailable()) {
                        static::markTestSkipped('APCu is not available');
                }
 
+               $this->cache = new APCuCache('localhost');
+               $this->lock = new CacheLock($this->cache);
+
                parent::setUp();
        }
 
-       protected function getInstance()
+       protected function getInstance(): CacheLock
+       {
+               return $this->lock;
+       }
+
+       protected function getCache(): ICanCacheInMemory
        {
-               return new CacheLock(new APCuCache('localhost'));
+               return $this->cache;
        }
 }
index 19ac7925c61ef803d43a6a45fb2d79d733350dde..2aac8e829338a92249c04ae53e8b39ade99261de 100644 (file)
@@ -7,15 +7,32 @@
 
 namespace Friendica\Test\src\Core\Lock;
 
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Cache\Type\ArrayCache;
 use Friendica\Core\Lock\Type\CacheLock;
-use Friendica\Test\LockTestCase;
+use Friendica\Test\CacheLockTestCase;
 
-class ArrayCacheLockTest extends LockTestCase
+class ArrayCacheLockTest extends CacheLockTestCase
 {
-       protected function getInstance()
+       private CacheLock $lock;
+       private ArrayCache $cache;
+
+       protected function setUp(): void
+       {
+               $this->cache = new ArrayCache('localhost');
+               $this->lock = new CacheLock($this->cache);
+
+               parent::setUp();
+       }
+
+       protected function getInstance(): CacheLock
+       {
+               return $this->lock;
+       }
+
+       protected function getCache(): ICanCacheInMemory
        {
-               return new CacheLock(new ArrayCache('localhost'));
+               return $this->cache;
        }
 
        /**
index ebc2b0090fbf7438ef0b71824ebce4c41eb52000..fbfe61762e3cc8af093c4d772330dc1f8870b08f 100644 (file)
@@ -7,6 +7,7 @@
 
 namespace Friendica\Test\src\Core\Lock;
 
+use Friendica\Core\Lock\Capability\ICanLock;
 use Friendica\Core\Lock\Type\DatabaseLock;
 use Friendica\Test\LockTestCase;
 use Friendica\Test\Util\CreateDatabaseTrait;
@@ -26,7 +27,7 @@ class DatabaseLockDriverTest extends LockTestCase
                parent::setUp();
        }
 
-       protected function getInstance()
+       protected function getInstance(): ICanLock
        {
                return new DatabaseLock($this->getDbInstance(), $this->pid);
        }
index 2bb0595cff3738a8ca0fd38863d1576b1ea5a5c1..c1dec663f117727cada479fa7aa170ec85ab1037 100644 (file)
@@ -8,19 +8,23 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Cache\Type\MemcacheCache;
 use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\Lock\Type\CacheLock;
-use Friendica\Test\LockTestCase;
+use Friendica\Test\CacheLockTestCase;
 use Mockery;
 
 /**
  * @requires extension Memcache
  * @group MEMCACHE
  */
-class MemcacheCacheLockTest extends LockTestCase
+class MemcacheCacheLockTest extends CacheLockTestCase
 {
-       protected function getInstance()
+       private CacheLock $lock;
+       private MemcacheCache $cache;
+
+       protected function setUp(): void
        {
                $configMock = Mockery::mock(IManageConfigValues::class);
 
@@ -36,16 +40,24 @@ class MemcacheCacheLockTest extends LockTestCase
                        ->with('system', 'memcache_port')
                        ->andReturn($port);
 
-               $lock = null;
-
                try {
-                       $cache = new MemcacheCache($host, $configMock);
-                       $lock = new CacheLock($cache);
+                       $this->cache = new MemcacheCache($host, $configMock);
+                       $this->lock = new CacheLock($this->cache);
                } catch (Exception $e) {
                        static::markTestSkipped('Memcache is not available');
                }
 
-               return $lock;
+               parent::setUp();
+       }
+
+       protected function getInstance(): CacheLock
+       {
+               return $this->lock;
+       }
+
+       protected function getCache(): ICanCacheInMemory
+       {
+               return $this->cache;
        }
 
        /**
index fb38ec3312b12fc407bc25f7bddf77ed2498dae3..773e664108502ab51fe29cb93375fcbdfd370307 100644 (file)
@@ -8,9 +8,11 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Cache\Type\MemcachedCache;
 use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\Lock\Type\CacheLock;
+use Friendica\Test\CacheLockTestCase;
 use Friendica\Test\LockTestCase;
 use Mockery;
 use Psr\Log\NullLogger;
@@ -19,9 +21,12 @@ use Psr\Log\NullLogger;
  * @requires extension memcached
  * @group MEMCACHED
  */
-class MemcachedCacheLockTest extends LockTestCase
+class MemcachedCacheLockTest extends CacheLockTestCase
 {
-       protected function getInstance()
+       private MemcachedCache $cache;
+       private CacheLock $lock;
+
+       protected function setUp(): void
        {
                $configMock = Mockery::mock(IManageConfigValues::class);
 
@@ -35,16 +40,24 @@ class MemcachedCacheLockTest extends LockTestCase
 
                $logger = new NullLogger();
 
-               $lock = null;
-
                try {
-                       $cache = new MemcachedCache($host, $configMock, $logger);
-                       $lock = new CacheLock($cache);
+                       $this->cache = new MemcachedCache($host, $configMock, $logger);
+                       $this->lock = new CacheLock($this->cache);
                } catch (Exception $e) {
                        static::markTestSkipped('Memcached is not available');
                }
 
-               return $lock;
+               parent::setUp();
+       }
+
+       protected function getInstance(): CacheLock
+       {
+               return $this->lock;
+       }
+
+       protected function getCache(): ICanCacheInMemory
+       {
+               return $this->cache;
        }
 
        /**
index d0237682c3d5065404fd9d73d261a7dcd150a766..3cb4fba43685c1053ffef12d6cc2105f5663b8a1 100644 (file)
@@ -8,9 +8,11 @@
 namespace Friendica\Test\src\Core\Lock;
 
 use Exception;
+use Friendica\Core\Cache\Capability\ICanCacheInMemory;
 use Friendica\Core\Cache\Type\RedisCache;
 use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\Lock\Type\CacheLock;
+use Friendica\Test\CacheLockTestCase;
 use Friendica\Test\LockTestCase;
 use Mockery;
 
@@ -18,9 +20,9 @@ use Mockery;
  * @requires extension redis
  * @group REDIS
  */
-class RedisCacheLockTest extends LockTestCase
+class RedisCacheLockTest extends CacheLockTestCase
 {
-       protected function getInstance()
+       protected function setUp(): void
        {
                $configMock = Mockery::mock(IManageConfigValues::class);
 
@@ -45,15 +47,23 @@ class RedisCacheLockTest extends LockTestCase
                        ->with('system', 'redis_password')
                        ->andReturn(null);
 
-               $lock = null;
-
                try {
-                       $cache = new RedisCache($host, $configMock);
-                       $lock = new CacheLock($cache);
+                       $this->cache = new RedisCache($host, $configMock);
+                       $this->lock = new CacheLock($this->cache);
                } catch (Exception $e) {
                        static::markTestSkipped('Redis is not available. Error: ' . $e->getMessage());
                }
 
-               return $lock;
+               parent::setUp();
+       }
+
+       protected function getInstance(): CAcheLock
+       {
+               return $this->lock;
+       }
+
+       protected function getCache(): ICanCacheInMemory
+       {
+               return $this->cache;
        }
 }
index 06b4e02f46a57568a0204960b89fce81c51afecb..1ddb2dade753bddfff0f8387aac602244c0e36d8 100644 (file)
@@ -12,6 +12,7 @@ use Friendica\App;
 use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 use Friendica\Core\Config\ValueObject\Cache;
+use Friendica\Core\Lock\Capability\ICanLock;
 use Friendica\Core\Lock\Type\SemaphoreLock;
 use Friendica\Core\System;
 use Friendica\DI;
@@ -40,7 +41,7 @@ class SemaphoreLockTest extends LockTestCase
                parent::setUp();
        }
 
-       protected function getInstance()
+       protected function getInstance(): ICanLock
        {
                return new SemaphoreLock();
        }
diff --git a/tests/src/Module/StatsCachingTest.php b/tests/src/Module/StatsCachingTest.php
new file mode 100644 (file)
index 0000000..08d4b8f
--- /dev/null
@@ -0,0 +1,205 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Friendica\Test\src\Module;
+
+use Friendica\Capabilities\ICanCreateResponses;
+use Friendica\Core\Cache\Capability\ICanCache;
+use Friendica\Core\Cache\Type\ArrayCache;
+use Friendica\Core\Cache\Type\DatabaseCache;
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\Lock\Capability\ICanLock;
+use Friendica\Core\Lock\Type\CacheLock;
+use Friendica\Core\Lock\Type\DatabaseLock;
+use Friendica\DI;
+use Friendica\Module\Special\HTTPException;
+use Friendica\Module\StatsCaching;
+use Friendica\Test\FixtureTestCase;
+use Mockery\MockInterface;
+use phpmock\mockery\PHPMockery;
+
+class StatsCachingTest extends FixtureTestCase
+{
+       /** @var MockInterface|HTTPException */
+       protected $httpExceptionMock;
+
+       protected ICanCache $cache;
+       protected ICanLock $lock;
+
+       /** @var MockInterface|IManageConfigValues */
+       protected $config;
+
+       protected function setUp(): void
+       {
+               parent::setUp();
+
+               $this->httpExceptionMock = \Mockery::mock(HTTPException::class);
+               $this->config = \Mockery::mock(IManageConfigValues::class);
+               $this->cache = new ArrayCache('localhost');
+               $this->lock = new CacheLock($this->cache);
+       }
+
+       public function testStatsCachingNotAllowed()
+       {
+               $this->httpExceptionMock->shouldReceive('content')->andReturn('failed')->once();
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock);
+
+               self::assertEquals('404', $response->getStatusCode());
+               self::assertEquals('Page not found', $response->getReasonPhrase());
+               self::assertEquals('failed', $response->getBody());
+       }
+
+       public function testStatsCachingWitMinimumCache()
+       {
+               $request = [
+                       'key' => '12345',
+               ];
+               $this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
+               PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock, $request);
+
+               self::assertJson($response->getBody());
+               self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
+
+               $json = json_decode($response->getBody(), true);
+
+               self::assertEquals([
+                       'type' => 'array',
+                       'stats' => [],
+               ], $json['cache']);
+               self::assertEquals([
+                       'type' => 'array',
+                       'stats' => [],
+               ], $json['lock']);
+       }
+
+       public function testStatsCachingWithDatabase()
+       {
+               $request = [
+                       'key' => '12345',
+               ];
+               $this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
+
+               $this->cache = new DatabaseCache('localhost', DI::dba());
+               $this->lock = new DatabaseLock(DI::dba());
+               PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock, $request);
+
+               self::assertJson($response->getBody());
+               self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
+
+               $json = json_decode($response->getBody(), true);
+
+               self::assertEquals(['enabled' => false], $json['opcache']);
+               self::assertEquals(['type' => 'database'], $json['cache']);
+               self::assertEquals(['type' => 'database'], $json['lock']);
+       }
+
+       public function testStatsCachingWithCache()
+       {
+               $request = [
+                       'key' => '12345',
+               ];
+               $this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
+
+               $this->cache = new DatabaseCache('localhost', DI::dba());
+               $this->lock = new DatabaseLock(DI::dba());
+               PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock, $request);
+
+               self::assertJson($response->getBody());
+               self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
+
+               $json = json_decode($response->getBody(), true);
+
+               self::assertEquals(['enabled' => false], $json['opcache']);
+               self::assertEquals(['type' => 'database'], $json['cache']);
+               self::assertEquals(['type' => 'database'], $json['lock']);
+       }
+
+       public function testStatsCachingWithOpcacheAndNull()
+       {
+               $request = [
+                       'key' => '12345',
+               ];
+               $this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
+
+               $this->cache = new DatabaseCache('localhost', DI::dba());
+               $this->lock = new DatabaseLock(DI::dba());
+               PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(true);
+               PHPMockery::mock("Friendica\\Module", "opcache_get_status")->with(false)->once()->andReturn(false);
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock, $request);
+
+               self::assertJson($response->getBody());
+               self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
+
+               $json = json_decode($response->getBody(), true);
+
+               print_r($json);
+
+               self::assertEquals([
+                       'enabled' => false,
+                       'hit_rate' => null,
+                       'used_memory' => null,
+                       'free_memory' => null,
+                       'num_cached_scripts' => null,
+               ], $json['opcache']);
+               self::assertEquals(['type' => 'database'], $json['cache']);
+               self::assertEquals(['type' => 'database'], $json['lock']);
+       }
+
+       public function testStatsCachingWithOpcacheAndValues()
+       {
+               $request = [
+                       'key' => '12345',
+               ];
+               $this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
+
+               $this->cache = new DatabaseCache('localhost', DI::dba());
+               $this->lock = new DatabaseLock(DI::dba());
+               PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(true);
+               PHPMockery::mock("Friendica\\Module", "opcache_get_status")->with(false)->once()->andReturn([
+                       'opcache_enabled' => true,
+                       'opcache_statistics' => [
+                               'opcache_hit_rate' => 1,
+                               'num_cached_scripts' => 2,
+                       ],
+                       'memory_usage' => [
+                               'used_memory' => 3,
+                               'free_memory' => 4,
+                       ]
+               ]);
+
+               $response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
+                       ->run($this->httpExceptionMock, $request);
+
+               self::assertJson($response->getBody());
+               self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
+
+               $json = json_decode($response->getBody(), true);
+
+               self::assertEquals([
+                       'enabled' => true,
+                       'hit_rate' => 1,
+                       'used_memory' => 3,
+                       'free_memory' => 4,
+                       'num_cached_scripts' => 2,
+               ], $json['opcache']);
+               self::assertEquals(['type' => 'database'], $json['cache']);
+               self::assertEquals(['type' => 'database'], $json['lock']);
+       }
+}