]> git.mxchange.org Git - friendica.git/blob - tests/src/Core/StorageManagerTest.php
Rename ISelectableStorage to IWritableStorage
[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                 if ($userBackend) {
181                         $storage = $storageManager->getWritableStorageByName($name);
182                 } else {
183                         $storage = $storageManager->getByName($name);
184                 }
185
186                 if (!empty($assert)) {
187                         self::assertInstanceOf(Storage\IStorage::class, $storage);
188                         self::assertInstanceOf($assert, $storage);
189                 } else {
190                         self::assertNull($storage);
191                 }
192                 self::assertEquals($assertName, $storage);
193         }
194
195         /**
196          * Test the isValidBackend() method
197          *
198          * @dataProvider dataStorages
199          */
200         public function testIsValidBackend($name, $assert, $assertName, $userBackend)
201         {
202                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
203
204                 // true in every of the backends
205                 self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
206
207                 // if userBackend is set to true, filter out e.g. SystemRessource
208                 self::assertEquals($userBackend, $storageManager->isValidBackend($name, true));
209         }
210
211         /**
212          * Test the method listBackends() with default setting
213          */
214         public function testListBackends()
215         {
216                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
217
218                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
219         }
220
221         /**
222          * Test the method getBackend()
223          *
224          * @dataProvider dataStorages
225          */
226         public function testGetBackend($name, $assert, $assertName, $userBackend)
227         {
228                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
229
230                 self::assertNull($storageManager->getBackend());
231
232                 if ($userBackend) {
233                         $selBackend = $storageManager->getWritableStorageByName($name);
234                         $storageManager->setBackend($selBackend);
235
236                         self::assertInstanceOf($assert, $storageManager->getBackend());
237                 }
238         }
239
240         /**
241          * Test the method getBackend() with a pre-configured backend
242          *
243          * @dataProvider dataStorages
244          * @dataProvider dataLegacyBackends
245          */
246         public function testPresetBackend($name, $assert, $assertName, $userBackend)
247         {
248                 $this->config->set('storage', 'name', $name);
249
250                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
251
252                 if ($userBackend) {
253                         self::assertInstanceOf($assert, $storageManager->getBackend());
254                 } else {
255                         self::assertNull($storageManager->getBackend());
256                 }
257         }
258
259         /**
260          * Tests the register and unregister methods for a new backend storage class
261          *
262          * Uses a sample storage for testing
263          *
264          * @see SampleStorageBackend
265          */
266         public function testRegisterUnregisterBackends()
267         {
268                 /// @todo Remove dice once "Hook" is dynamic and mockable
269                 $dice   = (new Dice())
270                         ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
271                         ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
272                         ->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
273                 DI::init($dice);
274
275                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
276
277                 self::assertTrue($storageManager->register(SampleStorageBackend::class));
278
279                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
280                         SampleStorageBackend::getName() => SampleStorageBackend::class,
281                 ]), $storageManager->listBackends());
282                 self::assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
283                         SampleStorageBackend::getName() => SampleStorageBackend::class,
284                 ]), $this->config->get('storage', 'backends'));
285
286                 // inline call to register own class as hook (testing purpose only)
287                 SampleStorageBackend::registerHook();
288                 Hook::loadHooks();
289
290                 self::assertTrue($storageManager->setBackend( $storageManager->getWritableStorageByName(SampleStorageBackend::NAME)));
291                 self::assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
292
293                 self::assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
294
295                 self::assertTrue($storageManager->unregister(SampleStorageBackend::class));
296                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $this->config->get('storage', 'backends'));
297                 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
298
299                 self::assertNull($storageManager->getBackend());
300                 self::assertNull($this->config->get('storage', 'name'));
301         }
302
303         /**
304          * Test moving data to a new storage (currently testing db & filesystem)
305          *
306          * @dataProvider dataStorages
307          */
308         public function testMoveStorage($name, $assert, $assertName, $userBackend)
309         {
310                 if (!$userBackend) {
311                         self::markTestSkipped("No user backend");
312                 }
313
314                 $this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
315
316                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
317                 $storage = $storageManager->getWritableStorageByName($name);
318                 $storageManager->move($storage);
319
320                 $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
321
322                 while ($photo = $this->dba->fetch($photos)) {
323
324                         self::assertEmpty($photo['data']);
325
326                         $storage = $storageManager->getByName($photo['backend-class']);
327                         $data = $storage->get($photo['backend-ref']);
328
329                         self::assertNotEmpty($data);
330                 }
331         }
332
333         /**
334          * Test moving data to a WRONG storage
335          */
336         public function testWrongWritableStorage()
337         {
338                 $this->expectException(\TypeError::class);
339
340                 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
341                 $storage = $storageManager->getWritableStorageByName(Storage\SystemResource::getName());
342                 $storageManager->move($storage);
343         }
344 }