diff --git a/tests/ConsumerTest.php b/tests/ConsumerTest.php index 653601c90..629ba4aae 100644 --- a/tests/ConsumerTest.php +++ b/tests/ConsumerTest.php @@ -31,6 +31,7 @@ use OCP\Activity\ActivitySettings; use OCP\Activity\IEvent; use OCP\Activity\IManager; +use OCP\Activity\ISetting; use OCP\Config\IUserConfig; use OCP\IDBConnection; use OCP\IL10N; @@ -263,4 +264,213 @@ public function testBulkReceiveNotification(string $type, string $author, string $this->consumer->bulkReceive($this->event, $affectedUsers, $settings); } + public function testBulkReceiveEmail(): void { + $time = time(); + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp($time) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + $settings = $this->createMock(ActivitySettings::class); + $settings->method('canChangeMail')->willReturn(true); + $settings->method('isDefaultEnabledMail')->willReturn(true); + $settings->method('canChangeNotification')->willReturn(false); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'affectedUser', 2 => 'affectedUser2']); + + $this->userConfig->method('getValuesByUsers') + ->willReturnCallback(function (string $app, string $key, mixed $type, array $users): array { + if (str_contains($key, 'email')) { + return array_fill_keys($users, true); + } + if (str_contains($key, 'batchtime')) { + return array_fill_keys($users, 10); + } + return []; + }); + + $this->data->expects($this->exactly(2)) + ->method('storeMail'); + + $this->consumer->bulkReceive($this->event, ['affectedUser', 'affectedUser2'], $settings); + } + + public function testBulkReceiveNoMailWhenSettingDisabled(): void { + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + $settings = $this->createMock(ActivitySettings::class); + $settings->method('canChangeMail')->willReturn(false); + $settings->method('isDefaultEnabledMail')->willReturn(false); + $settings->method('canChangeNotification')->willReturn(false); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'affectedUser']); + + $this->data->expects($this->never()) + ->method('storeMail'); + // Notification is still sent because $notificationSetting defaults to null + // and null !== false, so the default is to send notifications + $this->notificationGenerator->expects($this->once()) + ->method('sendNotificationForEvent'); + + $this->consumer->bulkReceive($this->event, ['affectedUser'], $settings); + } + + public function testBulkReceiveDeferAndFlushNotifications(): void { + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + $settings = $this->createMock(ActivitySettings::class); + $settings->method('canChangeMail')->willReturn(false); + $settings->method('isDefaultEnabledMail')->willReturn(false); + $settings->method('canChangeNotification')->willReturn(true); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'affectedUser']); + + $this->userConfig->method('getValuesByUsers') + ->willReturnCallback(function (string $app, string $key, mixed $type, array $users): array { + return array_fill_keys($users, true); + }); + + $this->notificationGenerator->expects($this->once()) + ->method('deferNotifications') + ->willReturn(true); + $this->notificationGenerator->expects($this->once()) + ->method('flushNotifications'); + $this->notificationGenerator->expects($this->once()) + ->method('sendNotificationForEvent'); + + $this->consumer->bulkReceive($this->event, ['affectedUser'], $settings); + } + + public function testBulkReceiveNoFlushWhenDeferReturnsFalse(): void { + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + $settings = $this->createMock(ActivitySettings::class); + $settings->method('canChangeMail')->willReturn(false); + $settings->method('isDefaultEnabledMail')->willReturn(false); + $settings->method('canChangeNotification')->willReturn(true); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'affectedUser']); + + $this->userConfig->method('getValuesByUsers') + ->willReturnCallback(function (string $app, string $key, mixed $type, array $users): array { + return array_fill_keys($users, true); + }); + + $this->notificationGenerator->expects($this->once()) + ->method('deferNotifications') + ->willReturn(false); + $this->notificationGenerator->expects($this->never()) + ->method('flushNotifications'); + + $this->consumer->bulkReceive($this->event, ['affectedUser'], $settings); + } + + public function testBulkReceiveMultipleUsersWithMixedSettings(): void { + $time = time(); + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp($time) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + $settings = $this->createMock(ActivitySettings::class); + $settings->method('canChangeMail')->willReturn(true); + $settings->method('isDefaultEnabledMail')->willReturn(true); + $settings->method('canChangeNotification')->willReturn(true); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'user1', 2 => 'user2', 3 => 'author']); + + $this->userConfig->method('getValuesByUsers') + ->willReturnCallback(function (string $app, string $key, mixed $type, array $users): array { + if (str_contains($key, 'notification')) { + // Only user1 has notifications enabled + return ['user1' => true]; + } + if (str_contains($key, 'email')) { + // Only user2 has email enabled + return ['user2' => true]; + } + if (str_contains($key, 'batchtime')) { + return ['user2' => 15]; + } + return []; + }); + + // user1 and user2 get notifications (user2 has null setting which defaults to send), author is skipped + $this->notificationGenerator->expects($this->exactly(2)) + ->method('sendNotificationForEvent'); + // user2 gets email, author is skipped + $this->data->expects($this->once()) + ->method('storeMail') + ->with($this->event, $time + 15); + + $this->consumer->bulkReceive($this->event, ['user1', 'user2', 'author'], $settings); + } + + public function testBulkReceiveWithISetting(): void { + $this->event->setApp('activity') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject', ['subjectParam1']) + ->setMessage('message', ['messageParam1']) + ->setObject('', 0, 'file') + ->setLink('link'); + + // ISetting (not ActivitySettings) — canChangeNotification is not available + $settings = $this->createMock(ISetting::class); + $settings->method('canChangeMail')->willReturn(false); + + $this->data->expects($this->once()) + ->method('bulkSend') + ->willReturn([1 => 'affectedUser']); + + // Notification is still sent because $notificationSetting defaults to null (not false) + // when ISetting is used (canChangeNotification not available), and null !== false + $this->notificationGenerator->expects($this->once()) + ->method('sendNotificationForEvent'); + $this->data->expects($this->never()) + ->method('storeMail'); + + $this->consumer->bulkReceive($this->event, ['affectedUser'], $settings); + } + } diff --git a/tests/DataTest.php b/tests/DataTest.php index f67c6f17e..d08b7cb42 100644 --- a/tests/DataTest.php +++ b/tests/DataTest.php @@ -154,6 +154,68 @@ public function testStoreMail(string $actionUser, string $affectedUser, string $ $this->deleteTestMails(); } + public function testBulkSend(): void { + $this->deleteTestActivities(); + + $event = $this->realActivityManager->generateEvent(); + $event->setApp('test') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject', ['param1']) + ->setMessage('message', ['msgParam1']) + ->setObject('files', 42, 'file.txt') + ->setLink('https://example.com'); + + $affectedUsers = ['user1', 'user2', 'user3']; + $activityIds = $this->data->bulkSend($event, $affectedUsers); + + $this->assertCount(3, $activityIds); + // Values should be the affected user strings + $this->assertEqualsCanonicalizing($affectedUsers, array_values($activityIds)); + // Keys should be positive integer IDs + foreach (array_keys($activityIds) as $id) { + $this->assertGreaterThan(0, $id); + } + + // Verify rows in DB + $qb = $this->dbConnection->getQueryBuilder(); + $query = $qb->select('user', 'affecteduser', 'app', 'subject', 'object_type', 'object_id') + ->from('activity') + ->where($qb->expr()->eq('app', $qb->createNamedParameter('test'))) + ->orderBy('activity_id', 'ASC'); + $result = $query->executeQuery(); + $rows = $result->fetchAll(); + + $this->assertCount(3, $rows); + foreach ($rows as $i => $row) { + $this->assertSame('author', $row['user']); + $this->assertSame($affectedUsers[$i], $row['affecteduser']); + $this->assertSame('test', $row['app']); + $this->assertSame('subject', $row['subject']); + $this->assertSame('files', $row['object_type']); + $this->assertEquals(42, $row['object_id']); + } + + $this->deleteTestActivities(); + } + + public function testBulkSendEmptyUsers(): void { + $this->deleteTestActivities(); + + $event = $this->realActivityManager->generateEvent(); + $event->setApp('test') + ->setType('type') + ->setAuthor('author') + ->setTimestamp(time()) + ->setSubject('subject'); + + $activityIds = $this->data->bulkSend($event, []); + $this->assertEmpty($activityIds); + + $this->deleteTestActivities(); + } + public static function dataSetOffsetFromSince(): array { return [ ['ASC', '`timestamp` >= \'123465789\'', '`activity_id` > \'{id}\'', null, null, null],