AppConfigTest.php 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2024, Maxence Lange <maxence@artificial-owl.com>
  5. *
  6. * @author Maxence Lange <maxence@artificial-owl.com>
  7. *
  8. * @license AGPL-3.0 or later
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace Test;
  24. use InvalidArgumentException;
  25. use OC\AppConfig;
  26. use OCP\Exceptions\AppConfigTypeConflictException;
  27. use OCP\Exceptions\AppConfigUnknownKeyException;
  28. use OCP\IAppConfig;
  29. use OCP\IDBConnection;
  30. use OCP\Security\ICrypto;
  31. use Psr\Log\LoggerInterface;
  32. /**
  33. * Class AppConfigTest
  34. *
  35. * @group DB
  36. *
  37. * @package Test
  38. */
  39. class AppConfigTest extends TestCase {
  40. protected IAppConfig $appConfig;
  41. protected IDBConnection $connection;
  42. private LoggerInterface $logger;
  43. private ICrypto $crypto;
  44. private array $originalConfig;
  45. /**
  46. * @var array<string, array<array<string, string, int, bool, bool>>>
  47. * [appId => [configKey, configValue, valueType, lazy, sensitive]]
  48. */
  49. private array $baseStruct =
  50. [
  51. 'testapp' => [
  52. 'enabled' => ['enabled', 'true'],
  53. 'installed_version' => ['installed_version', '1.2.3'],
  54. 'depends_on' => ['depends_on', 'someapp'],
  55. 'deletethis' => ['deletethis', 'deletethis'],
  56. 'key' => ['key', 'value']
  57. ],
  58. 'someapp' => [
  59. 'key' => ['key', 'value'],
  60. 'otherkey' => ['otherkey', 'othervalue']
  61. ],
  62. '123456' => [
  63. 'enabled' => ['enabled', 'true'],
  64. 'key' => ['key', 'value']
  65. ],
  66. 'anotherapp' => [
  67. 'enabled' => ['enabled', 'false'],
  68. 'key' => ['key', 'value']
  69. ],
  70. 'non-sensitive-app' => [
  71. 'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, false],
  72. 'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, false],
  73. ],
  74. 'sensitive-app' => [
  75. 'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, true],
  76. 'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, true],
  77. ],
  78. 'only-lazy' => [
  79. 'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true]
  80. ],
  81. 'typed' => [
  82. 'mixed' => ['mixed', 'mix', IAppConfig::VALUE_MIXED],
  83. 'string' => ['string', 'value', IAppConfig::VALUE_STRING],
  84. 'int' => ['int', '42', IAppConfig::VALUE_INT],
  85. 'float' => ['float', '3.14', IAppConfig::VALUE_FLOAT],
  86. 'bool' => ['bool', '1', IAppConfig::VALUE_BOOL],
  87. 'array' => ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
  88. ],
  89. 'prefix-app' => [
  90. 'key1' => ['key1', 'value'],
  91. 'prefix1' => ['prefix1', 'value'],
  92. 'prefix-2' => ['prefix-2', 'value'],
  93. 'key-2' => ['key-2', 'value'],
  94. ]
  95. ];
  96. protected function setUp(): void {
  97. parent::setUp();
  98. $this->connection = \OCP\Server::get(IDBConnection::class);
  99. $this->logger = \OCP\Server::get(LoggerInterface::class);
  100. $this->crypto = \OCP\Server::get(ICrypto::class);
  101. // storing current config and emptying the data table
  102. $sql = $this->connection->getQueryBuilder();
  103. $sql->select('*')
  104. ->from('appconfig');
  105. $result = $sql->executeQuery();
  106. $this->originalConfig = $result->fetchAll();
  107. $result->closeCursor();
  108. $sql = $this->connection->getQueryBuilder();
  109. $sql->delete('appconfig');
  110. $sql->executeStatement();
  111. $sql = $this->connection->getQueryBuilder();
  112. $sql->insert('appconfig')
  113. ->values(
  114. [
  115. 'appid' => $sql->createParameter('appid'),
  116. 'configkey' => $sql->createParameter('configkey'),
  117. 'configvalue' => $sql->createParameter('configvalue'),
  118. 'type' => $sql->createParameter('type'),
  119. 'lazy' => $sql->createParameter('lazy')
  120. ]
  121. );
  122. foreach ($this->baseStruct as $appId => $appData) {
  123. foreach ($appData as $key => $row) {
  124. $value = $row[1];
  125. $type = $row[2] ?? IAppConfig::VALUE_MIXED;
  126. if (($row[4] ?? false) === true) {
  127. $type |= IAppConfig::VALUE_SENSITIVE;
  128. $value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
  129. $this->baseStruct[$appId][$key]['encrypted'] = $value;
  130. }
  131. $sql->setParameters(
  132. [
  133. 'appid' => $appId,
  134. 'configkey' => $row[0],
  135. 'configvalue' => $value,
  136. 'type' => $type,
  137. 'lazy' => (($row[3] ?? false) === true) ? 1 : 0
  138. ]
  139. )->executeStatement();
  140. }
  141. }
  142. }
  143. protected function tearDown(): void {
  144. $sql = $this->connection->getQueryBuilder();
  145. $sql->delete('appconfig');
  146. $sql->executeStatement();
  147. $sql = $this->connection->getQueryBuilder();
  148. $sql->insert('appconfig')
  149. ->values(
  150. [
  151. 'appid' => $sql->createParameter('appid'),
  152. 'configkey' => $sql->createParameter('configkey'),
  153. 'configvalue' => $sql->createParameter('configvalue'),
  154. 'lazy' => $sql->createParameter('lazy'),
  155. 'type' => $sql->createParameter('type'),
  156. ]
  157. );
  158. foreach ($this->originalConfig as $key => $configs) {
  159. $sql->setParameter('appid', $configs['appid'])
  160. ->setParameter('configkey', $configs['configkey'])
  161. ->setParameter('configvalue', $configs['configvalue'])
  162. ->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
  163. ->setParameter('type', $configs['type']);
  164. $sql->executeStatement();
  165. }
  166. // $this->restoreService(AppConfig::class);
  167. parent::tearDown();
  168. }
  169. /**
  170. * @param bool $preLoading TRUE will preload the 'fast' cache, which is the normal behavior of usual
  171. * IAppConfig
  172. *
  173. * @return IAppConfig
  174. */
  175. private function generateAppConfig(bool $preLoading = true): IAppConfig {
  176. /** @var AppConfig $config */
  177. $config = new \OC\AppConfig(
  178. $this->connection,
  179. $this->logger,
  180. $this->crypto,
  181. );
  182. $msg = ' generateAppConfig() failed to confirm cache status';
  183. // confirm cache status
  184. $status = $config->statusCache();
  185. $this->assertSame(false, $status['fastLoaded'], $msg);
  186. $this->assertSame(false, $status['lazyLoaded'], $msg);
  187. $this->assertSame([], $status['fastCache'], $msg);
  188. $this->assertSame([], $status['lazyCache'], $msg);
  189. if ($preLoading) {
  190. // simple way to initiate the load of non-lazy config values in cache
  191. $config->getValueString('core', 'preload', '');
  192. // confirm cache status
  193. $status = $config->statusCache();
  194. $this->assertSame(true, $status['fastLoaded'], $msg);
  195. $this->assertSame(false, $status['lazyLoaded'], $msg);
  196. $apps = array_values(array_diff(array_keys($this->baseStruct), ['only-lazy']));
  197. $this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache']), $msg);
  198. $this->assertSame([], array_keys($status['lazyCache']), $msg);
  199. }
  200. return $config;
  201. }
  202. public function testGetApps(): void {
  203. $config = $this->generateAppConfig(false);
  204. $this->assertEqualsCanonicalizing(array_keys($this->baseStruct), $config->getApps());
  205. }
  206. /**
  207. * returns list of app and their keys
  208. *
  209. * @return array<string, string[]> ['appId' => ['key1', 'key2', ]]
  210. * @see testGetKeys
  211. */
  212. public function providerGetAppKeys(): array {
  213. $appKeys = [];
  214. foreach ($this->baseStruct as $appId => $appData) {
  215. $keys = [];
  216. foreach ($appData as $row) {
  217. $keys[] = $row[0];
  218. }
  219. $appKeys[] = [(string)$appId, $keys];
  220. }
  221. return $appKeys;
  222. }
  223. /**
  224. * returns list of config keys
  225. *
  226. * @return array<string, string, string, int, bool, bool> [appId, key, value, type, lazy, sensitive]
  227. * @see testIsSensitive
  228. * @see testIsLazy
  229. * @see testGetKeys
  230. */
  231. public function providerGetKeys(): array {
  232. $appKeys = [];
  233. foreach ($this->baseStruct as $appId => $appData) {
  234. foreach ($appData as $row) {
  235. $appKeys[] = [
  236. (string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
  237. $row[4] ?? false
  238. ];
  239. }
  240. }
  241. return $appKeys;
  242. }
  243. /**
  244. * @dataProvider providerGetAppKeys
  245. *
  246. * @param string $appId
  247. * @param array $expectedKeys
  248. */
  249. public function testGetKeys(string $appId, array $expectedKeys): void {
  250. $config = $this->generateAppConfig();
  251. $this->assertEqualsCanonicalizing($expectedKeys, $config->getKeys($appId));
  252. }
  253. public function testGetKeysOnUnknownAppShouldReturnsEmptyArray(): void {
  254. $config = $this->generateAppConfig();
  255. $this->assertEqualsCanonicalizing([], $config->getKeys('unknown-app'));
  256. }
  257. /**
  258. * @dataProvider providerGetKeys
  259. *
  260. * @param string $appId
  261. * @param string $configKey
  262. * @param string $value
  263. * @param bool $lazy
  264. */
  265. public function testHasKey(string $appId, string $configKey, string $value, int $type, bool $lazy): void {
  266. $config = $this->generateAppConfig();
  267. $this->assertEquals(true, $config->hasKey($appId, $configKey, $lazy));
  268. }
  269. public function testHasKeyOnNonExistentKeyReturnsFalse(): void {
  270. $config = $this->generateAppConfig();
  271. $this->assertEquals(false, $config->hasKey(array_keys($this->baseStruct)[0], 'inexistant-key'));
  272. }
  273. public function testHasKeyOnUnknownAppReturnsFalse(): void {
  274. $config = $this->generateAppConfig();
  275. $this->assertEquals(false, $config->hasKey('inexistant-app', 'inexistant-key'));
  276. }
  277. public function testHasKeyOnMistypedAsLazyReturnsFalse(): void {
  278. $config = $this->generateAppConfig();
  279. $this->assertSame(false, $config->hasKey('non-sensitive-app', 'non-lazy-key', true));
  280. }
  281. public function testHasKeyOnMistypeAsNonLazyReturnsFalse(): void {
  282. $config = $this->generateAppConfig();
  283. $this->assertSame(false, $config->hasKey('non-sensitive-app', 'lazy-key', false));
  284. }
  285. public function testHasKeyOnMistypeAsNonLazyReturnsTrueWithLazyArgumentIsNull(): void {
  286. $config = $this->generateAppConfig();
  287. $this->assertSame(true, $config->hasKey('non-sensitive-app', 'lazy-key', null));
  288. }
  289. /**
  290. * @dataProvider providerGetKeys
  291. */
  292. public function testIsSensitive(
  293. string $appId, string $configKey, string $configValue, int $type, bool $lazy, bool $sensitive
  294. ): void {
  295. $config = $this->generateAppConfig();
  296. $this->assertEquals($sensitive, $config->isSensitive($appId, $configKey, $lazy));
  297. }
  298. public function testIsSensitiveOnNonExistentKeyThrowsException(): void {
  299. $config = $this->generateAppConfig();
  300. $this->expectException(AppConfigUnknownKeyException::class);
  301. $config->isSensitive(array_keys($this->baseStruct)[0], 'inexistant-key');
  302. }
  303. public function testIsSensitiveOnUnknownAppThrowsException(): void {
  304. $config = $this->generateAppConfig();
  305. $this->expectException(AppConfigUnknownKeyException::class);
  306. $config->isSensitive('unknown-app', 'inexistant-key');
  307. }
  308. public function testIsSensitiveOnSensitiveMistypedAsLazy(): void {
  309. $config = $this->generateAppConfig();
  310. $this->assertSame(true, $config->isSensitive('sensitive-app', 'non-lazy-key', true));
  311. }
  312. public function testIsSensitiveOnNonSensitiveMistypedAsLazy(): void {
  313. $config = $this->generateAppConfig();
  314. $this->assertSame(false, $config->isSensitive('non-sensitive-app', 'non-lazy-key', true));
  315. }
  316. public function testIsSensitiveOnSensitiveMistypedAsNonLazyThrowsException(): void {
  317. $config = $this->generateAppConfig();
  318. $this->expectException(AppConfigUnknownKeyException::class);
  319. $config->isSensitive('sensitive-app', 'lazy-key', false);
  320. }
  321. public function testIsSensitiveOnNonSensitiveMistypedAsNonLazyThrowsException(): void {
  322. $config = $this->generateAppConfig();
  323. $this->expectException(AppConfigUnknownKeyException::class);
  324. $config->isSensitive('non-sensitive-app', 'lazy-key', false);
  325. }
  326. /**
  327. * @dataProvider providerGetKeys
  328. */
  329. public function testIsLazy(string $appId, string $configKey, string $configValue, int $type, bool $lazy
  330. ): void {
  331. $config = $this->generateAppConfig();
  332. $this->assertEquals($lazy, $config->isLazy($appId, $configKey));
  333. }
  334. public function testIsLazyOnNonExistentKeyThrowsException(): void {
  335. $config = $this->generateAppConfig();
  336. $this->expectException(AppConfigUnknownKeyException::class);
  337. $config->isLazy(array_keys($this->baseStruct)[0], 'inexistant-key');
  338. }
  339. public function testIsLazyOnUnknownAppThrowsException(): void {
  340. $config = $this->generateAppConfig();
  341. $this->expectException(AppConfigUnknownKeyException::class);
  342. $config->isLazy('unknown-app', 'inexistant-key');
  343. }
  344. public function testGetAllValues(): void {
  345. $config = $this->generateAppConfig();
  346. $this->assertEquals(
  347. [
  348. 'array' => ['test' => 1],
  349. 'bool' => true,
  350. 'float' => 3.14,
  351. 'int' => 42,
  352. 'mixed' => 'mix',
  353. 'string' => 'value',
  354. ],
  355. $config->getAllValues('typed')
  356. );
  357. }
  358. public function testGetAllValuesWithEmptyApp(): void {
  359. $config = $this->generateAppConfig();
  360. $this->expectException(InvalidArgumentException::class);
  361. $config->getAllValues('');
  362. }
  363. /**
  364. * @dataProvider providerGetAppKeys
  365. *
  366. * @param string $appId
  367. * @param array $keys
  368. */
  369. public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
  370. $config = $this->generateAppConfig();
  371. $this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
  372. }
  373. public function testGetAllValuesWithPrefix(): void {
  374. $config = $this->generateAppConfig();
  375. $this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
  376. }
  377. public function testSearchValues(): void {
  378. $config = $this->generateAppConfig();
  379. $this->assertEqualsCanonicalizing(['testapp' => 'true', '123456' => 'true', 'anotherapp' => 'false'], $config->searchValues('enabled'));
  380. }
  381. public function testGetValueString(): void {
  382. $config = $this->generateAppConfig();
  383. $this->assertSame('value', $config->getValueString('typed', 'string', ''));
  384. }
  385. public function testGetValueStringOnUnknownAppReturnsDefault(): void {
  386. $config = $this->generateAppConfig();
  387. $this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
  388. }
  389. public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
  390. $config = $this->generateAppConfig();
  391. $this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
  392. }
  393. public function testGetValueStringOnWrongType(): void {
  394. $config = $this->generateAppConfig();
  395. $this->expectException(AppConfigTypeConflictException::class);
  396. $config->getValueString('typed', 'int');
  397. }
  398. public function testGetNonLazyValueStringAsLazy(): void {
  399. $config = $this->generateAppConfig();
  400. $this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
  401. }
  402. public function testGetValueInt() {
  403. $config = $this->generateAppConfig();
  404. $this->assertSame(42, $config->getValueInt('typed', 'int', 0));
  405. }
  406. public function testGetValueIntOnUnknownAppReturnsDefault(): void {
  407. $config = $this->generateAppConfig();
  408. $this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
  409. }
  410. public function testGetValueIntOnNonExistentKeyReturnsDefault() {
  411. $config = $this->generateAppConfig();
  412. $this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
  413. }
  414. public function testGetValueIntOnWrongType(): void {
  415. $config = $this->generateAppConfig();
  416. $this->expectException(AppConfigTypeConflictException::class);
  417. $config->getValueInt('typed', 'float');
  418. }
  419. public function testGetValueFloat() {
  420. $config = $this->generateAppConfig();
  421. $this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
  422. }
  423. public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
  424. $config = $this->generateAppConfig();
  425. $this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
  426. }
  427. public function testGetValueFloatOnNonExistentKeyReturnsDefault() {
  428. $config = $this->generateAppConfig();
  429. $this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
  430. }
  431. public function testGetValueFloatOnWrongType(): void {
  432. $config = $this->generateAppConfig();
  433. $this->expectException(AppConfigTypeConflictException::class);
  434. $config->getValueFloat('typed', 'bool');
  435. }
  436. public function testGetValueBool(): void {
  437. $config = $this->generateAppConfig();
  438. $this->assertSame(true, $config->getValueBool('typed', 'bool'));
  439. }
  440. public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
  441. $config = $this->generateAppConfig();
  442. $this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
  443. }
  444. public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
  445. $config = $this->generateAppConfig();
  446. $this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
  447. }
  448. public function testGetValueBoolOnWrongType(): void {
  449. $config = $this->generateAppConfig();
  450. $this->expectException(AppConfigTypeConflictException::class);
  451. $config->getValueBool('typed', 'array');
  452. }
  453. public function testGetValueArray(): void {
  454. $config = $this->generateAppConfig();
  455. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
  456. }
  457. public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
  458. $config = $this->generateAppConfig();
  459. $this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
  460. }
  461. public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
  462. $config = $this->generateAppConfig();
  463. $this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
  464. }
  465. public function testGetValueArrayOnWrongType(): void {
  466. $config = $this->generateAppConfig();
  467. $this->expectException(AppConfigTypeConflictException::class);
  468. $config->getValueArray('typed', 'string');
  469. }
  470. /**
  471. * @return array
  472. * @see testGetValueType
  473. *
  474. * @see testGetValueMixed
  475. */
  476. public function providerGetValueMixed(): array {
  477. return [
  478. // key, value, type
  479. ['mixed', 'mix', IAppConfig::VALUE_MIXED],
  480. ['string', 'value', IAppConfig::VALUE_STRING],
  481. ['int', '42', IAppConfig::VALUE_INT],
  482. ['float', '3.14', IAppConfig::VALUE_FLOAT],
  483. ['bool', '1', IAppConfig::VALUE_BOOL],
  484. ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
  485. ];
  486. }
  487. /**
  488. * @dataProvider providerGetValueMixed
  489. *
  490. * @param string $key
  491. * @param string $value
  492. */
  493. public function testGetValueMixed(string $key, string $value): void {
  494. $config = $this->generateAppConfig();
  495. $this->assertSame($value, $config->getValueMixed('typed', $key));
  496. }
  497. /**
  498. * @dataProvider providerGetValueMixed
  499. *
  500. * @param string $key
  501. * @param string $value
  502. * @param int $type
  503. */
  504. public function testGetValueType(string $key, string $value, int $type): void {
  505. $config = $this->generateAppConfig();
  506. $this->assertSame($type, $config->getValueType('typed', $key));
  507. }
  508. public function testGetValueTypeOnUnknownApp(): void {
  509. $config = $this->generateAppConfig();
  510. $this->expectException(AppConfigUnknownKeyException::class);
  511. $config->getValueType('typed-1', 'string');
  512. }
  513. public function testGetValueTypeOnNonExistentKey(): void {
  514. $config = $this->generateAppConfig();
  515. $this->expectException(AppConfigUnknownKeyException::class);
  516. $config->getValueType('typed', 'string-2');
  517. }
  518. public function testSetValueString(): void {
  519. $config = $this->generateAppConfig();
  520. $config->setValueString('feed', 'string', 'value-1');
  521. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  522. }
  523. public function testSetValueStringCache(): void {
  524. $config = $this->generateAppConfig();
  525. $config->setValueString('feed', 'string', 'value-1');
  526. $status = $config->statusCache();
  527. $this->assertSame('value-1', $status['fastCache']['feed']['string']);
  528. }
  529. public function testSetValueStringDatabase(): void {
  530. $config = $this->generateAppConfig();
  531. $config->setValueString('feed', 'string', 'value-1');
  532. $config->clearCache();
  533. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  534. }
  535. public function testSetValueStringIsUpdated(): void {
  536. $config = $this->generateAppConfig();
  537. $config->setValueString('feed', 'string', 'value-1');
  538. $this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
  539. }
  540. public function testSetValueStringIsNotUpdated(): void {
  541. $config = $this->generateAppConfig();
  542. $config->setValueString('feed', 'string', 'value-1');
  543. $this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
  544. }
  545. public function testSetValueStringIsUpdatedCache(): void {
  546. $config = $this->generateAppConfig();
  547. $config->setValueString('feed', 'string', 'value-1');
  548. $config->setValueString('feed', 'string', 'value-2');
  549. $status = $config->statusCache();
  550. $this->assertSame('value-2', $status['fastCache']['feed']['string']);
  551. }
  552. public function testSetValueStringIsUpdatedDatabase(): void {
  553. $config = $this->generateAppConfig();
  554. $config->setValueString('feed', 'string', 'value-1');
  555. $config->setValueString('feed', 'string', 'value-2');
  556. $config->clearCache();
  557. $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
  558. }
  559. public function testSetValueInt(): void {
  560. $config = $this->generateAppConfig();
  561. $config->setValueInt('feed', 'int', 42);
  562. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  563. }
  564. public function testSetValueIntCache(): void {
  565. $config = $this->generateAppConfig();
  566. $config->setValueInt('feed', 'int', 42);
  567. $status = $config->statusCache();
  568. $this->assertSame('42', $status['fastCache']['feed']['int']);
  569. }
  570. public function testSetValueIntDatabase(): void {
  571. $config = $this->generateAppConfig();
  572. $config->setValueInt('feed', 'int', 42);
  573. $config->clearCache();
  574. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  575. }
  576. public function testSetValueIntIsUpdated(): void {
  577. $config = $this->generateAppConfig();
  578. $config->setValueInt('feed', 'int', 42);
  579. $this->assertSame(true, $config->setValueInt('feed', 'int', 17));
  580. }
  581. public function testSetValueIntIsNotUpdated(): void {
  582. $config = $this->generateAppConfig();
  583. $config->setValueInt('feed', 'int', 42);
  584. $this->assertSame(false, $config->setValueInt('feed', 'int', 42));
  585. }
  586. public function testSetValueIntIsUpdatedCache(): void {
  587. $config = $this->generateAppConfig();
  588. $config->setValueInt('feed', 'int', 42);
  589. $config->setValueInt('feed', 'int', 17);
  590. $status = $config->statusCache();
  591. $this->assertSame('17', $status['fastCache']['feed']['int']);
  592. }
  593. public function testSetValueIntIsUpdatedDatabase(): void {
  594. $config = $this->generateAppConfig();
  595. $config->setValueInt('feed', 'int', 42);
  596. $config->setValueInt('feed', 'int', 17);
  597. $config->clearCache();
  598. $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
  599. }
  600. public function testSetValueFloat(): void {
  601. $config = $this->generateAppConfig();
  602. $config->setValueFloat('feed', 'float', 3.14);
  603. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  604. }
  605. public function testSetValueFloatCache(): void {
  606. $config = $this->generateAppConfig();
  607. $config->setValueFloat('feed', 'float', 3.14);
  608. $status = $config->statusCache();
  609. $this->assertSame('3.14', $status['fastCache']['feed']['float']);
  610. }
  611. public function testSetValueFloatDatabase(): void {
  612. $config = $this->generateAppConfig();
  613. $config->setValueFloat('feed', 'float', 3.14);
  614. $config->clearCache();
  615. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  616. }
  617. public function testSetValueFloatIsUpdated(): void {
  618. $config = $this->generateAppConfig();
  619. $config->setValueFloat('feed', 'float', 3.14);
  620. $this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
  621. }
  622. public function testSetValueFloatIsNotUpdated(): void {
  623. $config = $this->generateAppConfig();
  624. $config->setValueFloat('feed', 'float', 3.14);
  625. $this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
  626. }
  627. public function testSetValueFloatIsUpdatedCache(): void {
  628. $config = $this->generateAppConfig();
  629. $config->setValueFloat('feed', 'float', 3.14);
  630. $config->setValueFloat('feed', 'float', 1.23);
  631. $status = $config->statusCache();
  632. $this->assertSame('1.23', $status['fastCache']['feed']['float']);
  633. }
  634. public function testSetValueFloatIsUpdatedDatabase(): void {
  635. $config = $this->generateAppConfig();
  636. $config->setValueFloat('feed', 'float', 3.14);
  637. $config->setValueFloat('feed', 'float', 1.23);
  638. $config->clearCache();
  639. $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
  640. }
  641. public function testSetValueBool(): void {
  642. $config = $this->generateAppConfig();
  643. $config->setValueBool('feed', 'bool', true);
  644. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  645. }
  646. public function testSetValueBoolCache(): void {
  647. $config = $this->generateAppConfig();
  648. $config->setValueBool('feed', 'bool', true);
  649. $status = $config->statusCache();
  650. $this->assertSame('1', $status['fastCache']['feed']['bool']);
  651. }
  652. public function testSetValueBoolDatabase(): void {
  653. $config = $this->generateAppConfig();
  654. $config->setValueBool('feed', 'bool', true);
  655. $config->clearCache();
  656. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  657. }
  658. public function testSetValueBoolIsUpdated(): void {
  659. $config = $this->generateAppConfig();
  660. $config->setValueBool('feed', 'bool', true);
  661. $this->assertSame(true, $config->setValueBool('feed', 'bool', false));
  662. }
  663. public function testSetValueBoolIsNotUpdated(): void {
  664. $config = $this->generateAppConfig();
  665. $config->setValueBool('feed', 'bool', true);
  666. $this->assertSame(false, $config->setValueBool('feed', 'bool', true));
  667. }
  668. public function testSetValueBoolIsUpdatedCache(): void {
  669. $config = $this->generateAppConfig();
  670. $config->setValueBool('feed', 'bool', true);
  671. $config->setValueBool('feed', 'bool', false);
  672. $status = $config->statusCache();
  673. $this->assertSame('0', $status['fastCache']['feed']['bool']);
  674. }
  675. public function testSetValueBoolIsUpdatedDatabase(): void {
  676. $config = $this->generateAppConfig();
  677. $config->setValueBool('feed', 'bool', true);
  678. $config->setValueBool('feed', 'bool', false);
  679. $config->clearCache();
  680. $this->assertSame(false, $config->getValueBool('feed', 'bool', true));
  681. }
  682. public function testSetValueArray(): void {
  683. $config = $this->generateAppConfig();
  684. $config->setValueArray('feed', 'array', ['test' => 1]);
  685. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  686. }
  687. public function testSetValueArrayCache(): void {
  688. $config = $this->generateAppConfig();
  689. $config->setValueArray('feed', 'array', ['test' => 1]);
  690. $status = $config->statusCache();
  691. $this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
  692. }
  693. public function testSetValueArrayDatabase(): void {
  694. $config = $this->generateAppConfig();
  695. $config->setValueArray('feed', 'array', ['test' => 1]);
  696. $config->clearCache();
  697. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  698. }
  699. public function testSetValueArrayIsUpdated(): void {
  700. $config = $this->generateAppConfig();
  701. $config->setValueArray('feed', 'array', ['test' => 1]);
  702. $this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
  703. }
  704. public function testSetValueArrayIsNotUpdated(): void {
  705. $config = $this->generateAppConfig();
  706. $config->setValueArray('feed', 'array', ['test' => 1]);
  707. $this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
  708. }
  709. public function testSetValueArrayIsUpdatedCache(): void {
  710. $config = $this->generateAppConfig();
  711. $config->setValueArray('feed', 'array', ['test' => 1]);
  712. $config->setValueArray('feed', 'array', ['test' => 2]);
  713. $status = $config->statusCache();
  714. $this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
  715. }
  716. public function testSetValueArrayIsUpdatedDatabase(): void {
  717. $config = $this->generateAppConfig();
  718. $config->setValueArray('feed', 'array', ['test' => 1]);
  719. $config->setValueArray('feed', 'array', ['test' => 2]);
  720. $config->clearCache();
  721. $this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
  722. }
  723. public function testSetLazyValueString(): void {
  724. $config = $this->generateAppConfig();
  725. $config->setValueString('feed', 'string', 'value-1', true);
  726. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  727. }
  728. public function testSetLazyValueStringCache(): void {
  729. $config = $this->generateAppConfig();
  730. $config->setValueString('feed', 'string', 'value-1', true);
  731. $status = $config->statusCache();
  732. $this->assertSame('value-1', $status['lazyCache']['feed']['string']);
  733. }
  734. public function testSetLazyValueStringDatabase(): void {
  735. $config = $this->generateAppConfig();
  736. $config->setValueString('feed', 'string', 'value-1', true);
  737. $config->clearCache();
  738. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  739. }
  740. public function testSetLazyValueStringAsNonLazy(): void {
  741. $config = $this->generateAppConfig();
  742. $config->setValueString('feed', 'string', 'value-1', true);
  743. $config->setValueString('feed', 'string', 'value-1', false);
  744. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  745. }
  746. public function testSetNonLazyValueStringAsLazy(): void {
  747. $config = $this->generateAppConfig();
  748. $config->setValueString('feed', 'string', 'value-1', false);
  749. $config->setValueString('feed', 'string', 'value-1', true);
  750. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  751. }
  752. public function testSetSensitiveValueString(): void {
  753. $config = $this->generateAppConfig();
  754. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  755. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  756. }
  757. public function testSetSensitiveValueStringCache(): void {
  758. $config = $this->generateAppConfig();
  759. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  760. $status = $config->statusCache();
  761. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
  762. }
  763. public function testSetSensitiveValueStringDatabase(): void {
  764. $config = $this->generateAppConfig();
  765. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  766. $config->clearCache();
  767. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  768. }
  769. public function testSetNonSensitiveValueStringAsSensitive(): void {
  770. $config = $this->generateAppConfig();
  771. $config->setValueString('feed', 'string', 'value-1', sensitive: false);
  772. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  773. $this->assertSame(true, $config->isSensitive('feed', 'string'));
  774. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  775. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  776. }
  777. public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
  778. $config = $this->generateAppConfig();
  779. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  780. $config->setValueString('feed', 'string', 'value-2', sensitive: false);
  781. $this->assertSame(true, $config->isSensitive('feed', 'string'));
  782. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  783. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  784. }
  785. public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
  786. $config = $this->generateAppConfig();
  787. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  788. $config->setValueString('feed', 'string', 'value-2', sensitive: false);
  789. $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
  790. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  791. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  792. }
  793. public function testSetLazyValueInt(): void {
  794. $config = $this->generateAppConfig();
  795. $config->setValueInt('feed', 'int', 42, true);
  796. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  797. }
  798. public function testSetLazyValueIntCache(): void {
  799. $config = $this->generateAppConfig();
  800. $config->setValueInt('feed', 'int', 42, true);
  801. $status = $config->statusCache();
  802. $this->assertSame('42', $status['lazyCache']['feed']['int']);
  803. }
  804. public function testSetLazyValueIntDatabase(): void {
  805. $config = $this->generateAppConfig();
  806. $config->setValueInt('feed', 'int', 42, true);
  807. $config->clearCache();
  808. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  809. }
  810. public function testSetLazyValueIntAsNonLazy(): void {
  811. $config = $this->generateAppConfig();
  812. $config->setValueInt('feed', 'int', 42, true);
  813. $config->setValueInt('feed', 'int', 42, false);
  814. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  815. }
  816. public function testSetNonLazyValueIntAsLazy(): void {
  817. $config = $this->generateAppConfig();
  818. $config->setValueInt('feed', 'int', 42, false);
  819. $config->setValueInt('feed', 'int', 42, true);
  820. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  821. }
  822. public function testSetSensitiveValueInt(): void {
  823. $config = $this->generateAppConfig();
  824. $config->setValueInt('feed', 'int', 42, sensitive: true);
  825. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  826. }
  827. public function testSetSensitiveValueIntCache(): void {
  828. $config = $this->generateAppConfig();
  829. $config->setValueInt('feed', 'int', 42, sensitive: true);
  830. $status = $config->statusCache();
  831. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
  832. }
  833. public function testSetSensitiveValueIntDatabase(): void {
  834. $config = $this->generateAppConfig();
  835. $config->setValueInt('feed', 'int', 42, sensitive: true);
  836. $config->clearCache();
  837. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  838. }
  839. public function testSetNonSensitiveValueIntAsSensitive(): void {
  840. $config = $this->generateAppConfig();
  841. $config->setValueInt('feed', 'int', 42);
  842. $config->setValueInt('feed', 'int', 42, sensitive: true);
  843. $this->assertSame(true, $config->isSensitive('feed', 'int'));
  844. }
  845. public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
  846. $config = $this->generateAppConfig();
  847. $config->setValueInt('feed', 'int', 42, sensitive: true);
  848. $config->setValueInt('feed', 'int', 17);
  849. $this->assertSame(true, $config->isSensitive('feed', 'int'));
  850. }
  851. public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
  852. $config = $this->generateAppConfig();
  853. $config->setValueInt('feed', 'int', 42, sensitive: true);
  854. $config->setValueInt('feed', 'int', 17);
  855. $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
  856. }
  857. public function testSetLazyValueFloat(): void {
  858. $config = $this->generateAppConfig();
  859. $config->setValueFloat('feed', 'float', 3.14, true);
  860. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  861. }
  862. public function testSetLazyValueFloatCache(): void {
  863. $config = $this->generateAppConfig();
  864. $config->setValueFloat('feed', 'float', 3.14, true);
  865. $status = $config->statusCache();
  866. $this->assertSame('3.14', $status['lazyCache']['feed']['float']);
  867. }
  868. public function testSetLazyValueFloatDatabase(): void {
  869. $config = $this->generateAppConfig();
  870. $config->setValueFloat('feed', 'float', 3.14, true);
  871. $config->clearCache();
  872. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  873. }
  874. public function testSetLazyValueFloatAsNonLazy(): void {
  875. $config = $this->generateAppConfig();
  876. $config->setValueFloat('feed', 'float', 3.14, true);
  877. $config->setValueFloat('feed', 'float', 3.14, false);
  878. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  879. }
  880. public function testSetNonLazyValueFloatAsLazy(): void {
  881. $config = $this->generateAppConfig();
  882. $config->setValueFloat('feed', 'float', 3.14, false);
  883. $config->setValueFloat('feed', 'float', 3.14, true);
  884. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  885. }
  886. public function testSetSensitiveValueFloat(): void {
  887. $config = $this->generateAppConfig();
  888. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  889. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  890. }
  891. public function testSetSensitiveValueFloatCache(): void {
  892. $config = $this->generateAppConfig();
  893. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  894. $status = $config->statusCache();
  895. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
  896. }
  897. public function testSetSensitiveValueFloatDatabase(): void {
  898. $config = $this->generateAppConfig();
  899. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  900. $config->clearCache();
  901. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  902. }
  903. public function testSetNonSensitiveValueFloatAsSensitive(): void {
  904. $config = $this->generateAppConfig();
  905. $config->setValueFloat('feed', 'float', 3.14);
  906. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  907. $this->assertSame(true, $config->isSensitive('feed', 'float'));
  908. }
  909. public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
  910. $config = $this->generateAppConfig();
  911. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  912. $config->setValueFloat('feed', 'float', 1.23);
  913. $this->assertSame(true, $config->isSensitive('feed', 'float'));
  914. }
  915. public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
  916. $config = $this->generateAppConfig();
  917. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  918. $config->setValueFloat('feed', 'float', 1.23);
  919. $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
  920. }
  921. public function testSetLazyValueBool(): void {
  922. $config = $this->generateAppConfig();
  923. $config->setValueBool('feed', 'bool', true, true);
  924. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  925. }
  926. public function testSetLazyValueBoolCache(): void {
  927. $config = $this->generateAppConfig();
  928. $config->setValueBool('feed', 'bool', true, true);
  929. $status = $config->statusCache();
  930. $this->assertSame('1', $status['lazyCache']['feed']['bool']);
  931. }
  932. public function testSetLazyValueBoolDatabase(): void {
  933. $config = $this->generateAppConfig();
  934. $config->setValueBool('feed', 'bool', true, true);
  935. $config->clearCache();
  936. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  937. }
  938. public function testSetLazyValueBoolAsNonLazy(): void {
  939. $config = $this->generateAppConfig();
  940. $config->setValueBool('feed', 'bool', true, true);
  941. $config->setValueBool('feed', 'bool', true, false);
  942. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  943. }
  944. public function testSetNonLazyValueBoolAsLazy(): void {
  945. $config = $this->generateAppConfig();
  946. $config->setValueBool('feed', 'bool', true, false);
  947. $config->setValueBool('feed', 'bool', true, true);
  948. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  949. }
  950. public function testSetLazyValueArray(): void {
  951. $config = $this->generateAppConfig();
  952. $config->setValueArray('feed', 'array', ['test' => 1], true);
  953. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  954. }
  955. public function testSetLazyValueArrayCache(): void {
  956. $config = $this->generateAppConfig();
  957. $config->setValueArray('feed', 'array', ['test' => 1], true);
  958. $status = $config->statusCache();
  959. $this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
  960. }
  961. public function testSetLazyValueArrayDatabase(): void {
  962. $config = $this->generateAppConfig();
  963. $config->setValueArray('feed', 'array', ['test' => 1], true);
  964. $config->clearCache();
  965. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  966. }
  967. public function testSetLazyValueArrayAsNonLazy(): void {
  968. $config = $this->generateAppConfig();
  969. $config->setValueArray('feed', 'array', ['test' => 1], true);
  970. $config->setValueArray('feed', 'array', ['test' => 1], false);
  971. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  972. }
  973. public function testSetNonLazyValueArrayAsLazy(): void {
  974. $config = $this->generateAppConfig();
  975. $config->setValueArray('feed', 'array', ['test' => 1], false);
  976. $config->setValueArray('feed', 'array', ['test' => 1], true);
  977. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  978. }
  979. public function testSetSensitiveValueArray(): void {
  980. $config = $this->generateAppConfig();
  981. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  982. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
  983. }
  984. public function testSetSensitiveValueArrayCache(): void {
  985. $config = $this->generateAppConfig();
  986. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  987. $status = $config->statusCache();
  988. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
  989. }
  990. public function testSetSensitiveValueArrayDatabase(): void {
  991. $config = $this->generateAppConfig();
  992. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  993. $config->clearCache();
  994. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
  995. }
  996. public function testSetNonSensitiveValueArrayAsSensitive(): void {
  997. $config = $this->generateAppConfig();
  998. $config->setValueArray('feed', 'array', ['test' => 1]);
  999. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  1000. $this->assertSame(true, $config->isSensitive('feed', 'array'));
  1001. }
  1002. public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
  1003. $config = $this->generateAppConfig();
  1004. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  1005. $config->setValueArray('feed', 'array', ['test' => 2]);
  1006. $this->assertSame(true, $config->isSensitive('feed', 'array'));
  1007. }
  1008. public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
  1009. $config = $this->generateAppConfig();
  1010. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  1011. $config->setValueArray('feed', 'array', ['test' => 2]);
  1012. $this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
  1013. }
  1014. public function testUpdateNotSensitiveToSensitive(): void {
  1015. $config = $this->generateAppConfig();
  1016. $config->updateSensitive('non-sensitive-app', 'lazy-key', true);
  1017. $this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
  1018. }
  1019. public function testUpdateSensitiveToNotSensitive(): void {
  1020. $config = $this->generateAppConfig();
  1021. $config->updateSensitive('sensitive-app', 'lazy-key', false);
  1022. $this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
  1023. }
  1024. public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
  1025. $config = $this->generateAppConfig();
  1026. $this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
  1027. }
  1028. public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
  1029. $config = $this->generateAppConfig();
  1030. $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
  1031. }
  1032. public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
  1033. $config = $this->generateAppConfig();
  1034. $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
  1035. }
  1036. public function testUpdateNotLazyToLazy(): void {
  1037. $config = $this->generateAppConfig();
  1038. $config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
  1039. $this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
  1040. }
  1041. public function testUpdateLazyToNotLazy(): void {
  1042. $config = $this->generateAppConfig();
  1043. $config->updateLazy('non-sensitive-app', 'lazy-key', false);
  1044. $this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
  1045. }
  1046. public function testUpdateLazyToLazyReturnsFalse(): void {
  1047. $config = $this->generateAppConfig();
  1048. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
  1049. }
  1050. public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
  1051. $config = $this->generateAppConfig();
  1052. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
  1053. }
  1054. public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
  1055. $config = $this->generateAppConfig();
  1056. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
  1057. }
  1058. public function testGetDetails(): void {
  1059. $config = $this->generateAppConfig();
  1060. $this->assertEquals(
  1061. [
  1062. 'app' => 'non-sensitive-app',
  1063. 'key' => 'lazy-key',
  1064. 'value' => 'value',
  1065. 'type' => 4,
  1066. 'lazy' => true,
  1067. 'typeString' => 'string',
  1068. 'sensitive' => false,
  1069. ],
  1070. $config->getDetails('non-sensitive-app', 'lazy-key')
  1071. );
  1072. }
  1073. public function testGetDetailsSensitive(): void {
  1074. $config = $this->generateAppConfig();
  1075. $this->assertEquals(
  1076. [
  1077. 'app' => 'sensitive-app',
  1078. 'key' => 'lazy-key',
  1079. 'value' => 'value',
  1080. 'type' => 4,
  1081. 'lazy' => true,
  1082. 'typeString' => 'string',
  1083. 'sensitive' => true,
  1084. ],
  1085. $config->getDetails('sensitive-app', 'lazy-key')
  1086. );
  1087. }
  1088. public function testGetDetailsInt(): void {
  1089. $config = $this->generateAppConfig();
  1090. $this->assertEquals(
  1091. [
  1092. 'app' => 'typed',
  1093. 'key' => 'int',
  1094. 'value' => '42',
  1095. 'type' => 8,
  1096. 'lazy' => false,
  1097. 'typeString' => 'integer',
  1098. 'sensitive' => false
  1099. ],
  1100. $config->getDetails('typed', 'int')
  1101. );
  1102. }
  1103. public function testGetDetailsFloat(): void {
  1104. $config = $this->generateAppConfig();
  1105. $this->assertEquals(
  1106. [
  1107. 'app' => 'typed',
  1108. 'key' => 'float',
  1109. 'value' => '3.14',
  1110. 'type' => 16,
  1111. 'lazy' => false,
  1112. 'typeString' => 'float',
  1113. 'sensitive' => false
  1114. ],
  1115. $config->getDetails('typed', 'float')
  1116. );
  1117. }
  1118. public function testGetDetailsBool(): void {
  1119. $config = $this->generateAppConfig();
  1120. $this->assertEquals(
  1121. [
  1122. 'app' => 'typed',
  1123. 'key' => 'bool',
  1124. 'value' => '1',
  1125. 'type' => 32,
  1126. 'lazy' => false,
  1127. 'typeString' => 'boolean',
  1128. 'sensitive' => false
  1129. ],
  1130. $config->getDetails('typed', 'bool')
  1131. );
  1132. }
  1133. public function testGetDetailsArray(): void {
  1134. $config = $this->generateAppConfig();
  1135. $this->assertEquals(
  1136. [
  1137. 'app' => 'typed',
  1138. 'key' => 'array',
  1139. 'value' => '{"test": 1}',
  1140. 'type' => 64,
  1141. 'lazy' => false,
  1142. 'typeString' => 'array',
  1143. 'sensitive' => false
  1144. ],
  1145. $config->getDetails('typed', 'array')
  1146. );
  1147. }
  1148. public function testDeleteKey(): void {
  1149. $config = $this->generateAppConfig();
  1150. $config->deleteKey('anotherapp', 'key');
  1151. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1152. }
  1153. public function testDeleteKeyCache(): void {
  1154. $config = $this->generateAppConfig();
  1155. $config->deleteKey('anotherapp', 'key');
  1156. $status = $config->statusCache();
  1157. $this->assertEqualsCanonicalizing(['enabled' => 'false'], $status['fastCache']['anotherapp']);
  1158. }
  1159. public function testDeleteKeyDatabase(): void {
  1160. $config = $this->generateAppConfig();
  1161. $config->deleteKey('anotherapp', 'key');
  1162. $config->clearCache();
  1163. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1164. }
  1165. public function testDeleteApp(): void {
  1166. $config = $this->generateAppConfig();
  1167. $config->deleteApp('anotherapp');
  1168. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1169. $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
  1170. }
  1171. public function testDeleteAppCache(): void {
  1172. $config = $this->generateAppConfig();
  1173. $status = $config->statusCache();
  1174. $this->assertSame(true, isset($status['fastCache']['anotherapp']));
  1175. $config->deleteApp('anotherapp');
  1176. $status = $config->statusCache();
  1177. $this->assertSame(false, isset($status['fastCache']['anotherapp']));
  1178. }
  1179. public function testDeleteAppDatabase(): void {
  1180. $config = $this->generateAppConfig();
  1181. $config->deleteApp('anotherapp');
  1182. $config->clearCache();
  1183. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1184. $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
  1185. }
  1186. public function testClearCache(): void {
  1187. $config = $this->generateAppConfig();
  1188. $config->setValueString('feed', 'string', '123454');
  1189. $config->clearCache();
  1190. $status = $config->statusCache();
  1191. $this->assertSame([], $status['fastCache']);
  1192. }
  1193. public function testSensitiveValuesAreEncrypted(): void {
  1194. $key = self::getUniqueID('secret');
  1195. $appConfig = $this->generateAppConfig();
  1196. $secret = md5((string) time());
  1197. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1198. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1199. // Can get in same run
  1200. $actualSecret = $appConfig->getValueString('testapp', $key);
  1201. $this->assertEquals($secret, $actualSecret);
  1202. // Can get freshly decrypted from DB
  1203. $newAppConfig = $this->generateAppConfig();
  1204. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1205. $this->assertEquals($secret, $actualSecret);
  1206. }
  1207. public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
  1208. $key = self::getUniqueID('secret');
  1209. $appConfig = $this->generateAppConfig();
  1210. $secret = sha1((string) time());
  1211. // Unencrypted
  1212. $appConfig->setValueString('testapp', $key, $secret);
  1213. $this->assertConfigKey('testapp', $key, $secret);
  1214. // Can get freshly decrypted from DB
  1215. $newAppConfig = $this->generateAppConfig();
  1216. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1217. $this->assertEquals($secret, $actualSecret);
  1218. // Encrypting on change
  1219. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1220. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1221. // Can get in same run
  1222. $actualSecret = $appConfig->getValueString('testapp', $key);
  1223. $this->assertEquals($secret, $actualSecret);
  1224. // Can get freshly decrypted from DB
  1225. $newAppConfig = $this->generateAppConfig();
  1226. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1227. $this->assertEquals($secret, $actualSecret);
  1228. }
  1229. public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
  1230. $key = self::getUniqueID('secret');
  1231. $appConfig = $this->generateAppConfig();
  1232. $secret = sha1((string) time());
  1233. // Encrypted
  1234. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1235. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1236. // Migrate to non-sensitive / non-encrypted
  1237. $appConfig->updateSensitive('testapp', $key, false);
  1238. $this->assertConfigKey('testapp', $key, $secret);
  1239. }
  1240. public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
  1241. $key = self::getUniqueID('secret');
  1242. $appConfig = $this->generateAppConfig();
  1243. $secret = sha1((string) time());
  1244. // Unencrypted
  1245. $appConfig->setValueString('testapp', $key, $secret);
  1246. $this->assertConfigKey('testapp', $key, $secret);
  1247. // Migrate to sensitive / encrypted
  1248. $appConfig->updateSensitive('testapp', $key, true);
  1249. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1250. }
  1251. protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
  1252. $sql = $this->connection->getQueryBuilder();
  1253. $sql->select('configvalue')
  1254. ->from('appconfig')
  1255. ->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
  1256. ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
  1257. ->setParameter('appid', $app)
  1258. ->setParameter('configkey', $key);
  1259. $query = $sql->executeQuery();
  1260. $actual = $query->fetchOne();
  1261. $query->closeCursor();
  1262. return $actual;
  1263. }
  1264. protected function assertConfigKey(string $app, string $key, string|false $expected): void {
  1265. $this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
  1266. }
  1267. protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
  1268. $this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
  1269. }
  1270. }