3 * @copyright Copyright (C) 2010-2021, the Friendica project
5 * @license GNU AGPL version 3 or any later version
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.
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.
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/>.
22 namespace Friendica\Test\src\Core;
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;
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;
48 class StorageManagerTest extends DatabaseTest
54 /** @var LoggerInterface */
58 /** @var HTTPRequest */
63 protected function setUp(): void
69 $this->logger = new NullLogger();
71 $profiler = \Mockery::mock(Profiler::class);
72 $profiler->shouldReceive('startRecording');
73 $profiler->shouldReceive('stopRecording');
74 $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
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);
81 $this->dba = new StaticDatabase($configCache, $profiler, $this->logger);
83 $configModel = new Config($this->dba);
84 $this->config = new PreloadConfig($configCache, $configModel);
86 $this->l10n = \Mockery::mock(L10n::class);
88 $this->httpRequest = \Mockery::mock(HTTPRequest::class);
92 * Test plain instancing first
94 public function testInstance()
96 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
98 self::assertInstanceOf(StorageManager::class, $storageManager);
101 public function dataStorages()
108 'userBackend' => false,
111 'name' => Storage\Database::NAME,
112 'assert' => Storage\Database::class,
113 'assertName' => Storage\Database::NAME,
114 'userBackend' => true,
117 'name' => Storage\Filesystem::NAME,
118 'assert' => Storage\Filesystem::class,
119 'assertName' => Storage\Filesystem::NAME,
120 'userBackend' => true,
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,
134 'userBackend' => false,
140 * Data array for legacy backends
142 * @todo 2020.09 After 2 releases, remove the legacy functionality and these data array with it
146 public function dataLegacyBackends()
149 'legacyDatabase' => [
150 'name' => 'Friendica\Model\Storage\Database',
151 'assert' => Storage\Database::class,
152 'assertName' => Storage\Database::NAME,
153 'userBackend' => true,
155 'legacyFilesystem' => [
156 'name' => 'Friendica\Model\Storage\Filesystem',
157 'assert' => Storage\Filesystem::class,
158 'assertName' => Storage\Filesystem::NAME,
159 'userBackend' => true,
161 'legacySystemResource' => [
162 'name' => 'Friendica\Model\Storage\SystemResource',
163 'assert' => Storage\SystemResource::class,
164 'assertName' => Storage\SystemResource::NAME,
165 'userBackend' => false,
171 * Test the getByName() method
173 * @dataProvider dataStorages
174 * @dataProvider dataLegacyBackends
176 public function testGetByName($name, $assert, $assertName, $userBackend)
178 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
181 $storage = $storageManager->getSelectableStorageByName($name);
183 $storage = $storageManager->getByName($name);
186 if (!empty($assert)) {
187 self::assertInstanceOf(Storage\IStorage::class, $storage);
188 self::assertInstanceOf($assert, $storage);
190 self::assertNull($storage);
192 self::assertEquals($assertName, $storage);
196 * Test the isValidBackend() method
198 * @dataProvider dataStorages
200 public function testIsValidBackend($name, $assert, $assertName, $userBackend)
202 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
204 // true in every of the backends
205 self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
207 // if userBackend is set to true, filter out e.g. SystemRessource
208 self::assertEquals($userBackend, $storageManager->isValidBackend($name, true));
212 * Test the method listBackends() with default setting
214 public function testListBackends()
216 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
218 self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
222 * Test the method getBackend()
224 * @dataProvider dataStorages
226 public function testGetBackend($name, $assert, $assertName, $userBackend)
228 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
230 self::assertNull($storageManager->getBackend());
233 $selBackend = $storageManager->getSelectableStorageByName($name);
234 $storageManager->setBackend($selBackend);
236 self::assertInstanceOf($assert, $storageManager->getBackend());
241 * Test the method getBackend() with a pre-configured backend
243 * @dataProvider dataStorages
244 * @dataProvider dataLegacyBackends
246 public function testPresetBackend($name, $assert, $assertName, $userBackend)
248 $this->config->set('storage', 'name', $name);
250 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
253 self::assertInstanceOf($assert, $storageManager->getBackend());
255 self::assertNull($storageManager->getBackend());
260 * Tests the register and unregister methods for a new backend storage class
262 * Uses a sample storage for testing
264 * @see SampleStorageBackend
266 public function testRegisterUnregisterBackends()
268 /// @todo Remove dice once "Hook" is dynamic and mockable
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]);
275 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
277 self::assertTrue($storageManager->register(SampleStorageBackend::class));
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'));
286 // inline call to register own class as hook (testing purpose only)
287 SampleStorageBackend::registerHook();
290 self::assertTrue($storageManager->setBackend( $storageManager->getSelectableStorageByName(SampleStorageBackend::NAME)));
291 self::assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
293 self::assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
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());
299 self::assertNull($storageManager->getBackend());
300 self::assertNull($this->config->get('storage', 'name'));
304 * Test moving data to a new storage (currently testing db & filesystem)
306 * @dataProvider dataStorages
308 public function testMoveStorage($name, $assert, $assertName, $userBackend)
311 self::markTestSkipped("No user backend");
314 $this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
316 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
317 $storage = $storageManager->getSelectableStorageByName($name);
318 $storageManager->move($storage);
320 $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
322 while ($photo = $this->dba->fetch($photos)) {
324 self::assertEmpty($photo['data']);
326 $storage = $storageManager->getByName($photo['backend-class']);
327 $data = $storage->get($photo['backend-ref']);
329 self::assertNotEmpty($data);
334 * Test moving data to a WRONG storage
336 public function testWrongSelectableStorage()
338 $this->expectException(\TypeError::class);
340 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
341 $storage = $storageManager->getSelectableStorageByName(Storage\SystemResource::getName());
342 $storageManager->move($storage);