3 * @copyright Copyright (C) 2010-2023, 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\Config\Cache;
24 use Friendica\Core\Config\Factory\Config;
25 use Friendica\Core\Config\ValueObject\Cache;
26 use Friendica\Test\MockedTest;
27 use Friendica\Test\Util\VFSTrait;
28 use Friendica\Core\Config\Util\ConfigFileManager;
29 use org\bovigo\vfs\vfsStream;
31 class ConfigFileManagerTest extends MockedTest
35 protected function setUp(): void
43 * Test the loadConfigFiles() method with default values
45 public function testLoadConfigFiles()
47 $this->delConfigFile('local.config.php');
49 $configFileLoader = new ConfigFileManager(
51 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
52 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
55 $configCache = new Cache();
57 $configFileLoader->setupCache($configCache);
59 self::assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
63 * Test the loadConfigFiles() method with a wrong local.config.php
66 public function testLoadConfigWrong()
68 $this->expectExceptionMessageMatches("/Error loading config file \w+/");
69 $this->expectException(\Exception::class);
70 $this->delConfigFile('local.config.php');
72 vfsStream::newFile('local.config.php')
73 ->at($this->root->getChild('config'))
74 ->setContent('<?php return true;');
76 $configFileLoader = new ConfigFileManager(
78 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
79 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
81 $configCache = new Cache();
83 $configFileLoader->setupCache($configCache);
87 * Test the loadConfigFiles() method with a local.config.php file
89 public function testLoadConfigFilesLocal()
91 $this->delConfigFile('local.config.php');
93 $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
94 '..' . DIRECTORY_SEPARATOR .
95 '..' . DIRECTORY_SEPARATOR .
96 '..' . DIRECTORY_SEPARATOR .
97 'datasets' . DIRECTORY_SEPARATOR .
98 'config' . DIRECTORY_SEPARATOR .
101 vfsStream::newFile('local.config.php')
102 ->at($this->root->getChild('config'))
103 ->setContent(file_get_contents($file));
105 $configFileLoader = new ConfigFileManager(
107 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
108 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
110 $configCache = new Cache();
112 $configFileLoader->setupCache($configCache);
114 self::assertEquals('testhost', $configCache->get('database', 'hostname'));
115 self::assertEquals('testuser', $configCache->get('database', 'username'));
116 self::assertEquals('testpw', $configCache->get('database', 'password'));
117 self::assertEquals('testdb', $configCache->get('database', 'database'));
119 self::assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
120 self::assertEquals('Friendica Social Network', $configCache->get('config', 'sitename'));
124 * Test the loadConfigFile() method with a local.ini.php file
126 public function testLoadConfigFilesINI()
128 $this->delConfigFile('local.config.php');
130 $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
131 '..' . DIRECTORY_SEPARATOR .
132 '..' . DIRECTORY_SEPARATOR .
133 '..' . DIRECTORY_SEPARATOR .
134 'datasets' . DIRECTORY_SEPARATOR .
135 'config' . DIRECTORY_SEPARATOR .
138 vfsStream::newFile('local.ini.php')
139 ->at($this->root->getChild('config'))
140 ->setContent(file_get_contents($file));
142 $configFileLoader = new ConfigFileManager(
144 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
145 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
147 $configCache = new Cache();
149 $configFileLoader->setupCache($configCache);
151 self::assertEquals('testhost', $configCache->get('database', 'hostname'));
152 self::assertEquals('testuser', $configCache->get('database', 'username'));
153 self::assertEquals('testpw', $configCache->get('database', 'password'));
154 self::assertEquals('testdb', $configCache->get('database', 'database'));
156 self::assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
160 * Test the loadConfigFile() method with a .htconfig.php file
162 public function testLoadConfigFilesHtconfig()
164 $this->delConfigFile('local.config.php');
166 $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
167 '..' . DIRECTORY_SEPARATOR .
168 '..' . DIRECTORY_SEPARATOR .
169 '..' . DIRECTORY_SEPARATOR .
170 'datasets' . DIRECTORY_SEPARATOR .
171 'config' . DIRECTORY_SEPARATOR .
174 vfsStream::newFile('.htconfig.php')
176 ->setContent(file_get_contents($file));
178 $configFileLoader = new ConfigFileManager(
180 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
181 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
183 $configCache = new Cache();
185 $configFileLoader->setupCache($configCache);
187 self::assertEquals('testhost', $configCache->get('database', 'hostname'));
188 self::assertEquals('testuser', $configCache->get('database', 'username'));
189 self::assertEquals('testpw', $configCache->get('database', 'password'));
190 self::assertEquals('testdb', $configCache->get('database', 'database'));
191 self::assertEquals('anotherCharset', $configCache->get('database', 'charset'));
193 self::assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile'));
194 self::assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone'));
195 self::assertEquals('fr', $configCache->get('system', 'language'));
197 self::assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
198 self::assertEquals('Friendly admin', $configCache->get('config', 'admin_nickname'));
200 self::assertEquals('/another/php', $configCache->get('config', 'php_path'));
201 self::assertEquals('999', $configCache->get('config', 'max_import_size'));
202 self::assertEquals('666', $configCache->get('system', 'maximagesize'));
204 self::assertEquals('frio,vier', $configCache->get('system', 'allowed_themes'));
205 self::assertEquals('1', $configCache->get('system', 'no_regfullname'));
208 public function testLoadAddonConfig()
218 vfsStream::create($structure, $this->root);
220 $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
221 '..' . DIRECTORY_SEPARATOR .
222 '..' . DIRECTORY_SEPARATOR .
223 '..' . DIRECTORY_SEPARATOR .
224 'datasets' . DIRECTORY_SEPARATOR .
225 'config' . DIRECTORY_SEPARATOR .
228 vfsStream::newFile('test.config.php')
229 ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
230 ->setContent(file_get_contents($file));
232 $configFileLoader = new ConfigFileManager(
234 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
235 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
238 $conf = $configFileLoader->loadAddonConfig('test');
240 self::assertEquals('testhost', $conf['database']['hostname']);
241 self::assertEquals('testuser', $conf['database']['username']);
242 self::assertEquals('testpw', $conf['database']['password']);
243 self::assertEquals('testdb', $conf['database']['database']);
245 self::assertEquals('admin@test.it', $conf['config']['admin_email']);
249 * test loading multiple config files - the last config should work
251 public function testLoadMultipleConfigs()
253 $this->delConfigFile('local.config.php');
255 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
256 '..' . DIRECTORY_SEPARATOR .
257 '..' . DIRECTORY_SEPARATOR .
258 '..' . DIRECTORY_SEPARATOR .
259 'datasets' . DIRECTORY_SEPARATOR .
260 'config' . DIRECTORY_SEPARATOR;
262 vfsStream::newFile('A.config.php')
263 ->at($this->root->getChild('config'))
264 ->setContent(file_get_contents($fileDir . 'A.config.php'));
265 vfsStream::newFile('B.config.php')
266 ->at($this->root->getChild('config'))
267 ->setContent(file_get_contents($fileDir . 'B.config.php'));
269 $configFileLoader = new ConfigFileManager(
271 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
272 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
274 $configCache = new Cache();
276 $configFileLoader->setupCache($configCache);
278 self::assertEquals('admin@overwritten.local', $configCache->get('config', 'admin_email'));
279 self::assertEquals('newValue', $configCache->get('system', 'newKey'));
283 * test loading multiple config files - the last config should work (INI-version)
285 public function testLoadMultipleInis()
287 $this->delConfigFile('local.config.php');
289 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
290 '..' . DIRECTORY_SEPARATOR .
291 '..' . DIRECTORY_SEPARATOR .
292 '..' . DIRECTORY_SEPARATOR .
293 'datasets' . DIRECTORY_SEPARATOR .
294 'config' . DIRECTORY_SEPARATOR;
296 vfsStream::newFile('A.ini.php')
297 ->at($this->root->getChild('config'))
298 ->setContent(file_get_contents($fileDir . 'A.ini.php'));
299 vfsStream::newFile('B.ini.php')
300 ->at($this->root->getChild('config'))
301 ->setContent(file_get_contents($fileDir . 'B.ini.php'));
303 $configFileLoader = new ConfigFileManager(
305 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
306 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
308 $configCache = new Cache();
310 $configFileLoader->setupCache($configCache);
312 self::assertEquals('admin@overwritten.local', $configCache->get('config', 'admin_email'));
313 self::assertEquals('newValue', $configCache->get('system', 'newKey'));
317 * Test that sample-files (e.g. local-sample.config.php) is never loaded
319 public function testNotLoadingSamples()
321 $this->delConfigFile('local.config.php');
323 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
324 '..' . DIRECTORY_SEPARATOR .
325 '..' . DIRECTORY_SEPARATOR .
326 '..' . DIRECTORY_SEPARATOR .
327 'datasets' . DIRECTORY_SEPARATOR .
328 'config' . DIRECTORY_SEPARATOR;
330 vfsStream::newFile('A.ini.php')
331 ->at($this->root->getChild('config'))
332 ->setContent(file_get_contents($fileDir . 'A.ini.php'));
333 vfsStream::newFile('B-sample.ini.php')
334 ->at($this->root->getChild('config'))
335 ->setContent(file_get_contents($fileDir . 'B.ini.php'));
337 $configFileLoader = new ConfigFileManager(
339 $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
340 $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
343 $configCache = new Cache();
345 $configFileLoader->setupCache($configCache);
347 self::assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
348 self::assertEmpty($configCache->get('system', 'NewKey'));
352 * Test that using a wrong configuration directory leads to the "normal" config path
354 public function testWrongEnvDir()
356 $this->delConfigFile('local.config.php');
358 $configFileManager = (new Config())->createConfigFileManager($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']);
359 $configCache = new Cache();
361 $configFileManager->setupCache($configCache);
363 self::assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
367 * Test that a different location of the configuration directory produces the expected output
369 public function testRightEnvDir()
371 $this->delConfigFile('local.config.php');
373 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
374 '..' . DIRECTORY_SEPARATOR .
375 '..' . DIRECTORY_SEPARATOR .
376 '..' . DIRECTORY_SEPARATOR .
377 'datasets' . DIRECTORY_SEPARATOR .
378 'config' . DIRECTORY_SEPARATOR;
380 vfsStream::newFile('B.config.php')
381 ->at($this->root->getChild('config2'))
382 ->setContent(file_get_contents($fileDir . 'B.config.php'));
384 $configFileManager = (new Config())->createConfigFileManager($this->root->url(),
386 'FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url(),
388 $configCache = new Cache();
390 $configFileManager->setupCache($configCache);
392 self::assertEquals('newValue', $configCache->get('system', 'newKey'));
395 public function testSaveData()
397 $this->delConfigFile('local.config.php');
399 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
400 '..' . DIRECTORY_SEPARATOR .
401 '..' . DIRECTORY_SEPARATOR .
402 '..' . DIRECTORY_SEPARATOR .
403 'datasets' . DIRECTORY_SEPARATOR .
404 'config' . DIRECTORY_SEPARATOR;
406 vfsStream::newFile('B.config.php')
407 ->at($this->root->getChild('config2'))
408 ->setContent(file_get_contents($fileDir . 'B.config.php'));
410 $configFileManager = (new Config())->createConfigFileManager($this->root->url(),
412 'FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url(),
414 $configCache = new Cache();
416 $configFileManager->setupCache($configCache);
418 $specialChars = '!"§$%&/()(/&%$\'><?$a,;:[]}{}\\?¿¿ß';
420 // overwrite some data and save it back to the config file
421 $configCache->set('system', 'test', 'it', Cache::SOURCE_DATA);
422 $configCache->set('config', 'test', 'it', Cache::SOURCE_DATA);
423 $configCache->set('system', 'test_2', 2, Cache::SOURCE_DATA);
424 $configCache->set('special_chars', 'special', $specialChars, Cache::SOURCE_DATA);
425 $configFileManager->saveData($configCache);
427 // Reload the configCache with the new values
428 $configCache2 = new Cache();
429 $configFileManager->setupCache($configCache2);
431 self::assertEquals($configCache, $configCache2);
441 'special' => $specialChars,
442 ]], $configCache2->getDataBySource(Cache::SOURCE_DATA));
446 * If we delete something with the Cache::delete() functionality, be sure to override the underlying source as well
448 public function testDeleteKeyOverwrite()
450 $this->delConfigFile('node.config.php');
452 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
453 '..' . DIRECTORY_SEPARATOR .
454 '..' . DIRECTORY_SEPARATOR .
455 '..' . DIRECTORY_SEPARATOR .
456 'datasets' . DIRECTORY_SEPARATOR .
457 'config' . DIRECTORY_SEPARATOR;
459 vfsStream::newFile('B.config.php')
460 ->at($this->root->getChild('config'))
461 ->setContent(file_get_contents($fileDir . 'B.config.php'));
463 $configFileManager = (new Config())->createConfigFileManager($this->root->url());
464 $configCache = new Cache();
466 $configFileManager->setupCache($configCache);
468 $configCache->delete('system', 'default_timezone', Cache::SOURCE_DATA);
470 $configFileManager->saveData($configCache);
472 // assert that system.default_timezone is now null, even it's set with settings.conf.php
473 $configCache = new Cache();
475 $configFileManager->setupCache($configCache);
477 self::assertNull($configCache->get('system', 'default_timezone'));
481 * If we delete something with the Cache::delete() functionality, be sure to override the underlying source as well
483 public function testDeleteCategoryOverwrite()
485 $this->delConfigFile('node.config.php');
487 $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
488 '..' . DIRECTORY_SEPARATOR .
489 '..' . DIRECTORY_SEPARATOR .
490 '..' . DIRECTORY_SEPARATOR .
491 'datasets' . DIRECTORY_SEPARATOR .
492 'config' . DIRECTORY_SEPARATOR;
494 vfsStream::newFile('B.config.php')
495 ->at($this->root->getChild('config'))
496 ->setContent(file_get_contents($fileDir . 'B.config.php'));
498 $configFileManager = (new Config())->createConfigFileManager($this->root->url());
499 $configCache = new Cache();
501 $configFileManager->setupCache($configCache);
503 $configCache->delete('system');
505 $configFileManager->saveData($configCache);
507 // assert that system.default_timezone is now null, even it's set with settings.conf.php
508 $configCache = new Cache();
510 $configFileManager->setupCache($configCache);
512 self::assertNull($configCache->get('system', 'default_timezone'));
516 * Test for empty node.config.php
518 public function testEmptyFile()
520 $this->delConfigFile('node.config.php');
522 vfsStream::newFile('node.config.php')
523 ->at($this->root->getChild('config'))
526 $configFileManager = (new Config())->createConfigFileManager($this->root->url());
527 $configCache = new Cache();
529 $configFileManager->setupCache($configCache);
531 self::assertEquals(1,1);