BackendTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\Tests\unit\DAV\Sharing;
  8. use OCA\DAV\CalDAV\Sharing\Backend as CalendarSharingBackend;
  9. use OCA\DAV\CalDAV\Sharing\Service;
  10. use OCA\DAV\CardDAV\Sharing\Backend as ContactsSharingBackend;
  11. use OCA\DAV\Connector\Sabre\Principal;
  12. use OCA\DAV\DAV\Sharing\Backend;
  13. use OCA\DAV\DAV\Sharing\IShareable;
  14. use OCP\ICache;
  15. use OCP\ICacheFactory;
  16. use OCP\IDBConnection;
  17. use OCP\IGroupManager;
  18. use OCP\IUserManager;
  19. use PHPUnit\Framework\MockObject\MockObject;
  20. use Psr\Log\LoggerInterface;
  21. use Test\TestCase;
  22. class BackendTest extends TestCase {
  23. private IDBConnection|MockObject $db;
  24. private IUserManager|MockObject $userManager;
  25. private IGroupManager|MockObject $groupManager;
  26. private MockObject|Principal $principalBackend;
  27. private MockObject|ICache $shareCache;
  28. private LoggerInterface|MockObject $logger;
  29. private MockObject|ICacheFactory $cacheFactory;
  30. private Service|MockObject $calendarService;
  31. private CalendarSharingBackend $backend;
  32. protected function setUp(): void {
  33. parent::setUp();
  34. $this->db = $this->createMock(IDBConnection::class);
  35. $this->userManager = $this->createMock(IUserManager::class);
  36. $this->groupManager = $this->createMock(IGroupManager::class);
  37. $this->principalBackend = $this->createMock(Principal::class);
  38. $this->cacheFactory = $this->createMock(ICacheFactory::class);
  39. $this->shareCache = $this->createMock(ICache::class);
  40. $this->logger = $this->createMock(LoggerInterface::class);
  41. $this->calendarService = $this->createMock(Service::class);
  42. $this->cacheFactory->expects(self::any())
  43. ->method('createInMemory')
  44. ->willReturn($this->shareCache);
  45. $this->backend = new CalendarSharingBackend(
  46. $this->userManager,
  47. $this->groupManager,
  48. $this->principalBackend,
  49. $this->cacheFactory,
  50. $this->calendarService,
  51. $this->logger,
  52. );
  53. }
  54. public function testUpdateShareCalendarBob(): void {
  55. $shareable = $this->createConfiguredMock(IShareable::class, [
  56. 'getOwner' => 'principals/users/alice',
  57. 'getResourceId' => 42,
  58. ]);
  59. $add = [
  60. [
  61. 'href' => 'principal:principals/users/bob',
  62. 'readOnly' => true,
  63. ]
  64. ];
  65. $principal = 'principals/users/bob';
  66. $this->shareCache->expects(self::once())
  67. ->method('clear');
  68. $this->principalBackend->expects(self::once())
  69. ->method('findByUri')
  70. ->willReturn($principal);
  71. $this->userManager->expects(self::once())
  72. ->method('userExists')
  73. ->willReturn(true);
  74. $this->groupManager->expects(self::never())
  75. ->method('groupExists');
  76. $this->calendarService->expects(self::once())
  77. ->method('shareWith')
  78. ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
  79. $this->backend->updateShares($shareable, $add, []);
  80. }
  81. public function testUpdateShareCalendarGroup(): void {
  82. $shareable = $this->createConfiguredMock(IShareable::class, [
  83. 'getOwner' => 'principals/users/alice',
  84. 'getResourceId' => 42,
  85. ]);
  86. $add = [
  87. [
  88. 'href' => 'principal:principals/groups/bob',
  89. 'readOnly' => true,
  90. ]
  91. ];
  92. $principal = 'principals/groups/bob';
  93. $this->shareCache->expects(self::once())
  94. ->method('clear');
  95. $this->principalBackend->expects(self::once())
  96. ->method('findByUri')
  97. ->willReturn($principal);
  98. $this->userManager->expects(self::never())
  99. ->method('userExists');
  100. $this->groupManager->expects(self::once())
  101. ->method('groupExists')
  102. ->willReturn(true);
  103. $this->calendarService->expects(self::once())
  104. ->method('shareWith')
  105. ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
  106. $this->backend->updateShares($shareable, $add, []);
  107. }
  108. public function testUpdateShareContactsBob(): void {
  109. $shareable = $this->createConfiguredMock(IShareable::class, [
  110. 'getOwner' => 'principals/users/alice',
  111. 'getResourceId' => 42,
  112. ]);
  113. $add = [
  114. [
  115. 'href' => 'principal:principals/users/bob',
  116. 'readOnly' => true,
  117. ]
  118. ];
  119. $principal = 'principals/users/bob';
  120. $this->shareCache->expects(self::once())
  121. ->method('clear');
  122. $this->principalBackend->expects(self::once())
  123. ->method('findByUri')
  124. ->willReturn($principal);
  125. $this->userManager->expects(self::once())
  126. ->method('userExists')
  127. ->willReturn(true);
  128. $this->groupManager->expects(self::never())
  129. ->method('groupExists');
  130. $this->calendarService->expects(self::once())
  131. ->method('shareWith')
  132. ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
  133. $this->backend->updateShares($shareable, $add, []);
  134. }
  135. public function testUpdateShareContactsGroup(): void {
  136. $shareable = $this->createConfiguredMock(IShareable::class, [
  137. 'getOwner' => 'principals/users/alice',
  138. 'getResourceId' => 42,
  139. ]);
  140. $add = [
  141. [
  142. 'href' => 'principal:principals/groups/bob',
  143. 'readOnly' => true,
  144. ]
  145. ];
  146. $principal = 'principals/groups/bob';
  147. $this->shareCache->expects(self::once())
  148. ->method('clear');
  149. $this->principalBackend->expects(self::once())
  150. ->method('findByUri')
  151. ->willReturn($principal);
  152. $this->userManager->expects(self::never())
  153. ->method('userExists');
  154. $this->groupManager->expects(self::once())
  155. ->method('groupExists')
  156. ->willReturn(true);
  157. $this->calendarService->expects(self::once())
  158. ->method('shareWith')
  159. ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
  160. $this->backend->updateShares($shareable, $add, []);
  161. }
  162. public function testUpdateShareCircle(): void {
  163. $shareable = $this->createConfiguredMock(IShareable::class, [
  164. 'getOwner' => 'principals/users/alice',
  165. 'getResourceId' => 42,
  166. ]);
  167. $add = [
  168. [
  169. 'href' => 'principal:principals/circles/bob',
  170. 'readOnly' => true,
  171. ]
  172. ];
  173. $principal = 'principals/groups/bob';
  174. $this->shareCache->expects(self::once())
  175. ->method('clear');
  176. $this->principalBackend->expects(self::once())
  177. ->method('findByUri')
  178. ->willReturn($principal);
  179. $this->userManager->expects(self::never())
  180. ->method('userExists');
  181. $this->groupManager->expects(self::once())
  182. ->method('groupExists')
  183. ->willReturn(true);
  184. $this->calendarService->expects(self::once())
  185. ->method('shareWith')
  186. ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
  187. $this->backend->updateShares($shareable, $add, []);
  188. }
  189. public function testUnshareBob(): void {
  190. $shareable = $this->createConfiguredMock(IShareable::class, [
  191. 'getOwner' => 'principals/users/alice',
  192. 'getResourceId' => 42,
  193. ]);
  194. $remove = [
  195. [
  196. 'href' => 'principal:principals/users/bob',
  197. 'readOnly' => true,
  198. ]
  199. ];
  200. $principal = 'principals/users/bob';
  201. $this->shareCache->expects(self::once())
  202. ->method('clear');
  203. $this->principalBackend->expects(self::once())
  204. ->method('findByUri')
  205. ->willReturn($principal);
  206. $this->calendarService->expects(self::once())
  207. ->method('deleteShare')
  208. ->with($shareable->getResourceId(), $principal);
  209. $this->calendarService->expects(self::once())
  210. ->method('hasGroupShare')
  211. ->willReturn(false);
  212. $this->calendarService->expects(self::never())
  213. ->method('unshare');
  214. $this->backend->updateShares($shareable, [], $remove);
  215. }
  216. public function testUnshareWithBobGroup(): void {
  217. $shareable = $this->createConfiguredMock(IShareable::class, [
  218. 'getOwner' => 'principals/users/alice',
  219. 'getResourceId' => 42,
  220. ]);
  221. $remove = [
  222. [
  223. 'href' => 'principal:principals/users/bob',
  224. 'readOnly' => true,
  225. ]
  226. ];
  227. $oldShares = [
  228. [
  229. 'href' => 'principal:principals/groups/bob',
  230. 'commonName' => 'bob',
  231. 'status' => 1,
  232. 'readOnly' => true,
  233. '{http://owncloud.org/ns}principal' => 'principals/groups/bob',
  234. '{http://owncloud.org/ns}group-share' => true,
  235. ]
  236. ];
  237. $this->shareCache->expects(self::once())
  238. ->method('clear');
  239. $this->principalBackend->expects(self::once())
  240. ->method('findByUri')
  241. ->willReturn('principals/users/bob');
  242. $this->calendarService->expects(self::once())
  243. ->method('deleteShare')
  244. ->with($shareable->getResourceId(), 'principals/users/bob');
  245. $this->calendarService->expects(self::once())
  246. ->method('hasGroupShare')
  247. ->with($oldShares)
  248. ->willReturn(true);
  249. $this->calendarService->expects(self::once())
  250. ->method('unshare')
  251. ->with($shareable->getResourceId(), 'principals/users/bob');
  252. $this->backend->updateShares($shareable, [], $remove, $oldShares);
  253. }
  254. public function testGetShares(): void {
  255. $resourceId = 42;
  256. $principal = 'principals/groups/bob';
  257. $rows = [
  258. [
  259. 'principaluri' => $principal,
  260. 'access' => Backend::ACCESS_READ,
  261. ]
  262. ];
  263. $expected = [
  264. [
  265. 'href' => 'principal:principals/groups/bob',
  266. 'commonName' => 'bob',
  267. 'status' => 1,
  268. 'readOnly' => true,
  269. '{http://owncloud.org/ns}principal' => $principal,
  270. '{http://owncloud.org/ns}group-share' => true,
  271. ]
  272. ];
  273. $this->shareCache->expects(self::once())
  274. ->method('get')
  275. ->with((string)$resourceId)
  276. ->willReturn(null);
  277. $this->calendarService->expects(self::once())
  278. ->method('getShares')
  279. ->with($resourceId)
  280. ->willReturn($rows);
  281. $this->principalBackend->expects(self::once())
  282. ->method('getPrincipalByPath')
  283. ->with($principal)
  284. ->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
  285. $this->shareCache->expects(self::once())
  286. ->method('set')
  287. ->with((string)$resourceId, $expected);
  288. $result = $this->backend->getShares($resourceId);
  289. $this->assertEquals($expected, $result);
  290. }
  291. public function testGetSharesAddressbooks(): void {
  292. $service = $this->createMock(\OCA\DAV\CardDAV\Sharing\Service::class);
  293. $backend = new ContactsSharingBackend(
  294. $this->userManager,
  295. $this->groupManager,
  296. $this->principalBackend,
  297. $this->cacheFactory,
  298. $service,
  299. $this->logger);
  300. $resourceId = 42;
  301. $principal = 'principals/groups/bob';
  302. $rows = [
  303. [
  304. 'principaluri' => $principal,
  305. 'access' => Backend::ACCESS_READ,
  306. ]
  307. ];
  308. $expected = [
  309. [
  310. 'href' => 'principal:principals/groups/bob',
  311. 'commonName' => 'bob',
  312. 'status' => 1,
  313. 'readOnly' => true,
  314. '{http://owncloud.org/ns}principal' => $principal,
  315. '{http://owncloud.org/ns}group-share' => true,
  316. ]
  317. ];
  318. $this->shareCache->expects(self::once())
  319. ->method('get')
  320. ->with((string)$resourceId)
  321. ->willReturn(null);
  322. $service->expects(self::once())
  323. ->method('getShares')
  324. ->with($resourceId)
  325. ->willReturn($rows);
  326. $this->principalBackend->expects(self::once())
  327. ->method('getPrincipalByPath')
  328. ->with($principal)
  329. ->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
  330. $this->shareCache->expects(self::once())
  331. ->method('set')
  332. ->with((string)$resourceId, $expected);
  333. $result = $backend->getShares($resourceId);
  334. $this->assertEquals($expected, $result);
  335. }
  336. public function testPreloadShares(): void {
  337. $resourceIds = [42, 99];
  338. $rows = [
  339. [
  340. 'resourceid' => 42,
  341. 'principaluri' => 'principals/groups/bob',
  342. 'access' => Backend::ACCESS_READ,
  343. ],
  344. [
  345. 'resourceid' => 99,
  346. 'principaluri' => 'principals/users/carlos',
  347. 'access' => Backend::ACCESS_READ_WRITE,
  348. ]
  349. ];
  350. $principalResults = [
  351. ['uri' => 'principals/groups/bob', '{DAV:}displayname' => 'bob'],
  352. ['uri' => 'principals/users/carlos', '{DAV:}displayname' => 'carlos'],
  353. ];
  354. $this->shareCache->expects(self::exactly(2))
  355. ->method('get')
  356. ->willReturn(null);
  357. $this->calendarService->expects(self::once())
  358. ->method('getSharesForIds')
  359. ->with($resourceIds)
  360. ->willReturn($rows);
  361. $this->principalBackend->expects(self::exactly(2))
  362. ->method('getPrincipalByPath')
  363. ->willReturnCallback(function (string $principal) use ($principalResults) {
  364. switch ($principal) {
  365. case 'principals/groups/bob':
  366. return $principalResults[0];
  367. default:
  368. return $principalResults[1];
  369. }
  370. });
  371. $this->shareCache->expects(self::exactly(2))
  372. ->method('set');
  373. $this->backend->preloadShares($resourceIds);
  374. }
  375. }