AppManagerTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-or-later
  7. */
  8. namespace Test\App;
  9. use OC\App\AppManager;
  10. use OC\AppConfig;
  11. use OCP\App\AppPathNotFoundException;
  12. use OCP\App\Events\AppDisableEvent;
  13. use OCP\App\Events\AppEnableEvent;
  14. use OCP\App\IAppManager;
  15. use OCP\EventDispatcher\IEventDispatcher;
  16. use OCP\ICache;
  17. use OCP\ICacheFactory;
  18. use OCP\IConfig;
  19. use OCP\IGroup;
  20. use OCP\IGroupManager;
  21. use OCP\IURLGenerator;
  22. use OCP\IUser;
  23. use OCP\IUserSession;
  24. use PHPUnit\Framework\MockObject\MockObject;
  25. use Psr\Log\LoggerInterface;
  26. use Test\TestCase;
  27. /**
  28. * Class AppManagerTest
  29. *
  30. * @package Test\App
  31. */
  32. class AppManagerTest extends TestCase {
  33. /**
  34. * @return AppConfig|MockObject
  35. */
  36. protected function getAppConfig() {
  37. $appConfig = [];
  38. $config = $this->createMock(AppConfig::class);
  39. $config->expects($this->any())
  40. ->method('getValue')
  41. ->willReturnCallback(function ($app, $key, $default) use (&$appConfig) {
  42. return (isset($appConfig[$app]) and isset($appConfig[$app][$key])) ? $appConfig[$app][$key] : $default;
  43. });
  44. $config->expects($this->any())
  45. ->method('setValue')
  46. ->willReturnCallback(function ($app, $key, $value) use (&$appConfig) {
  47. if (!isset($appConfig[$app])) {
  48. $appConfig[$app] = [];
  49. }
  50. $appConfig[$app][$key] = $value;
  51. });
  52. $config->expects($this->any())
  53. ->method('getValues')
  54. ->willReturnCallback(function ($app, $key) use (&$appConfig) {
  55. if ($app) {
  56. return $appConfig[$app];
  57. } else {
  58. $values = [];
  59. foreach ($appConfig as $appid => $appData) {
  60. if (isset($appData[$key])) {
  61. $values[$appid] = $appData[$key];
  62. }
  63. }
  64. return $values;
  65. }
  66. });
  67. return $config;
  68. }
  69. /** @var IUserSession|MockObject */
  70. protected $userSession;
  71. /** @var IConfig|MockObject */
  72. private $config;
  73. /** @var IGroupManager|MockObject */
  74. protected $groupManager;
  75. /** @var AppConfig|MockObject */
  76. protected $appConfig;
  77. /** @var ICache|MockObject */
  78. protected $cache;
  79. /** @var ICacheFactory|MockObject */
  80. protected $cacheFactory;
  81. /** @var IEventDispatcher|MockObject */
  82. protected $eventDispatcher;
  83. /** @var LoggerInterface|MockObject */
  84. protected $logger;
  85. protected IURLGenerator&MockObject $urlGenerator;
  86. /** @var IAppManager */
  87. protected $manager;
  88. protected function setUp(): void {
  89. parent::setUp();
  90. $this->userSession = $this->createMock(IUserSession::class);
  91. $this->groupManager = $this->createMock(IGroupManager::class);
  92. $this->config = $this->createMock(IConfig::class);
  93. $this->appConfig = $this->getAppConfig();
  94. $this->cacheFactory = $this->createMock(ICacheFactory::class);
  95. $this->cache = $this->createMock(ICache::class);
  96. $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
  97. $this->logger = $this->createMock(LoggerInterface::class);
  98. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  99. $this->overwriteService(AppConfig::class, $this->appConfig);
  100. $this->overwriteService(IURLGenerator::class, $this->urlGenerator);
  101. $this->cacheFactory->expects($this->any())
  102. ->method('createDistributed')
  103. ->with('settings')
  104. ->willReturn($this->cache);
  105. $this->config
  106. ->method('getSystemValueBool')
  107. ->with('installed', false)
  108. ->willReturn(true);
  109. $this->manager = new AppManager(
  110. $this->userSession,
  111. $this->config,
  112. $this->groupManager,
  113. $this->cacheFactory,
  114. $this->eventDispatcher,
  115. $this->logger,
  116. );
  117. }
  118. /**
  119. * @dataProvider dataGetAppIcon
  120. */
  121. public function testGetAppIcon($callback, ?bool $dark, string|null $expected): void {
  122. $this->urlGenerator->expects($this->atLeastOnce())
  123. ->method('imagePath')
  124. ->willReturnCallback($callback);
  125. if ($dark !== null) {
  126. $this->assertEquals($expected, $this->manager->getAppIcon('test', $dark));
  127. } else {
  128. $this->assertEquals($expected, $this->manager->getAppIcon('test'));
  129. }
  130. }
  131. public function dataGetAppIcon(): array {
  132. $nothing = function ($appId) {
  133. $this->assertEquals('test', $appId);
  134. throw new \RuntimeException();
  135. };
  136. $createCallback = function ($workingIcons) {
  137. return function ($appId, $icon) use ($workingIcons) {
  138. $this->assertEquals('test', $appId);
  139. if (in_array($icon, $workingIcons)) {
  140. return '/path/' . $icon;
  141. }
  142. throw new \RuntimeException();
  143. };
  144. };
  145. return [
  146. 'does not find anything' => [
  147. $nothing,
  148. false,
  149. null,
  150. ],
  151. 'nothing if request dark but only bright available' => [
  152. $createCallback(['app.svg']),
  153. true,
  154. null,
  155. ],
  156. 'nothing if request bright but only dark available' => [
  157. $createCallback(['app-dark.svg']),
  158. false,
  159. null,
  160. ],
  161. 'bright and only app.svg' => [
  162. $createCallback(['app.svg']),
  163. false,
  164. '/path/app.svg',
  165. ],
  166. 'dark and only app-dark.svg' => [
  167. $createCallback(['app-dark.svg']),
  168. true,
  169. '/path/app-dark.svg',
  170. ],
  171. 'dark only appname -dark.svg' => [
  172. $createCallback(['test-dark.svg']),
  173. true,
  174. '/path/test-dark.svg',
  175. ],
  176. 'bright and only appname.svg' => [
  177. $createCallback(['test.svg']),
  178. false,
  179. '/path/test.svg',
  180. ],
  181. 'priotize custom over default' => [
  182. $createCallback(['app.svg', 'test.svg']),
  183. false,
  184. '/path/test.svg',
  185. ],
  186. 'defaults to bright' => [
  187. $createCallback(['test-dark.svg', 'test.svg']),
  188. null,
  189. '/path/test.svg',
  190. ],
  191. 'no dark icon on default' => [
  192. $createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
  193. false,
  194. '/path/test.svg',
  195. ],
  196. 'no bright icon on dark' => [
  197. $createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
  198. true,
  199. '/path/test-dark.svg',
  200. ],
  201. ];
  202. }
  203. public function testEnableApp(): void {
  204. // making sure "files_trashbin" is disabled
  205. if ($this->manager->isEnabledForUser('files_trashbin')) {
  206. $this->manager->disableApp('files_trashbin');
  207. }
  208. $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('files_trashbin'));
  209. $this->manager->enableApp('files_trashbin');
  210. $this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
  211. }
  212. public function testDisableApp(): void {
  213. $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppDisableEvent('files_trashbin'));
  214. $this->manager->disableApp('files_trashbin');
  215. $this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
  216. }
  217. public function testNotEnableIfNotInstalled(): void {
  218. try {
  219. $this->manager->enableApp('some_random_name_which_i_hope_is_not_an_app');
  220. $this->assertFalse(true, 'If this line is reached the expected exception is not thrown.');
  221. } catch (AppPathNotFoundException $e) {
  222. // Exception is expected
  223. $this->assertEquals('Could not find path for some_random_name_which_i_hope_is_not_an_app', $e->getMessage());
  224. }
  225. $this->assertEquals('no', $this->appConfig->getValue(
  226. 'some_random_name_which_i_hope_is_not_an_app', 'enabled', 'no'
  227. ));
  228. }
  229. public function testEnableAppForGroups(): void {
  230. $group1 = $this->createMock(IGroup::class);
  231. $group1->method('getGID')
  232. ->willReturn('group1');
  233. $group2 = $this->createMock(IGroup::class);
  234. $group2->method('getGID')
  235. ->willReturn('group2');
  236. $groups = [$group1, $group2];
  237. /** @var AppManager|MockObject $manager */
  238. $manager = $this->getMockBuilder(AppManager::class)
  239. ->setConstructorArgs([
  240. $this->userSession,
  241. $this->config,
  242. $this->groupManager,
  243. $this->cacheFactory,
  244. $this->eventDispatcher,
  245. $this->logger,
  246. ])
  247. ->onlyMethods([
  248. 'getAppPath',
  249. ])
  250. ->getMock();
  251. $manager->expects($this->exactly(2))
  252. ->method('getAppPath')
  253. ->with('test')
  254. ->willReturn('apps/test');
  255. $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
  256. $manager->enableAppForGroups('test', $groups);
  257. $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
  258. }
  259. public function dataEnableAppForGroupsAllowedTypes() {
  260. return [
  261. [[]],
  262. [[
  263. 'types' => [],
  264. ]],
  265. [[
  266. 'types' => ['nickvergessen'],
  267. ]],
  268. ];
  269. }
  270. /**
  271. * @dataProvider dataEnableAppForGroupsAllowedTypes
  272. *
  273. * @param array $appInfo
  274. */
  275. public function testEnableAppForGroupsAllowedTypes(array $appInfo): void {
  276. $group1 = $this->createMock(IGroup::class);
  277. $group1->method('getGID')
  278. ->willReturn('group1');
  279. $group2 = $this->createMock(IGroup::class);
  280. $group2->method('getGID')
  281. ->willReturn('group2');
  282. $groups = [$group1, $group2];
  283. /** @var AppManager|MockObject $manager */
  284. $manager = $this->getMockBuilder(AppManager::class)
  285. ->setConstructorArgs([
  286. $this->userSession,
  287. $this->config,
  288. $this->groupManager,
  289. $this->cacheFactory,
  290. $this->eventDispatcher,
  291. $this->logger,
  292. ])
  293. ->onlyMethods([
  294. 'getAppPath',
  295. 'getAppInfo',
  296. ])
  297. ->getMock();
  298. $manager->expects($this->once())
  299. ->method('getAppPath')
  300. ->with('test')
  301. ->willReturn('');
  302. $manager->expects($this->once())
  303. ->method('getAppInfo')
  304. ->with('test')
  305. ->willReturn($appInfo);
  306. $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
  307. $manager->enableAppForGroups('test', $groups);
  308. $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
  309. }
  310. public function dataEnableAppForGroupsForbiddenTypes() {
  311. return [
  312. ['filesystem'],
  313. ['prelogin'],
  314. ['authentication'],
  315. ['logging'],
  316. ['prevent_group_restriction'],
  317. ];
  318. }
  319. /**
  320. * @dataProvider dataEnableAppForGroupsForbiddenTypes
  321. *
  322. * @param string $type
  323. *
  324. */
  325. public function testEnableAppForGroupsForbiddenTypes($type): void {
  326. $this->expectException(\Exception::class);
  327. $this->expectExceptionMessage('test can\'t be enabled for groups.');
  328. $group1 = $this->createMock(IGroup::class);
  329. $group1->method('getGID')
  330. ->willReturn('group1');
  331. $group2 = $this->createMock(IGroup::class);
  332. $group2->method('getGID')
  333. ->willReturn('group2');
  334. $groups = [$group1, $group2];
  335. /** @var AppManager|MockObject $manager */
  336. $manager = $this->getMockBuilder(AppManager::class)
  337. ->setConstructorArgs([
  338. $this->userSession,
  339. $this->config,
  340. $this->groupManager,
  341. $this->cacheFactory,
  342. $this->eventDispatcher,
  343. $this->logger,
  344. ])
  345. ->onlyMethods([
  346. 'getAppPath',
  347. 'getAppInfo',
  348. ])
  349. ->getMock();
  350. $manager->expects($this->once())
  351. ->method('getAppPath')
  352. ->with('test')
  353. ->willReturn('');
  354. $manager->expects($this->once())
  355. ->method('getAppInfo')
  356. ->with('test')
  357. ->willReturn([
  358. 'types' => [$type],
  359. ]);
  360. $this->eventDispatcher->expects($this->never())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
  361. $manager->enableAppForGroups('test', $groups);
  362. }
  363. public function testIsInstalledEnabled(): void {
  364. $this->appConfig->setValue('test', 'enabled', 'yes');
  365. $this->assertTrue($this->manager->isInstalled('test'));
  366. }
  367. public function testIsInstalledDisabled(): void {
  368. $this->appConfig->setValue('test', 'enabled', 'no');
  369. $this->assertFalse($this->manager->isInstalled('test'));
  370. }
  371. public function testIsInstalledEnabledForGroups(): void {
  372. $this->appConfig->setValue('test', 'enabled', '["foo"]');
  373. $this->assertTrue($this->manager->isInstalled('test'));
  374. }
  375. private function newUser($uid) {
  376. $user = $this->createMock(IUser::class);
  377. $user->method('getUID')
  378. ->willReturn($uid);
  379. return $user;
  380. }
  381. public function testIsEnabledForUserEnabled(): void {
  382. $this->appConfig->setValue('test', 'enabled', 'yes');
  383. $user = $this->newUser('user1');
  384. $this->assertTrue($this->manager->isEnabledForUser('test', $user));
  385. }
  386. public function testIsEnabledForUserDisabled(): void {
  387. $this->appConfig->setValue('test', 'enabled', 'no');
  388. $user = $this->newUser('user1');
  389. $this->assertFalse($this->manager->isEnabledForUser('test', $user));
  390. }
  391. public function testGetAppPath(): void {
  392. $this->assertEquals(\OC::$SERVERROOT . '/apps/files', $this->manager->getAppPath('files'));
  393. }
  394. public function testGetAppPathSymlink(): void {
  395. $fakeAppDirname = sha1(uniqid('test', true));
  396. $fakeAppPath = sys_get_temp_dir() . '/' . $fakeAppDirname;
  397. $fakeAppLink = \OC::$SERVERROOT . '/' . $fakeAppDirname;
  398. mkdir($fakeAppPath);
  399. if (symlink($fakeAppPath, $fakeAppLink) === false) {
  400. $this->markTestSkipped('Failed to create symlink');
  401. }
  402. // Use the symlink as the app path
  403. \OC::$APPSROOTS[] = [
  404. 'path' => $fakeAppLink,
  405. 'url' => \OC::$WEBROOT . '/' . $fakeAppDirname,
  406. 'writable' => false,
  407. ];
  408. $fakeTestAppPath = $fakeAppPath . '/' . 'test-test-app';
  409. mkdir($fakeTestAppPath);
  410. $generatedAppPath = $this->manager->getAppPath('test-test-app');
  411. rmdir($fakeTestAppPath);
  412. unlink($fakeAppLink);
  413. rmdir($fakeAppPath);
  414. $this->assertEquals($fakeAppLink . '/test-test-app', $generatedAppPath);
  415. }
  416. public function testGetAppPathFail(): void {
  417. $this->expectException(AppPathNotFoundException::class);
  418. $this->manager->getAppPath('testnotexisting');
  419. }
  420. public function testIsEnabledForUserEnabledForGroup(): void {
  421. $user = $this->newUser('user1');
  422. $this->groupManager->expects($this->once())
  423. ->method('getUserGroupIds')
  424. ->with($user)
  425. ->willReturn(['foo', 'bar']);
  426. $this->appConfig->setValue('test', 'enabled', '["foo"]');
  427. $this->assertTrue($this->manager->isEnabledForUser('test', $user));
  428. }
  429. public function testIsEnabledForUserDisabledForGroup(): void {
  430. $user = $this->newUser('user1');
  431. $this->groupManager->expects($this->once())
  432. ->method('getUserGroupIds')
  433. ->with($user)
  434. ->willReturn(['bar']);
  435. $this->appConfig->setValue('test', 'enabled', '["foo"]');
  436. $this->assertFalse($this->manager->isEnabledForUser('test', $user));
  437. }
  438. public function testIsEnabledForUserLoggedOut(): void {
  439. $this->appConfig->setValue('test', 'enabled', '["foo"]');
  440. $this->assertFalse($this->manager->isEnabledForUser('test'));
  441. }
  442. public function testIsEnabledForUserLoggedIn(): void {
  443. $user = $this->newUser('user1');
  444. $this->userSession->expects($this->once())
  445. ->method('getUser')
  446. ->willReturn($user);
  447. $this->groupManager->expects($this->once())
  448. ->method('getUserGroupIds')
  449. ->with($user)
  450. ->willReturn(['foo', 'bar']);
  451. $this->appConfig->setValue('test', 'enabled', '["foo"]');
  452. $this->assertTrue($this->manager->isEnabledForUser('test'));
  453. }
  454. public function testGetInstalledApps(): void {
  455. $this->appConfig->setValue('test1', 'enabled', 'yes');
  456. $this->appConfig->setValue('test2', 'enabled', 'no');
  457. $this->appConfig->setValue('test3', 'enabled', '["foo"]');
  458. $apps = [
  459. 'cloud_federation_api',
  460. 'dav',
  461. 'federatedfilesharing',
  462. 'files',
  463. 'lookup_server_connector',
  464. 'oauth2',
  465. 'provisioning_api',
  466. 'settings',
  467. 'test1',
  468. 'test3',
  469. 'theming',
  470. 'twofactor_backupcodes',
  471. 'viewer',
  472. 'workflowengine',
  473. ];
  474. $this->assertEquals($apps, $this->manager->getInstalledApps());
  475. }
  476. public function testGetAppsForUser(): void {
  477. $user = $this->newUser('user1');
  478. $this->groupManager->expects($this->any())
  479. ->method('getUserGroupIds')
  480. ->with($user)
  481. ->willReturn(['foo', 'bar']);
  482. $this->appConfig->setValue('test1', 'enabled', 'yes');
  483. $this->appConfig->setValue('test2', 'enabled', 'no');
  484. $this->appConfig->setValue('test3', 'enabled', '["foo"]');
  485. $this->appConfig->setValue('test4', 'enabled', '["asd"]');
  486. $enabled = [
  487. 'cloud_federation_api',
  488. 'dav',
  489. 'federatedfilesharing',
  490. 'files',
  491. 'lookup_server_connector',
  492. 'oauth2',
  493. 'provisioning_api',
  494. 'settings',
  495. 'test1',
  496. 'test3',
  497. 'theming',
  498. 'twofactor_backupcodes',
  499. 'viewer',
  500. 'workflowengine',
  501. ];
  502. $this->assertEquals($enabled, $this->manager->getEnabledAppsForUser($user));
  503. }
  504. public function testGetAppsNeedingUpgrade(): void {
  505. /** @var AppManager|MockObject $manager */
  506. $manager = $this->getMockBuilder(AppManager::class)
  507. ->setConstructorArgs([
  508. $this->userSession,
  509. $this->config,
  510. $this->groupManager,
  511. $this->cacheFactory,
  512. $this->eventDispatcher,
  513. $this->logger,
  514. ])
  515. ->onlyMethods(['getAppInfo'])
  516. ->getMock();
  517. $appInfos = [
  518. 'cloud_federation_api' => ['id' => 'cloud_federation_api'],
  519. 'dav' => ['id' => 'dav'],
  520. 'files' => ['id' => 'files'],
  521. 'federatedfilesharing' => ['id' => 'federatedfilesharing'],
  522. 'provisioning_api' => ['id' => 'provisioning_api'],
  523. 'lookup_server_connector' => ['id' => 'lookup_server_connector'],
  524. 'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'],
  525. 'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
  526. 'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
  527. 'test4' => ['id' => 'test4', 'version' => '3.0.0', 'requiremin' => '8.1.0'],
  528. 'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
  529. 'settings' => ['id' => 'settings'],
  530. 'theming' => ['id' => 'theming'],
  531. 'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
  532. 'viewer' => ['id' => 'viewer'],
  533. 'workflowengine' => ['id' => 'workflowengine'],
  534. 'oauth2' => ['id' => 'oauth2'],
  535. ];
  536. $manager->expects($this->any())
  537. ->method('getAppInfo')
  538. ->willReturnCallback(
  539. function ($appId) use ($appInfos) {
  540. return $appInfos[$appId];
  541. }
  542. );
  543. $this->appConfig->setValue('test1', 'enabled', 'yes');
  544. $this->appConfig->setValue('test1', 'installed_version', '1.0.0');
  545. $this->appConfig->setValue('test2', 'enabled', 'yes');
  546. $this->appConfig->setValue('test2', 'installed_version', '1.0.0');
  547. $this->appConfig->setValue('test3', 'enabled', 'yes');
  548. $this->appConfig->setValue('test3', 'installed_version', '1.0.0');
  549. $this->appConfig->setValue('test4', 'enabled', 'yes');
  550. $this->appConfig->setValue('test4', 'installed_version', '2.4.0');
  551. $apps = $manager->getAppsNeedingUpgrade('8.2.0');
  552. $this->assertCount(2, $apps);
  553. $this->assertEquals('test1', $apps[0]['id']);
  554. $this->assertEquals('test4', $apps[1]['id']);
  555. }
  556. public function testGetIncompatibleApps(): void {
  557. /** @var AppManager|MockObject $manager */
  558. $manager = $this->getMockBuilder(AppManager::class)
  559. ->setConstructorArgs([
  560. $this->userSession,
  561. $this->config,
  562. $this->groupManager,
  563. $this->cacheFactory,
  564. $this->eventDispatcher,
  565. $this->logger,
  566. ])
  567. ->onlyMethods(['getAppInfo'])
  568. ->getMock();
  569. $appInfos = [
  570. 'cloud_federation_api' => ['id' => 'cloud_federation_api'],
  571. 'dav' => ['id' => 'dav'],
  572. 'files' => ['id' => 'files'],
  573. 'federatedfilesharing' => ['id' => 'federatedfilesharing'],
  574. 'provisioning_api' => ['id' => 'provisioning_api'],
  575. 'lookup_server_connector' => ['id' => 'lookup_server_connector'],
  576. 'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'],
  577. 'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
  578. 'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
  579. 'settings' => ['id' => 'settings'],
  580. 'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
  581. 'theming' => ['id' => 'theming'],
  582. 'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
  583. 'workflowengine' => ['id' => 'workflowengine'],
  584. 'oauth2' => ['id' => 'oauth2'],
  585. 'viewer' => ['id' => 'viewer'],
  586. ];
  587. $manager->expects($this->any())
  588. ->method('getAppInfo')
  589. ->willReturnCallback(
  590. function ($appId) use ($appInfos) {
  591. return $appInfos[$appId];
  592. }
  593. );
  594. $this->appConfig->setValue('test1', 'enabled', 'yes');
  595. $this->appConfig->setValue('test2', 'enabled', 'yes');
  596. $this->appConfig->setValue('test3', 'enabled', 'yes');
  597. $apps = $manager->getIncompatibleApps('8.2.0');
  598. $this->assertCount(2, $apps);
  599. $this->assertEquals('test1', $apps[0]['id']);
  600. $this->assertEquals('test3', $apps[1]['id']);
  601. }
  602. public function testGetEnabledAppsForGroup(): void {
  603. $group = $this->createMock(IGroup::class);
  604. $group->expects($this->any())
  605. ->method('getGID')
  606. ->willReturn('foo');
  607. $this->appConfig->setValue('test1', 'enabled', 'yes');
  608. $this->appConfig->setValue('test2', 'enabled', 'no');
  609. $this->appConfig->setValue('test3', 'enabled', '["foo"]');
  610. $this->appConfig->setValue('test4', 'enabled', '["asd"]');
  611. $enabled = [
  612. 'cloud_federation_api',
  613. 'dav',
  614. 'federatedfilesharing',
  615. 'files',
  616. 'lookup_server_connector',
  617. 'oauth2',
  618. 'provisioning_api',
  619. 'settings',
  620. 'test1',
  621. 'test3',
  622. 'theming',
  623. 'twofactor_backupcodes',
  624. 'viewer',
  625. 'workflowengine',
  626. ];
  627. $this->assertEquals($enabled, $this->manager->getEnabledAppsForGroup($group));
  628. }
  629. public function testGetAppRestriction(): void {
  630. $this->appConfig->setValue('test1', 'enabled', 'yes');
  631. $this->appConfig->setValue('test2', 'enabled', 'no');
  632. $this->appConfig->setValue('test3', 'enabled', '["foo"]');
  633. $this->assertEquals([], $this->manager->getAppRestriction('test1'));
  634. $this->assertEquals([], $this->manager->getAppRestriction('test2'));
  635. $this->assertEquals(['foo'], $this->manager->getAppRestriction('test3'));
  636. }
  637. public static function isBackendRequiredDataProvider(): array {
  638. return [
  639. // backend available
  640. [
  641. 'caldav',
  642. ['app1' => ['caldav']],
  643. true,
  644. ],
  645. [
  646. 'caldav',
  647. ['app1' => [], 'app2' => ['foo'], 'app3' => ['caldav']],
  648. true,
  649. ],
  650. // backend not available
  651. [
  652. 'caldav',
  653. ['app3' => [], 'app1' => ['foo'], 'app2' => ['bar', 'baz']],
  654. false,
  655. ],
  656. // no app available
  657. [
  658. 'caldav',
  659. [],
  660. false,
  661. ],
  662. ];
  663. }
  664. /**
  665. * @dataProvider isBackendRequiredDataProvider
  666. */
  667. public function testIsBackendRequired(
  668. string $backend,
  669. array $appBackends,
  670. bool $expected,
  671. ): void {
  672. $appInfoData = array_map(
  673. static fn (array $backends) => ['dependencies' => ['backend' => $backends]],
  674. $appBackends,
  675. );
  676. $reflection = new \ReflectionClass($this->manager);
  677. $property = $reflection->getProperty('appInfos');
  678. $property->setValue($this->manager, $appInfoData);
  679. $this->assertEquals($expected, $this->manager->isBackendRequired($backend));
  680. }
  681. }