AppConfigTest.php 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  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 testGetAllValuesWithEmptyApp(): void {
  345. $config = $this->generateAppConfig();
  346. $this->expectException(InvalidArgumentException::class);
  347. $config->getAllValues('');
  348. }
  349. /**
  350. * @dataProvider providerGetAppKeys
  351. *
  352. * @param string $appId
  353. * @param array $keys
  354. */
  355. public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
  356. $config = $this->generateAppConfig();
  357. $this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
  358. }
  359. public function testGetAllValuesWithPrefix(): void {
  360. $config = $this->generateAppConfig();
  361. $this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
  362. }
  363. public function testSearchValues(): void {
  364. $config = $this->generateAppConfig();
  365. $this->assertEqualsCanonicalizing(['testapp' => 'true', '123456' => 'true', 'anotherapp' => 'false'], $config->searchValues('enabled'));
  366. }
  367. public function testGetValueString(): void {
  368. $config = $this->generateAppConfig();
  369. $this->assertSame('value', $config->getValueString('typed', 'string', ''));
  370. }
  371. public function testGetValueStringOnUnknownAppReturnsDefault(): void {
  372. $config = $this->generateAppConfig();
  373. $this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
  374. }
  375. public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
  376. $config = $this->generateAppConfig();
  377. $this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
  378. }
  379. public function testGetValueStringOnWrongType(): void {
  380. $config = $this->generateAppConfig();
  381. $this->expectException(AppConfigTypeConflictException::class);
  382. $config->getValueString('typed', 'int');
  383. }
  384. public function testGetNonLazyValueStringAsLazy(): void {
  385. $config = $this->generateAppConfig();
  386. $this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
  387. }
  388. public function testGetValueInt() {
  389. $config = $this->generateAppConfig();
  390. $this->assertSame(42, $config->getValueInt('typed', 'int', 0));
  391. }
  392. public function testGetValueIntOnUnknownAppReturnsDefault(): void {
  393. $config = $this->generateAppConfig();
  394. $this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
  395. }
  396. public function testGetValueIntOnNonExistentKeyReturnsDefault() {
  397. $config = $this->generateAppConfig();
  398. $this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
  399. }
  400. public function testGetValueIntOnWrongType(): void {
  401. $config = $this->generateAppConfig();
  402. $this->expectException(AppConfigTypeConflictException::class);
  403. $config->getValueInt('typed', 'float');
  404. }
  405. public function testGetValueFloat() {
  406. $config = $this->generateAppConfig();
  407. $this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
  408. }
  409. public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
  410. $config = $this->generateAppConfig();
  411. $this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
  412. }
  413. public function testGetValueFloatOnNonExistentKeyReturnsDefault() {
  414. $config = $this->generateAppConfig();
  415. $this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
  416. }
  417. public function testGetValueFloatOnWrongType(): void {
  418. $config = $this->generateAppConfig();
  419. $this->expectException(AppConfigTypeConflictException::class);
  420. $config->getValueFloat('typed', 'bool');
  421. }
  422. public function testGetValueBool(): void {
  423. $config = $this->generateAppConfig();
  424. $this->assertSame(true, $config->getValueBool('typed', 'bool'));
  425. }
  426. public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
  427. $config = $this->generateAppConfig();
  428. $this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
  429. }
  430. public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
  431. $config = $this->generateAppConfig();
  432. $this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
  433. }
  434. public function testGetValueBoolOnWrongType(): void {
  435. $config = $this->generateAppConfig();
  436. $this->expectException(AppConfigTypeConflictException::class);
  437. $config->getValueBool('typed', 'array');
  438. }
  439. public function testGetValueArray(): void {
  440. $config = $this->generateAppConfig();
  441. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
  442. }
  443. public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
  444. $config = $this->generateAppConfig();
  445. $this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
  446. }
  447. public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
  448. $config = $this->generateAppConfig();
  449. $this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
  450. }
  451. public function testGetValueArrayOnWrongType(): void {
  452. $config = $this->generateAppConfig();
  453. $this->expectException(AppConfigTypeConflictException::class);
  454. $config->getValueArray('typed', 'string');
  455. }
  456. /**
  457. * @return array
  458. * @see testGetValueType
  459. *
  460. * @see testGetValueMixed
  461. */
  462. public function providerGetValueMixed(): array {
  463. return [
  464. // key, value, type
  465. ['mixed', 'mix', IAppConfig::VALUE_MIXED],
  466. ['string', 'value', IAppConfig::VALUE_STRING],
  467. ['int', '42', IAppConfig::VALUE_INT],
  468. ['float', '3.14', IAppConfig::VALUE_FLOAT],
  469. ['bool', '1', IAppConfig::VALUE_BOOL],
  470. ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
  471. ];
  472. }
  473. /**
  474. * @dataProvider providerGetValueMixed
  475. *
  476. * @param string $key
  477. * @param string $value
  478. */
  479. public function testGetValueMixed(string $key, string $value): void {
  480. $config = $this->generateAppConfig();
  481. $this->assertSame($value, $config->getValueMixed('typed', $key));
  482. }
  483. /**
  484. * @dataProvider providerGetValueMixed
  485. *
  486. * @param string $key
  487. * @param string $value
  488. * @param int $type
  489. */
  490. public function testGetValueType(string $key, string $value, int $type): void {
  491. $config = $this->generateAppConfig();
  492. $this->assertSame($type, $config->getValueType('typed', $key));
  493. }
  494. public function testGetValueTypeOnUnknownApp(): void {
  495. $config = $this->generateAppConfig();
  496. $this->expectException(AppConfigUnknownKeyException::class);
  497. $config->getValueType('typed-1', 'string');
  498. }
  499. public function testGetValueTypeOnNonExistentKey(): void {
  500. $config = $this->generateAppConfig();
  501. $this->expectException(AppConfigUnknownKeyException::class);
  502. $config->getValueType('typed', 'string-2');
  503. }
  504. public function testSetValueString(): void {
  505. $config = $this->generateAppConfig();
  506. $config->setValueString('feed', 'string', 'value-1');
  507. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  508. }
  509. public function testSetValueStringCache(): void {
  510. $config = $this->generateAppConfig();
  511. $config->setValueString('feed', 'string', 'value-1');
  512. $status = $config->statusCache();
  513. $this->assertSame('value-1', $status['fastCache']['feed']['string']);
  514. }
  515. public function testSetValueStringDatabase(): void {
  516. $config = $this->generateAppConfig();
  517. $config->setValueString('feed', 'string', 'value-1');
  518. $config->clearCache();
  519. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  520. }
  521. public function testSetValueStringIsUpdated(): void {
  522. $config = $this->generateAppConfig();
  523. $config->setValueString('feed', 'string', 'value-1');
  524. $this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
  525. }
  526. public function testSetValueStringIsNotUpdated(): void {
  527. $config = $this->generateAppConfig();
  528. $config->setValueString('feed', 'string', 'value-1');
  529. $this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
  530. }
  531. public function testSetValueStringIsUpdatedCache(): void {
  532. $config = $this->generateAppConfig();
  533. $config->setValueString('feed', 'string', 'value-1');
  534. $config->setValueString('feed', 'string', 'value-2');
  535. $status = $config->statusCache();
  536. $this->assertSame('value-2', $status['fastCache']['feed']['string']);
  537. }
  538. public function testSetValueStringIsUpdatedDatabase(): void {
  539. $config = $this->generateAppConfig();
  540. $config->setValueString('feed', 'string', 'value-1');
  541. $config->setValueString('feed', 'string', 'value-2');
  542. $config->clearCache();
  543. $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
  544. }
  545. public function testSetValueInt(): void {
  546. $config = $this->generateAppConfig();
  547. $config->setValueInt('feed', 'int', 42);
  548. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  549. }
  550. public function testSetValueIntCache(): void {
  551. $config = $this->generateAppConfig();
  552. $config->setValueInt('feed', 'int', 42);
  553. $status = $config->statusCache();
  554. $this->assertSame('42', $status['fastCache']['feed']['int']);
  555. }
  556. public function testSetValueIntDatabase(): void {
  557. $config = $this->generateAppConfig();
  558. $config->setValueInt('feed', 'int', 42);
  559. $config->clearCache();
  560. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  561. }
  562. public function testSetValueIntIsUpdated(): void {
  563. $config = $this->generateAppConfig();
  564. $config->setValueInt('feed', 'int', 42);
  565. $this->assertSame(true, $config->setValueInt('feed', 'int', 17));
  566. }
  567. public function testSetValueIntIsNotUpdated(): void {
  568. $config = $this->generateAppConfig();
  569. $config->setValueInt('feed', 'int', 42);
  570. $this->assertSame(false, $config->setValueInt('feed', 'int', 42));
  571. }
  572. public function testSetValueIntIsUpdatedCache(): void {
  573. $config = $this->generateAppConfig();
  574. $config->setValueInt('feed', 'int', 42);
  575. $config->setValueInt('feed', 'int', 17);
  576. $status = $config->statusCache();
  577. $this->assertSame('17', $status['fastCache']['feed']['int']);
  578. }
  579. public function testSetValueIntIsUpdatedDatabase(): void {
  580. $config = $this->generateAppConfig();
  581. $config->setValueInt('feed', 'int', 42);
  582. $config->setValueInt('feed', 'int', 17);
  583. $config->clearCache();
  584. $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
  585. }
  586. public function testSetValueFloat(): void {
  587. $config = $this->generateAppConfig();
  588. $config->setValueFloat('feed', 'float', 3.14);
  589. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  590. }
  591. public function testSetValueFloatCache(): void {
  592. $config = $this->generateAppConfig();
  593. $config->setValueFloat('feed', 'float', 3.14);
  594. $status = $config->statusCache();
  595. $this->assertSame('3.14', $status['fastCache']['feed']['float']);
  596. }
  597. public function testSetValueFloatDatabase(): void {
  598. $config = $this->generateAppConfig();
  599. $config->setValueFloat('feed', 'float', 3.14);
  600. $config->clearCache();
  601. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  602. }
  603. public function testSetValueFloatIsUpdated(): void {
  604. $config = $this->generateAppConfig();
  605. $config->setValueFloat('feed', 'float', 3.14);
  606. $this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
  607. }
  608. public function testSetValueFloatIsNotUpdated(): void {
  609. $config = $this->generateAppConfig();
  610. $config->setValueFloat('feed', 'float', 3.14);
  611. $this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
  612. }
  613. public function testSetValueFloatIsUpdatedCache(): void {
  614. $config = $this->generateAppConfig();
  615. $config->setValueFloat('feed', 'float', 3.14);
  616. $config->setValueFloat('feed', 'float', 1.23);
  617. $status = $config->statusCache();
  618. $this->assertSame('1.23', $status['fastCache']['feed']['float']);
  619. }
  620. public function testSetValueFloatIsUpdatedDatabase(): void {
  621. $config = $this->generateAppConfig();
  622. $config->setValueFloat('feed', 'float', 3.14);
  623. $config->setValueFloat('feed', 'float', 1.23);
  624. $config->clearCache();
  625. $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
  626. }
  627. public function testSetValueBool(): void {
  628. $config = $this->generateAppConfig();
  629. $config->setValueBool('feed', 'bool', true);
  630. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  631. }
  632. public function testSetValueBoolCache(): void {
  633. $config = $this->generateAppConfig();
  634. $config->setValueBool('feed', 'bool', true);
  635. $status = $config->statusCache();
  636. $this->assertSame('1', $status['fastCache']['feed']['bool']);
  637. }
  638. public function testSetValueBoolDatabase(): void {
  639. $config = $this->generateAppConfig();
  640. $config->setValueBool('feed', 'bool', true);
  641. $config->clearCache();
  642. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  643. }
  644. public function testSetValueBoolIsUpdated(): void {
  645. $config = $this->generateAppConfig();
  646. $config->setValueBool('feed', 'bool', true);
  647. $this->assertSame(true, $config->setValueBool('feed', 'bool', false));
  648. }
  649. public function testSetValueBoolIsNotUpdated(): void {
  650. $config = $this->generateAppConfig();
  651. $config->setValueBool('feed', 'bool', true);
  652. $this->assertSame(false, $config->setValueBool('feed', 'bool', true));
  653. }
  654. public function testSetValueBoolIsUpdatedCache(): void {
  655. $config = $this->generateAppConfig();
  656. $config->setValueBool('feed', 'bool', true);
  657. $config->setValueBool('feed', 'bool', false);
  658. $status = $config->statusCache();
  659. $this->assertSame('0', $status['fastCache']['feed']['bool']);
  660. }
  661. public function testSetValueBoolIsUpdatedDatabase(): void {
  662. $config = $this->generateAppConfig();
  663. $config->setValueBool('feed', 'bool', true);
  664. $config->setValueBool('feed', 'bool', false);
  665. $config->clearCache();
  666. $this->assertSame(false, $config->getValueBool('feed', 'bool', true));
  667. }
  668. public function testSetValueArray(): void {
  669. $config = $this->generateAppConfig();
  670. $config->setValueArray('feed', 'array', ['test' => 1]);
  671. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  672. }
  673. public function testSetValueArrayCache(): void {
  674. $config = $this->generateAppConfig();
  675. $config->setValueArray('feed', 'array', ['test' => 1]);
  676. $status = $config->statusCache();
  677. $this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
  678. }
  679. public function testSetValueArrayDatabase(): void {
  680. $config = $this->generateAppConfig();
  681. $config->setValueArray('feed', 'array', ['test' => 1]);
  682. $config->clearCache();
  683. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  684. }
  685. public function testSetValueArrayIsUpdated(): void {
  686. $config = $this->generateAppConfig();
  687. $config->setValueArray('feed', 'array', ['test' => 1]);
  688. $this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
  689. }
  690. public function testSetValueArrayIsNotUpdated(): void {
  691. $config = $this->generateAppConfig();
  692. $config->setValueArray('feed', 'array', ['test' => 1]);
  693. $this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
  694. }
  695. public function testSetValueArrayIsUpdatedCache(): void {
  696. $config = $this->generateAppConfig();
  697. $config->setValueArray('feed', 'array', ['test' => 1]);
  698. $config->setValueArray('feed', 'array', ['test' => 2]);
  699. $status = $config->statusCache();
  700. $this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
  701. }
  702. public function testSetValueArrayIsUpdatedDatabase(): void {
  703. $config = $this->generateAppConfig();
  704. $config->setValueArray('feed', 'array', ['test' => 1]);
  705. $config->setValueArray('feed', 'array', ['test' => 2]);
  706. $config->clearCache();
  707. $this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
  708. }
  709. public function testSetLazyValueString(): void {
  710. $config = $this->generateAppConfig();
  711. $config->setValueString('feed', 'string', 'value-1', true);
  712. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  713. }
  714. public function testSetLazyValueStringCache(): void {
  715. $config = $this->generateAppConfig();
  716. $config->setValueString('feed', 'string', 'value-1', true);
  717. $status = $config->statusCache();
  718. $this->assertSame('value-1', $status['lazyCache']['feed']['string']);
  719. }
  720. public function testSetLazyValueStringDatabase(): void {
  721. $config = $this->generateAppConfig();
  722. $config->setValueString('feed', 'string', 'value-1', true);
  723. $config->clearCache();
  724. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  725. }
  726. public function testSetLazyValueStringAsNonLazy(): void {
  727. $config = $this->generateAppConfig();
  728. $config->setValueString('feed', 'string', 'value-1', true);
  729. $config->setValueString('feed', 'string', 'value-1', false);
  730. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  731. }
  732. public function testSetNonLazyValueStringAsLazy(): void {
  733. $config = $this->generateAppConfig();
  734. $config->setValueString('feed', 'string', 'value-1', false);
  735. $config->setValueString('feed', 'string', 'value-1', true);
  736. $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
  737. }
  738. public function testSetSensitiveValueString(): void {
  739. $config = $this->generateAppConfig();
  740. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  741. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  742. }
  743. public function testSetSensitiveValueStringCache(): void {
  744. $config = $this->generateAppConfig();
  745. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  746. $status = $config->statusCache();
  747. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
  748. }
  749. public function testSetSensitiveValueStringDatabase(): void {
  750. $config = $this->generateAppConfig();
  751. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  752. $config->clearCache();
  753. $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
  754. }
  755. public function testSetNonSensitiveValueStringAsSensitive(): void {
  756. $config = $this->generateAppConfig();
  757. $config->setValueString('feed', 'string', 'value-1', sensitive: false);
  758. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  759. $this->assertSame(true, $config->isSensitive('feed', 'string'));
  760. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  761. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  762. }
  763. public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
  764. $config = $this->generateAppConfig();
  765. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  766. $config->setValueString('feed', 'string', 'value-2', sensitive: false);
  767. $this->assertSame(true, $config->isSensitive('feed', 'string'));
  768. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  769. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  770. }
  771. public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
  772. $config = $this->generateAppConfig();
  773. $config->setValueString('feed', 'string', 'value-1', sensitive: true);
  774. $config->setValueString('feed', 'string', 'value-2', sensitive: false);
  775. $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
  776. $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
  777. $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
  778. }
  779. public function testSetLazyValueInt(): void {
  780. $config = $this->generateAppConfig();
  781. $config->setValueInt('feed', 'int', 42, true);
  782. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  783. }
  784. public function testSetLazyValueIntCache(): void {
  785. $config = $this->generateAppConfig();
  786. $config->setValueInt('feed', 'int', 42, true);
  787. $status = $config->statusCache();
  788. $this->assertSame('42', $status['lazyCache']['feed']['int']);
  789. }
  790. public function testSetLazyValueIntDatabase(): void {
  791. $config = $this->generateAppConfig();
  792. $config->setValueInt('feed', 'int', 42, true);
  793. $config->clearCache();
  794. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  795. }
  796. public function testSetLazyValueIntAsNonLazy(): void {
  797. $config = $this->generateAppConfig();
  798. $config->setValueInt('feed', 'int', 42, true);
  799. $config->setValueInt('feed', 'int', 42, false);
  800. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  801. }
  802. public function testSetNonLazyValueIntAsLazy(): void {
  803. $config = $this->generateAppConfig();
  804. $config->setValueInt('feed', 'int', 42, false);
  805. $config->setValueInt('feed', 'int', 42, true);
  806. $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
  807. }
  808. public function testSetSensitiveValueInt(): void {
  809. $config = $this->generateAppConfig();
  810. $config->setValueInt('feed', 'int', 42, sensitive: true);
  811. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  812. }
  813. public function testSetSensitiveValueIntCache(): void {
  814. $config = $this->generateAppConfig();
  815. $config->setValueInt('feed', 'int', 42, sensitive: true);
  816. $status = $config->statusCache();
  817. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
  818. }
  819. public function testSetSensitiveValueIntDatabase(): void {
  820. $config = $this->generateAppConfig();
  821. $config->setValueInt('feed', 'int', 42, sensitive: true);
  822. $config->clearCache();
  823. $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
  824. }
  825. public function testSetNonSensitiveValueIntAsSensitive(): void {
  826. $config = $this->generateAppConfig();
  827. $config->setValueInt('feed', 'int', 42);
  828. $config->setValueInt('feed', 'int', 42, sensitive: true);
  829. $this->assertSame(true, $config->isSensitive('feed', 'int'));
  830. }
  831. public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
  832. $config = $this->generateAppConfig();
  833. $config->setValueInt('feed', 'int', 42, sensitive: true);
  834. $config->setValueInt('feed', 'int', 17);
  835. $this->assertSame(true, $config->isSensitive('feed', 'int'));
  836. }
  837. public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
  838. $config = $this->generateAppConfig();
  839. $config->setValueInt('feed', 'int', 42, sensitive: true);
  840. $config->setValueInt('feed', 'int', 17);
  841. $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
  842. }
  843. public function testSetLazyValueFloat(): void {
  844. $config = $this->generateAppConfig();
  845. $config->setValueFloat('feed', 'float', 3.14, true);
  846. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  847. }
  848. public function testSetLazyValueFloatCache(): void {
  849. $config = $this->generateAppConfig();
  850. $config->setValueFloat('feed', 'float', 3.14, true);
  851. $status = $config->statusCache();
  852. $this->assertSame('3.14', $status['lazyCache']['feed']['float']);
  853. }
  854. public function testSetLazyValueFloatDatabase(): void {
  855. $config = $this->generateAppConfig();
  856. $config->setValueFloat('feed', 'float', 3.14, true);
  857. $config->clearCache();
  858. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  859. }
  860. public function testSetLazyValueFloatAsNonLazy(): void {
  861. $config = $this->generateAppConfig();
  862. $config->setValueFloat('feed', 'float', 3.14, true);
  863. $config->setValueFloat('feed', 'float', 3.14, false);
  864. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  865. }
  866. public function testSetNonLazyValueFloatAsLazy(): void {
  867. $config = $this->generateAppConfig();
  868. $config->setValueFloat('feed', 'float', 3.14, false);
  869. $config->setValueFloat('feed', 'float', 3.14, true);
  870. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
  871. }
  872. public function testSetSensitiveValueFloat(): void {
  873. $config = $this->generateAppConfig();
  874. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  875. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  876. }
  877. public function testSetSensitiveValueFloatCache(): void {
  878. $config = $this->generateAppConfig();
  879. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  880. $status = $config->statusCache();
  881. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
  882. }
  883. public function testSetSensitiveValueFloatDatabase(): void {
  884. $config = $this->generateAppConfig();
  885. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  886. $config->clearCache();
  887. $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
  888. }
  889. public function testSetNonSensitiveValueFloatAsSensitive(): void {
  890. $config = $this->generateAppConfig();
  891. $config->setValueFloat('feed', 'float', 3.14);
  892. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  893. $this->assertSame(true, $config->isSensitive('feed', 'float'));
  894. }
  895. public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
  896. $config = $this->generateAppConfig();
  897. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  898. $config->setValueFloat('feed', 'float', 1.23);
  899. $this->assertSame(true, $config->isSensitive('feed', 'float'));
  900. }
  901. public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
  902. $config = $this->generateAppConfig();
  903. $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
  904. $config->setValueFloat('feed', 'float', 1.23);
  905. $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
  906. }
  907. public function testSetLazyValueBool(): void {
  908. $config = $this->generateAppConfig();
  909. $config->setValueBool('feed', 'bool', true, true);
  910. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  911. }
  912. public function testSetLazyValueBoolCache(): void {
  913. $config = $this->generateAppConfig();
  914. $config->setValueBool('feed', 'bool', true, true);
  915. $status = $config->statusCache();
  916. $this->assertSame('1', $status['lazyCache']['feed']['bool']);
  917. }
  918. public function testSetLazyValueBoolDatabase(): void {
  919. $config = $this->generateAppConfig();
  920. $config->setValueBool('feed', 'bool', true, true);
  921. $config->clearCache();
  922. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  923. }
  924. public function testSetLazyValueBoolAsNonLazy(): void {
  925. $config = $this->generateAppConfig();
  926. $config->setValueBool('feed', 'bool', true, true);
  927. $config->setValueBool('feed', 'bool', true, false);
  928. $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
  929. }
  930. public function testSetNonLazyValueBoolAsLazy(): void {
  931. $config = $this->generateAppConfig();
  932. $config->setValueBool('feed', 'bool', true, false);
  933. $config->setValueBool('feed', 'bool', true, true);
  934. $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
  935. }
  936. public function testSetLazyValueArray(): void {
  937. $config = $this->generateAppConfig();
  938. $config->setValueArray('feed', 'array', ['test' => 1], true);
  939. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  940. }
  941. public function testSetLazyValueArrayCache(): void {
  942. $config = $this->generateAppConfig();
  943. $config->setValueArray('feed', 'array', ['test' => 1], true);
  944. $status = $config->statusCache();
  945. $this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
  946. }
  947. public function testSetLazyValueArrayDatabase(): void {
  948. $config = $this->generateAppConfig();
  949. $config->setValueArray('feed', 'array', ['test' => 1], true);
  950. $config->clearCache();
  951. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  952. }
  953. public function testSetLazyValueArrayAsNonLazy(): void {
  954. $config = $this->generateAppConfig();
  955. $config->setValueArray('feed', 'array', ['test' => 1], true);
  956. $config->setValueArray('feed', 'array', ['test' => 1], false);
  957. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
  958. }
  959. public function testSetNonLazyValueArrayAsLazy(): void {
  960. $config = $this->generateAppConfig();
  961. $config->setValueArray('feed', 'array', ['test' => 1], false);
  962. $config->setValueArray('feed', 'array', ['test' => 1], true);
  963. $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
  964. }
  965. public function testSetSensitiveValueArray(): void {
  966. $config = $this->generateAppConfig();
  967. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  968. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
  969. }
  970. public function testSetSensitiveValueArrayCache(): void {
  971. $config = $this->generateAppConfig();
  972. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  973. $status = $config->statusCache();
  974. $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
  975. }
  976. public function testSetSensitiveValueArrayDatabase(): void {
  977. $config = $this->generateAppConfig();
  978. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  979. $config->clearCache();
  980. $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
  981. }
  982. public function testSetNonSensitiveValueArrayAsSensitive(): void {
  983. $config = $this->generateAppConfig();
  984. $config->setValueArray('feed', 'array', ['test' => 1]);
  985. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  986. $this->assertSame(true, $config->isSensitive('feed', 'array'));
  987. }
  988. public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
  989. $config = $this->generateAppConfig();
  990. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  991. $config->setValueArray('feed', 'array', ['test' => 2]);
  992. $this->assertSame(true, $config->isSensitive('feed', 'array'));
  993. }
  994. public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
  995. $config = $this->generateAppConfig();
  996. $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
  997. $config->setValueArray('feed', 'array', ['test' => 2]);
  998. $this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
  999. }
  1000. public function testUpdateNotSensitiveToSensitive(): void {
  1001. $config = $this->generateAppConfig();
  1002. $config->updateSensitive('non-sensitive-app', 'lazy-key', true);
  1003. $this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
  1004. }
  1005. public function testUpdateSensitiveToNotSensitive(): void {
  1006. $config = $this->generateAppConfig();
  1007. $config->updateSensitive('sensitive-app', 'lazy-key', false);
  1008. $this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
  1009. }
  1010. public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
  1011. $config = $this->generateAppConfig();
  1012. $this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
  1013. }
  1014. public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
  1015. $config = $this->generateAppConfig();
  1016. $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
  1017. }
  1018. public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
  1019. $config = $this->generateAppConfig();
  1020. $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
  1021. }
  1022. public function testUpdateNotLazyToLazy(): void {
  1023. $config = $this->generateAppConfig();
  1024. $config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
  1025. $this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
  1026. }
  1027. public function testUpdateLazyToNotLazy(): void {
  1028. $config = $this->generateAppConfig();
  1029. $config->updateLazy('non-sensitive-app', 'lazy-key', false);
  1030. $this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
  1031. }
  1032. public function testUpdateLazyToLazyReturnsFalse(): void {
  1033. $config = $this->generateAppConfig();
  1034. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
  1035. }
  1036. public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
  1037. $config = $this->generateAppConfig();
  1038. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
  1039. }
  1040. public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
  1041. $config = $this->generateAppConfig();
  1042. $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
  1043. }
  1044. public function testGetDetails(): void {
  1045. $config = $this->generateAppConfig();
  1046. $this->assertEquals(
  1047. [
  1048. 'app' => 'non-sensitive-app',
  1049. 'key' => 'lazy-key',
  1050. 'value' => 'value',
  1051. 'type' => 4,
  1052. 'lazy' => true,
  1053. 'typeString' => 'string',
  1054. 'sensitive' => false,
  1055. ],
  1056. $config->getDetails('non-sensitive-app', 'lazy-key')
  1057. );
  1058. }
  1059. public function testGetDetailsSensitive(): void {
  1060. $config = $this->generateAppConfig();
  1061. $this->assertEquals(
  1062. [
  1063. 'app' => 'sensitive-app',
  1064. 'key' => 'lazy-key',
  1065. 'value' => $this->baseStruct['sensitive-app']['lazy-key']['encrypted'],
  1066. 'type' => 4,
  1067. 'lazy' => true,
  1068. 'typeString' => 'string',
  1069. 'sensitive' => true,
  1070. ],
  1071. $config->getDetails('sensitive-app', 'lazy-key')
  1072. );
  1073. }
  1074. public function testGetDetailsInt(): void {
  1075. $config = $this->generateAppConfig();
  1076. $this->assertEquals(
  1077. [
  1078. 'app' => 'typed',
  1079. 'key' => 'int',
  1080. 'value' => '42',
  1081. 'type' => 8,
  1082. 'lazy' => false,
  1083. 'typeString' => 'integer',
  1084. 'sensitive' => false
  1085. ],
  1086. $config->getDetails('typed', 'int')
  1087. );
  1088. }
  1089. public function testGetDetailsFloat(): void {
  1090. $config = $this->generateAppConfig();
  1091. $this->assertEquals(
  1092. [
  1093. 'app' => 'typed',
  1094. 'key' => 'float',
  1095. 'value' => '3.14',
  1096. 'type' => 16,
  1097. 'lazy' => false,
  1098. 'typeString' => 'float',
  1099. 'sensitive' => false
  1100. ],
  1101. $config->getDetails('typed', 'float')
  1102. );
  1103. }
  1104. public function testGetDetailsBool(): void {
  1105. $config = $this->generateAppConfig();
  1106. $this->assertEquals(
  1107. [
  1108. 'app' => 'typed',
  1109. 'key' => 'bool',
  1110. 'value' => '1',
  1111. 'type' => 32,
  1112. 'lazy' => false,
  1113. 'typeString' => 'boolean',
  1114. 'sensitive' => false
  1115. ],
  1116. $config->getDetails('typed', 'bool')
  1117. );
  1118. }
  1119. public function testGetDetailsArray(): void {
  1120. $config = $this->generateAppConfig();
  1121. $this->assertEquals(
  1122. [
  1123. 'app' => 'typed',
  1124. 'key' => 'array',
  1125. 'value' => '{"test": 1}',
  1126. 'type' => 64,
  1127. 'lazy' => false,
  1128. 'typeString' => 'array',
  1129. 'sensitive' => false
  1130. ],
  1131. $config->getDetails('typed', 'array')
  1132. );
  1133. }
  1134. public function testDeleteKey(): void {
  1135. $config = $this->generateAppConfig();
  1136. $config->deleteKey('anotherapp', 'key');
  1137. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1138. }
  1139. public function testDeleteKeyCache(): void {
  1140. $config = $this->generateAppConfig();
  1141. $config->deleteKey('anotherapp', 'key');
  1142. $status = $config->statusCache();
  1143. $this->assertEqualsCanonicalizing(['enabled' => 'false'], $status['fastCache']['anotherapp']);
  1144. }
  1145. public function testDeleteKeyDatabase(): void {
  1146. $config = $this->generateAppConfig();
  1147. $config->deleteKey('anotherapp', 'key');
  1148. $config->clearCache();
  1149. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1150. }
  1151. public function testDeleteApp(): void {
  1152. $config = $this->generateAppConfig();
  1153. $config->deleteApp('anotherapp');
  1154. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1155. $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
  1156. }
  1157. public function testDeleteAppCache(): void {
  1158. $config = $this->generateAppConfig();
  1159. $status = $config->statusCache();
  1160. $this->assertSame(true, isset($status['fastCache']['anotherapp']));
  1161. $config->deleteApp('anotherapp');
  1162. $status = $config->statusCache();
  1163. $this->assertSame(false, isset($status['fastCache']['anotherapp']));
  1164. }
  1165. public function testDeleteAppDatabase(): void {
  1166. $config = $this->generateAppConfig();
  1167. $config->deleteApp('anotherapp');
  1168. $config->clearCache();
  1169. $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
  1170. $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
  1171. }
  1172. public function testClearCache(): void {
  1173. $config = $this->generateAppConfig();
  1174. $config->setValueString('feed', 'string', '123454');
  1175. $config->clearCache();
  1176. $status = $config->statusCache();
  1177. $this->assertSame([], $status['fastCache']);
  1178. }
  1179. public function testSensitiveValuesAreEncrypted(): void {
  1180. $key = self::getUniqueID('secret');
  1181. $appConfig = $this->generateAppConfig();
  1182. $secret = md5((string) time());
  1183. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1184. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1185. // Can get in same run
  1186. $actualSecret = $appConfig->getValueString('testapp', $key);
  1187. $this->assertEquals($secret, $actualSecret);
  1188. // Can get freshly decrypted from DB
  1189. $newAppConfig = $this->generateAppConfig();
  1190. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1191. $this->assertEquals($secret, $actualSecret);
  1192. }
  1193. public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
  1194. $key = self::getUniqueID('secret');
  1195. $appConfig = $this->generateAppConfig();
  1196. $secret = sha1((string) time());
  1197. // Unencrypted
  1198. $appConfig->setValueString('testapp', $key, $secret);
  1199. $this->assertConfigKey('testapp', $key, $secret);
  1200. // Can get freshly decrypted from DB
  1201. $newAppConfig = $this->generateAppConfig();
  1202. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1203. $this->assertEquals($secret, $actualSecret);
  1204. // Encrypting on change
  1205. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1206. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1207. // Can get in same run
  1208. $actualSecret = $appConfig->getValueString('testapp', $key);
  1209. $this->assertEquals($secret, $actualSecret);
  1210. // Can get freshly decrypted from DB
  1211. $newAppConfig = $this->generateAppConfig();
  1212. $actualSecret = $newAppConfig->getValueString('testapp', $key);
  1213. $this->assertEquals($secret, $actualSecret);
  1214. }
  1215. public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
  1216. $key = self::getUniqueID('secret');
  1217. $appConfig = $this->generateAppConfig();
  1218. $secret = sha1((string) time());
  1219. // Encrypted
  1220. $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
  1221. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1222. // Migrate to non-sensitive / non-encrypted
  1223. $appConfig->updateSensitive('testapp', $key, false);
  1224. $this->assertConfigKey('testapp', $key, $secret);
  1225. }
  1226. public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
  1227. $key = self::getUniqueID('secret');
  1228. $appConfig = $this->generateAppConfig();
  1229. $secret = sha1((string) time());
  1230. // Unencrypted
  1231. $appConfig->setValueString('testapp', $key, $secret);
  1232. $this->assertConfigKey('testapp', $key, $secret);
  1233. // Migrate to sensitive / encrypted
  1234. $appConfig->updateSensitive('testapp', $key, true);
  1235. $this->assertConfigValueNotEquals('testapp', $key, $secret);
  1236. }
  1237. protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
  1238. $sql = $this->connection->getQueryBuilder();
  1239. $sql->select('configvalue')
  1240. ->from('appconfig')
  1241. ->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
  1242. ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
  1243. ->setParameter('appid', $app)
  1244. ->setParameter('configkey', $key);
  1245. $query = $sql->executeQuery();
  1246. $actual = $query->fetchOne();
  1247. $query->closeCursor();
  1248. return $actual;
  1249. }
  1250. protected function assertConfigKey(string $app, string $key, string|false $expected): void {
  1251. $this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
  1252. }
  1253. protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
  1254. $this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
  1255. }
  1256. }