]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/StorageManagerTest.php
Refactor IStorage
[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\Model\Storage\StorageException;
38 use Friendica\Network\HTTPRequest;
39 use Friendica\Test\DatabaseTest;
40 use Friendica\Test\Util\Database\StaticDatabase;
41 use Friendica\Test\Util\VFSTrait;
42 use Friendica\Util\ConfigFileLoader;
43 use Friendica\Util\Profiler;
44 use Psr\Log\LoggerInterface;
45 use Psr\Log\NullLogger;
46 use Friendica\Test\Util\SampleStorageBackend;
47
48 class StorageManagerTest extends DatabaseTest
49 {
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         use VFSTrait;
62
63         protected function setUp(): void
64         {
65                 parent::setUp();
66
67                 $this->setUpVfsDir();
68
69                 $this->logger = new NullLogger();
70
71                 $profiler = \Mockery::mock(Profiler::class);
72                 $profiler->shouldReceive('startRecording');
73                 $profiler->shouldReceive('stopRecording');
74                 $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
75
76                 // load real config to avoid mocking every config-entry which is related to the Database class
77                 $configFactory = new ConfigFactory();
78                 $loader        = new ConfigFileLoader($this->root->url());
79                 $configCache   = $configFactory->createCache($loader);
80
81                 $this->dba = new StaticDatabase($configCache, $profiler, $this->logger);
82
83                 $configModel  = new Config($this->dba);
84                 $this->config = new PreloadConfig($configCache, $configModel);
85
86                 $this->l10n = \Mockery::mock(L10n::class);
87
88                 $this->httpRequest = \Mockery::mock(HTTPRequest::class);
89         }
90
91         /**
92          * Test plain instancing first
93          */
94         public function testInstance()
95         {
96                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
97
98                 self::assertInstanceOf(StorageManager::class, $storageManager);
99         }
100
101         public function dataStorages()
102         {
103                 return [
104                         'empty'          => [
105                                 'name'        => '',
106                                 'assert'      => null,
107                                 'assertName'  => '',
108                                 'userBackend' => false,
109                         ],
110                         'database'       => [
111                                 'name'        => Storage\Database::NAME,
112                                 'assert'      => Storage\Database::class,
113                                 'assertName'  => Storage\Database::NAME,
114                                 'userBackend' => true,
115                         ],
116                         'filesystem'     => [
117                                 'name'        => Storage\Filesystem::NAME,
118                                 'assert'      => Storage\Filesystem::class,
119                                 'assertName'  => Storage\Filesystem::NAME,
120                                 'userBackend' => true,
121                         ],
122                         'systemresource' => [
123                                 'name'        => Storage\SystemResource::NAME,
124                                 'assert'      => Storage\SystemResource::class,
125                                 'assertName'  => Storage\SystemResource::NAME,
126                                 // false here, because SystemResource isn't meant to be a user backend,
127                                 // it's for system resources only
128                                 'userBackend' => false,
129                         ],
130                         'invalid'        => [
131                                 'name'        => 'invalid',
132                                 'assert'      => null,
133                                 'assertName'  => '',
134                                 'userBackend' => false,
135                         ],
136                 ];
137         }
138
139         /**
140          * Data array for legacy backends
141          *
142          * @todo 2020.09 After 2 releases, remove the legacy functionality and these data array with it
143          *
144          * @return array
145          */
146         public function dataLegacyBackends()
147         {
148                 return [
149                         'legacyDatabase'          => [
150                                 'name'        => 'Friendica\Model\Storage\Database',
151                                 'assert'      => Storage\Database::class,
152                                 'assertName'  => Storage\Database::NAME,
153                                 'userBackend' => true,
154                         ],
155                         'legacyFilesystem'       => [
156                                 'name'        => 'Friendica\Model\Storage\Filesystem',
157                                 'assert'      => Storage\Filesystem::class,
158                                 'assertName'  => Storage\Filesystem::NAME,
159                                 'userBackend' => true,
160                         ],
161                         'legacySystemResource'     => [
162                                 'name'        => 'Friendica\Model\Storage\SystemResource',
163                                 'assert'      => Storage\SystemResource::class,
164                                 'assertName'  => Storage\SystemResource::NAME,
165                                 'userBackend' => false,
166                         ],
167                 ];
168         }
169
170         /**
171          * Test the getByName() method
172          *
173          * @dataProvider dataStorages
174          * @dataProvider dataLegacyBackends
175          */
176         public function testGetByName($name, $assert, $assertName, $userBackend)
177         {
178                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
179
180                 $storage = $storageManager->getByName($name, $userBackend);
181
182                 if (!empty($assert)) {
183                         self::assertInstanceOf(Storage\IStorage::class, $storage);
184                         self::assertInstanceOf($assert, $storage);
185                 } else {
186                         self::assertNull($storage);
187                 }
188                 self::assertEquals($assertName, $storage);
189         }
190
191         /**
192          * Test the isValidBackend() method
193          *
194          * @dataProvider dataStorages
195          */
196         public function testIsValidBackend($name, $assert, $assertName, $userBackend)
197         {
198                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
199
200                 // true in every of the backends
201                 self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
202
203                 // if userBackend is set to true, filter out e.g. SystemRessource
204                 self::assertEquals($userBackend, $storageManager->isValidBackend($name, true));
205         }
206
207         /**
208          * Test the method listBackends() with default setting
209          */
210         public function testListBackends()
211         {
212                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
213
214                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
215         }
216
217         /**
218          * Test the method getBackend()
219          *
220          * @dataProvider dataStorages
221          */
222         public function testGetBackend($name, $assert, $assertName, $userBackend)
223         {
224                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
225
226                 self::assertNull($storageManager->getBackend());
227
228                 if ($userBackend) {
229                         $storageManager->setBackend($name);
230
231                         self::assertInstanceOf($assert, $storageManager->getBackend());
232                 }
233         }
234
235         /**
236          * Test the method getBackend() with a pre-configured backend
237          *
238          * @dataProvider dataStorages
239          * @dataProvider dataLegacyBackends
240          */
241         public function testPresetBackend($name, $assert, $assertName, $userBackend)
242         {
243                 $this->config->set('storage', 'name', $name);
244
245                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
246
247                 if ($userBackend) {
248                         self::assertInstanceOf($assert, $storageManager->getBackend());
249                 } else {
250                         self::assertNull($storageManager->getBackend());
251                 }
252         }
253
254         /**
255          * Tests the register and unregister methods for a new backend storage class
256          *
257          * Uses a sample storage for testing
258          *
259          * @see SampleStorageBackend
260          */
261         public function testRegisterUnregisterBackends()
262         {
263                 /// @todo Remove dice once "Hook" is dynamic and mockable
264                 $dice   = (new Dice())
265                         ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
266                         ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
267                         ->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
268                 DI::init($dice);
269
270                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
271
272                 self::assertTrue($storageManager->register(SampleStorageBackend::class));
273
274                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
275                         SampleStorageBackend::getName() => SampleStorageBackend::class,
276                 ]), $storageManager->listBackends());
277                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
278                         SampleStorageBackend::getName() => SampleStorageBackend::class,
279                 ]), $this->config->get('storage', 'backends'));
280
281                 // inline call to register own class as hook (testing purpose only)
282                 SampleStorageBackend::registerHook();
283                 Hook::loadHooks();
284
285                 self::assertTrue($storageManager->setBackend(SampleStorageBackend::NAME));
286                 self::assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
287
288                 self::assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
289
290                 self::assertTrue($storageManager->unregister(SampleStorageBackend::class));
291                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $this->config->get('storage', 'backends'));
292                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
293
294                 self::assertNull($storageManager->getBackend());
295                 self::assertNull($this->config->get('storage', 'name'));
296         }
297
298         /**
299          * Test moving data to a new storage (currently testing db & filesystem)
300          *
301          * @dataProvider dataStorages
302          */
303         public function testMoveStorage($name, $assert, $assertName, $userBackend)
304         {
305                 if (!$userBackend) {
306                         self::markTestSkipped("No user backend");
307                 }
308
309                 $this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
310
311                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
312                 $storage = $storageManager->getSelectableStorageByName($name);
313                 $storageManager->move($storage);
314
315                 $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
316
317                 while ($photo = $this->dba->fetch($photos)) {
318
319                         self::assertEmpty($photo['data']);
320
321                         $storage = $storageManager->getByName($photo['backend-class']);
322                         $data = $storage->get($photo['backend-ref']);
323
324                         self::assertNotEmpty($data);
325                 }
326         }
327
328         /**
329          * Test moving data to a WRONG storage
330          */
331         public function testMoveStorageWrong()
332         {
333                 $this->expectExceptionMessage("Can't move to storage backend 'SystemResource'");
334                 $this->expectException(StorageException::class);
335
336                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
337                 $storage = $storageManager->getSelectableStorageByName(Storage\SystemResource::getName());
338                 $storageManager->move($storage);
339         }
340 }