3 * @copyright Copyright (C) 2020, Friendica
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\Database\DBStructure;
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;
47 class StorageManagerTest extends DatabaseTest
53 /** @var LoggerInterface */
60 public function setUp()
66 $this->logger = new NullLogger();
68 $profiler = \Mockery::mock(Profiler::class);
69 $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
71 // load real config to avoid mocking every config-entry which is related to the Database class
72 $configFactory = new ConfigFactory();
73 $loader = new ConfigFileLoader($this->root->url());
74 $configCache = $configFactory->createCache($loader);
76 $this->dba = new StaticDatabase($configCache, $profiler, $this->logger);
78 $this->dba->setTestmode(true);
80 DBStructure::checkInitialValues();
82 $configModel = new Config($this->dba);
83 $this->config = new PreloadConfig($configCache, $configModel);
85 $this->l10n = \Mockery::mock(L10n::class);
89 * Test plain instancing first
91 public function testInstance()
93 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
95 $this->assertInstanceOf(StorageManager::class, $storageManager);
98 public function dataStorages()
105 'userBackend' => false,
108 'name' => Storage\Database::NAME,
109 'assert' => Storage\Database::class,
110 'assertName' => Storage\Database::NAME,
111 'userBackend' => true,
114 'name' => Storage\Filesystem::NAME,
115 'assert' => Storage\Filesystem::class,
116 'assertName' => Storage\Filesystem::NAME,
117 'userBackend' => true,
119 'systemresource' => [
120 'name' => Storage\SystemResource::NAME,
121 'assert' => Storage\SystemResource::class,
122 'assertName' => Storage\SystemResource::NAME,
123 // false here, because SystemResource isn't meant to be a user backend,
124 // it's for system resources only
125 'userBackend' => false,
131 'userBackend' => false,
137 * Data array for legacy backends
139 * @todo 2020.09 After 2 releases, remove the legacy functionality and these data array with it
143 public function dataLegacyBackends()
146 'legacyDatabase' => [
147 'name' => 'Friendica\Model\Storage\Database',
148 'assert' => Storage\Database::class,
149 'assertName' => Storage\Database::NAME,
150 'userBackend' => true,
152 'legacyFilesystem' => [
153 'name' => 'Friendica\Model\Storage\Filesystem',
154 'assert' => Storage\Filesystem::class,
155 'assertName' => Storage\Filesystem::NAME,
156 'userBackend' => true,
158 'legacySystemResource' => [
159 'name' => 'Friendica\Model\Storage\SystemResource',
160 'assert' => Storage\SystemResource::class,
161 'assertName' => Storage\SystemResource::NAME,
162 'userBackend' => false,
168 * Test the getByName() method
170 * @dataProvider dataStorages
171 * @dataProvider dataLegacyBackends
173 public function testGetByName($name, $assert, $assertName, $userBackend)
175 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
177 $storage = $storageManager->getByName($name, $userBackend);
179 if (!empty($assert)) {
180 $this->assertInstanceOf(Storage\IStorage::class, $storage);
181 $this->assertInstanceOf($assert, $storage);
183 $this->assertNull($storage);
185 $this->assertEquals($assertName, $storage);
189 * Test the isValidBackend() method
191 * @dataProvider dataStorages
193 public function testIsValidBackend($name, $assert, $assertName, $userBackend)
195 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
197 // true in every of the backends
198 $this->assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
200 // if userBackend is set to true, filter out e.g. SystemRessource
201 $this->assertEquals($userBackend, $storageManager->isValidBackend($name, true));
205 * Test the method listBackends() with default setting
207 public function testListBackends()
209 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
211 $this->assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
215 * Test the method getBackend()
217 * @dataProvider dataStorages
219 public function testGetBackend($name, $assert, $assertName, $userBackend)
221 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
223 $this->assertNull($storageManager->getBackend());
226 $storageManager->setBackend($name);
228 $this->assertInstanceOf($assert, $storageManager->getBackend());
233 * Test the method getBackend() with a pre-configured backend
235 * @dataProvider dataStorages
236 * @dataProvider dataLegacyBackends
238 public function testPresetBackend($name, $assert, $assertName, $userBackend)
240 $this->config->set('storage', 'name', $name);
242 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
245 $this->assertInstanceOf($assert, $storageManager->getBackend());
247 $this->assertNull($storageManager->getBackend());
252 * Tests the register and unregister methods for a new backend storage class
254 * Uses a sample storage for testing
256 * @see SampleStorageBackend
258 public function testRegisterUnregisterBackends()
260 /// @todo Remove dice once "Hook" is dynamic and mockable
262 ->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
263 ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
264 ->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
267 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
269 $this->assertTrue($storageManager->register(SampleStorageBackend::class));
271 $this->assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
272 SampleStorageBackend::getName() => SampleStorageBackend::class,
273 ]), $storageManager->listBackends());
274 $this->assertEquals(array_merge(StorageManager::DEFAULT_BACKENDS, [
275 SampleStorageBackend::getName() => SampleStorageBackend::class,
276 ]), $this->config->get('storage', 'backends'));
278 // inline call to register own class as hook (testing purpose only)
279 SampleStorageBackend::registerHook();
282 $this->assertTrue($storageManager->setBackend(SampleStorageBackend::NAME));
283 $this->assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
285 $this->assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
287 $this->assertTrue($storageManager->unregister(SampleStorageBackend::class));
288 $this->assertEquals(StorageManager::DEFAULT_BACKENDS, $this->config->get('storage', 'backends'));
289 $this->assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
291 $this->assertNull($storageManager->getBackend());
292 $this->assertNull($this->config->get('storage', 'name'));
296 * Test moving data to a new storage (currently testing db & filesystem)
298 * @dataProvider dataStorages
300 public function testMoveStorage($name, $assert, $assertName, $userBackend)
306 $this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
308 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
309 $storage = $storageManager->getByName($name);
310 $storageManager->move($storage);
312 $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
314 while ($photo = $this->dba->fetch($photos)) {
316 $this->assertEmpty($photo['data']);
318 $storage = $storageManager->getByName($photo['backend-class']);
319 $data = $storage->get($photo['backend-ref']);
321 $this->assertNotEmpty($data);
326 * Test moving data to a WRONG storage
328 * @expectedException \Friendica\Model\Storage\StorageException
329 * @expectedExceptionMessage Can't move to storage backend 'SystemResource'
331 public function testMoveStorageWrong()
333 $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
334 $storage = $storageManager->getByName(Storage\SystemResource::getName());
335 $storageManager->move($storage);