AppConfigTest.php 50 KB

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