]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/StorageManagerTest.php
Merge remote-tracking branch 'upstream/develop' into improved-payload
[friendica.git] / tests / src / Core / StorageManagerTest.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Test\src\Core;
23
24 use Dice\Dice;
25 use Friendica\Core\Config\IConfig;
26 use Friendica\Core\Config\PreloadConfig;
27 use Friendica\Core\Hook;
28 use Friendica\Core\L10n;
29 use Friendica\Core\Session\ISession;
30 use Friendica\Core\StorageManager;
31 use Friendica\Database\Database;
32 use Friendica\DI;
33 use Friendica\Factory\ConfigFactory;
34 use Friendica\Model\Config\Config;
35 use Friendica\Model\Storage;
36 use Friendica\Core\Session;
37 use Friendica\Network\HTTPRequest;
38 use Friendica\Test\DatabaseTest;
39 use Friendica\Test\Util\Database\StaticDatabase;
40 use Friendica\Test\Util\VFSTrait;
41 use Friendica\Util\ConfigFileLoader;
42 use Friendica\Util\Profiler;
43 use Psr\Log\LoggerInterface;
44 use Psr\Log\NullLogger;
45 use Friendica\Test\Util\SampleStorageBackend;
46
47 class StorageManagerTest extends DatabaseTest
48 {
49         use VFSTrait;
50         /** @var Database */
51         private $dba;
52         /** @var IConfig */
53         private $config;
54         /** @var LoggerInterface */
55         private $logger;
56         /** @var L10n */
57         private $l10n;
58         /** @var HTTPRequest */
59         private $httpRequest;
60
61         protected function setUp(): void
62         {
63                 parent::setUp();
64
65                 $this->setUpVfsDir();
66
67                 $this->logger = new NullLogger();
68
69                 $profiler = \Mockery::mock(Profiler::class);
70                 $profiler->shouldReceive('startRecording');
71                 $profiler->shouldReceive('stopRecording');
72                 $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
73
74                 // load real config to avoid mocking every config-entry which is related to the Database class
75                 $configFactory = new ConfigFactory();
76                 $loader        = new ConfigFileLoader($this->root->url());
77                 $configCache   = $configFactory->createCache($loader);
78
79                 $this->dba = new StaticDatabase($configCache, $profiler, $this->logger);
80
81                 $configModel  = new Config($this->dba);
82                 $this->config = new PreloadConfig($configCache, $configModel);
83                 $this->config->set('storage', 'name', 'Database');
84
85                 $this->l10n = \Mockery::mock(L10n::class);
86
87                 $this->httpRequest = \Mockery::mock(HTTPRequest::class);
88         }
89
90         /**
91          * Test plain instancing first
92          */
93         public function testInstance()
94         {
95                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
96
97                 self::assertInstanceOf(StorageManager::class, $storageManager);
98         }
99
100         public function dataStorages()
101         {
102                 return [
103                         'empty' => [
104                                 'name'       => '',
105                                 'valid'      => false,
106                                 'interface'  => Storage\IStorage::class,
107                                 'assert'     => null,
108                                 'assertName' => '',
109                         ],
110                         'database' => [
111                                 'name'       => Storage\Database::NAME,
112                                 'valid'      => true,
113                                 'interface'  => Storage\IWritableStorage::class,
114                                 'assert'     => Storage\Database::class,
115                                 'assertName' => Storage\Database::NAME,
116                         ],
117                         'filesystem' => [
118                                 'name'       => Storage\Filesystem::NAME,
119                                 'valid'      => true,
120                                 'interface'  => Storage\IWritableStorage::class,
121                                 'assert'     => Storage\Filesystem::class,
122                                 'assertName' => Storage\Filesystem::NAME,
123                         ],
124                         'systemresource' => [
125                                 'name'       => Storage\SystemResource::NAME,
126                                 'valid'      => true,
127                                 'interface'  => Storage\IStorage::class,
128                                 'assert'     => Storage\SystemResource::class,
129                                 'assertName' => Storage\SystemResource::NAME,
130                         ],
131                         'invalid' => [
132                                 'name'        => 'invalid',
133                                 'valid'       => false,
134                                 'interface'   => null,
135                                 'assert'      => null,
136                                 'assertName'  => '',
137                                 'userBackend' => false,
138                         ],
139                 ];
140         }
141
142         /**
143          * Test the getByName() method
144          *
145          * @dataProvider dataStorages
146          */
147         public function testGetByName($name, $valid, $interface, $assert, $assertName)
148         {
149                 if (!$valid) {
150                         $this->expectException(Storage\InvalidClassStorageException::class);
151                 }
152
153                 if ($interface === Storage\IWritableStorage::class) {
154                         $this->config->set('storage', 'name', $name);
155                 }
156
157                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
158
159                 if ($interface === Storage\IWritableStorage::class) {
160                         $storage = $storageManager->getWritableStorageByName($name);
161                 } else {
162                         $storage = $storageManager->getByName($name);
163                 }
164
165                 self::assertInstanceOf($interface, $storage);
166                 self::assertInstanceOf($assert, $storage);
167                 self::assertEquals($assertName, $storage);
168         }
169
170         /**
171          * Test the isValidBackend() method
172          *
173          * @dataProvider dataStorages
174          */
175         public function testIsValidBackend($name, $valid, $interface, $assert, $assertName)
176         {
177                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
178
179                 // true in every of the backends
180                 self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
181
182                 // if it's a IWritableStorage, the valid backend should return true, otherwise false
183                 self::assertEquals($interface === Storage\IWritableStorage::class, $storageManager->isValidBackend($name, StorageManager::DEFAULT_BACKENDS));
184         }
185
186         /**
187          * Test the method listBackends() with default setting
188          */
189         public function testListBackends()
190         {
191                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
192
193                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
194         }
195
196         /**
197          * Test the method getBackend()
198          *
199          * @dataProvider dataStorages
200          */
201         public function testGetBackend($name, $valid, $interface, $assert, $assertName)
202         {
203                 if ($interface !== Storage\IWritableStorage::class) {
204                         static::markTestSkipped('only works for IWritableStorage');
205                 }
206
207                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
208
209                 $selBackend = $storageManager->getWritableStorageByName($name);
210                 $storageManager->setBackend($selBackend);
211
212                 self::assertInstanceOf($assert, $storageManager->getBackend());
213         }
214
215         /**
216          * Test the method getBackend() with a pre-configured backend
217          *
218          * @dataProvider dataStorages
219          */
220         public function testPresetBackend($name, $valid, $interface, $assert, $assertName)
221         {
222                 $this->config->set('storage', 'name', $name);
223                 if ($interface !== Storage\IWritableStorage::class) {
224                         $this->expectException(Storage\InvalidClassStorageException::class);
225                 }
226
227                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
228
229                 self::assertInstanceOf($assert, $storageManager->getBackend());
230         }
231
232         /**
233          * Tests the register and unregister methods for a new backend storage class
234          *
235          * Uses a sample storage for testing
236          *
237          * @see SampleStorageBackend
238          */
239         public function testRegisterUnregisterBackends()
240         {
241                 /// @todo Remove dice once "Hook" is dynamic and mockable
242                 $dice = (new Dice())
243                         ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
244                         ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
245                         ->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
246                 DI::init($dice);
247
248                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
249
250                 self::assertTrue($storageManager->register(SampleStorageBackend::class));
251
252                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
253                         SampleStorageBackend::getName(),
254                 ]), $storageManager->listBackends());
255                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
256                         SampleStorageBackend::getName()
257                 ]), $this->config->get('storage', 'backends'));
258
259                 self::assertTrue($storageManager->unregister(SampleStorageBackend::class));
260                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $this->config->get('storage', 'backends'));
261                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
262         }
263
264         /**
265          * tests that an active backend cannot get unregistered
266          */
267         public function testUnregisterActiveBackend()
268         {
269                 /// @todo Remove dice once "Hook" is dynamic and mockable
270                 $dice = (new Dice())
271                         ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
272                         ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
273                         ->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
274                 DI::init($dice);
275
276                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
277
278                 self::assertTrue($storageManager->register(SampleStorageBackend::class));
279
280                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
281                         SampleStorageBackend::getName(),
282                 ]), $storageManager->listBackends());
283                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
284                         SampleStorageBackend::getName()
285                 ]), $this->config->get('storage', 'backends'));
286
287                 // inline call to register own class as hook (testing purpose only)
288                 SampleStorageBackend::registerHook();
289                 Hook::loadHooks();
290
291                 self::assertTrue($storageManager->setBackend($storageManager->getWritableStorageByName(SampleStorageBackend::NAME)));
292                 self::assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
293
294                 self::assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
295
296                 self::expectException(Storage\StorageException::class);
297                 self::expectExceptionMessage('Cannot unregister Sample Storage, because it\'s currently active.');
298
299                 $storageManager->unregister(SampleStorageBackend::class);
300         }
301
302         /**
303          * Test moving data to a new storage (currently testing db & filesystem)
304          *
305          * @dataProvider dataStorages
306          */
307         public function testMoveStorage($name, $valid, $interface, $assert, $assertName)
308         {
309                 if ($interface !== Storage\IWritableStorage::class) {
310                         self::markTestSkipped("No user backend");
311                 }
312
313                 $this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
314
315                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
316                 $storage        = $storageManager->getWritableStorageByName($name);
317                 $storageManager->move($storage);
318
319                 $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
320
321                 while ($photo = $this->dba->fetch($photos)) {
322                         self::assertEmpty($photo['data']);
323
324                         $storage = $storageManager->getByName($photo['backend-class']);
325                         $data    = $storage->get($photo['backend-ref']);
326
327                         self::assertNotEmpty($data);
328                 }
329         }
330
331         /**
332          * Test moving data to a WRONG storage
333          */
334         public function testWrongWritableStorage()
335         {
336                 $this->expectException(Storage\InvalidClassStorageException::class);
337                 $this->expectExceptionMessage('Backend SystemResource is not valid');
338
339                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
340                 $storage        = $storageManager->getWritableStorageByName(Storage\SystemResource::getName());
341                 $storageManager->move($storage);
342         }
343 }