diff --git a/apps/files_sharing/tests/ShareMountEventsTest.php b/apps/files_sharing/tests/ShareMountEventsTest.php new file mode 100644 index 0000000000000..28cd0bdcdcd67 --- /dev/null +++ b/apps/files_sharing/tests/ShareMountEventsTest.php @@ -0,0 +1,134 @@ + */ + private array $events = []; + /** @var \Closure(Event): void */ + private \Closure $listener; + + protected function setUp(): void { + parent::setUp(); + + $this->eventDispatcher = Server::get(IEventDispatcher::class); + $this->listener = function (Event $event): void { + $this->events[] = $event; + }; + $this->eventDispatcher->addListener(UserMountAddedEvent::class, $this->listener); + $this->eventDispatcher->addListener(UserMountRemovedEvent::class, $this->listener); + + $this->rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1)->newFolder(self::FOLDER); + + // The recipient has used their file system before + $this->assertFalse($this->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->nodeExists(self::FOLDER)); + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->events = []; + } + + protected function tearDown(): void { + $this->eventDispatcher->removeListener(UserMountAddedEvent::class, $this->listener); + $this->eventDispatcher->removeListener(UserMountRemovedEvent::class, $this->listener); + Server::get(SharesUpdatedListener::class)->setCutOffMarkTime(-1); + + parent::tearDown(); + } + + /** + * @return array + */ + public static function shareProvider(): array { + // A cutoff time of -1 updates the share mounts of recipients immediately, + // 0 marks recipients so their share mounts are updated on their next setup + return [ + 'user share, immediate update' => [IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2, -1], + 'user share, deferred update' => [IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 0], + 'group share, immediate update' => [IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1, -1], + 'group share, deferred update' => [IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1, 0], + ]; + } + + #[DataProvider(methodName: 'shareProvider')] + public function testMountAddedEventForCreatedShare(int $shareType, string $recipient, float $cutOffTime): void { + Server::get(SharesUpdatedListener::class)->setCutOffMarkTime($cutOffTime); + + $this->share($shareType, self::FOLDER, self::TEST_FILES_SHARING_API_USER1, $recipient, Constants::PERMISSION_ALL); + $this->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get(self::FOLDER); + + $this->assertEquals( + ['/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . self::FOLDER . '/'], + $this->getMountPointsOfEvents(UserMountAddedEvent::class, self::TEST_FILES_SHARING_API_USER2), + 'A UserMountAddedEvent should be dispatched for the share mount of the recipient', + ); + } + + #[DataProvider(methodName: 'shareProvider')] + public function testMountRemovedEventForDeletedShare(int $shareType, string $recipient, float $cutOffTime): void { + $share = $this->share($shareType, self::FOLDER, self::TEST_FILES_SHARING_API_USER1, $recipient, Constants::PERMISSION_ALL); + $this->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get(self::FOLDER); + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->events = []; + + Server::get(SharesUpdatedListener::class)->setCutOffMarkTime($cutOffTime); + $this->shareManager->deleteShare($share); + $this->assertFalse( + $this->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->nodeExists(self::FOLDER), + 'The share should no longer be mounted for the recipient', + ); + + $this->assertEquals( + ['/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . self::FOLDER . '/'], + $this->getMountPointsOfEvents(UserMountRemovedEvent::class, self::TEST_FILES_SHARING_API_USER2), + 'A UserMountRemovedEvent should be dispatched for the share mount of the recipient', + ); + } + + /** + * Log in as the user and get their user folder, as a new request by them would + */ + private function getUserFolder(string $userId): Folder { + $this->loginHelper($userId); + return $this->rootFolder->getUserFolder($userId); + } + + /** + * @param class-string $eventClass + * @return list + */ + private function getMountPointsOfEvents(string $eventClass, string $userId): array { + $mountPoints = []; + foreach ($this->events as $event) { + if ($event instanceof $eventClass && $event->mountPoint->getUser()->getUID() === $userId) { + $mountPoints[] = $event->mountPoint->getMountPoint(); + } + } + return $mountPoints; + } +}