diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/data/ics/free-busy-request.ics | 14 | ||||
-rw-r--r-- | tests/data/ics/free-busy-request.ics.license | 2 | ||||
-rw-r--r-- | tests/lib/Calendar/ManagerTest.php | 260 |
3 files changed, 276 insertions, 0 deletions
diff --git a/tests/data/ics/free-busy-request.ics b/tests/data/ics/free-busy-request.ics new file mode 100644 index 00000000000..dd01d35b671 --- /dev/null +++ b/tests/data/ics/free-busy-request.ics @@ -0,0 +1,14 @@ +BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Sabre//Sabre VObject 4.5.6//EN
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VFREEBUSY
+DTSTART:20250116T060000Z
+DTEND:20250117T060000Z
+ORGANIZER:mailto:admin@imap.localhost
+ATTENDEE:mailto:admin@imap.localhost
+ATTENDEE:mailto:user@imap.localhost
+ATTENDEE:mailto:empty@imap.localhost
+END:VFREEBUSY
+END:VCALENDAR
diff --git a/tests/data/ics/free-busy-request.ics.license b/tests/data/ics/free-busy-request.ics.license new file mode 100644 index 00000000000..f7f52efa96f --- /dev/null +++ b/tests/data/ics/free-busy-request.ics.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/tests/lib/Calendar/ManagerTest.php b/tests/lib/Calendar/ManagerTest.php index a7aeed98046..6c01cd90811 100644 --- a/tests/lib/Calendar/ManagerTest.php +++ b/tests/lib/Calendar/ManagerTest.php @@ -6,18 +6,26 @@ namespace Test\Calendar; +use DateTimeImmutable; use OC\AppFramework\Bootstrap\Coordinator; +use OC\Calendar\AvailabilityResult; use OC\Calendar\Manager; +use OCA\DAV\CalDAV\Auth\CustomPrincipalPlugin; +use OCA\DAV\ServerFactory; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Calendar\ICalendar; use OCP\Calendar\ICalendarIsShared; use OCP\Calendar\ICalendarIsWritable; use OCP\Calendar\ICreateFromString; use OCP\Calendar\IHandleImipMessage; +use OCP\IUser; +use OCP\IUserManager; use OCP\Security\ISecureRandom; use PHPUnit\Framework\MockObject\MockObject; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Document; use Sabre\VObject\Reader; @@ -48,6 +56,9 @@ class ManagerTest extends TestCase { /** @var ISecureRandom&MockObject */ private ISecureRandom $secureRandom; + private IUserManager&MockObject $userManager; + private ServerFactory&MockObject $serverFactory; + private VCalendar $vCalendar1a; protected function setUp(): void { @@ -58,6 +69,8 @@ class ManagerTest extends TestCase { $this->logger = $this->createMock(LoggerInterface::class); $this->time = $this->createMock(ITimeFactory::class); $this->secureRandom = $this->createMock(ISecureRandom::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->serverFactory = $this->createMock(ServerFactory::class); $this->manager = new Manager( $this->coordinator, @@ -65,6 +78,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ); // construct calendar with a 1 hour event and same start/end time zones @@ -268,6 +283,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -300,6 +317,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -331,6 +350,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -363,6 +384,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -396,6 +419,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -429,6 +454,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -462,6 +489,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -506,6 +535,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -550,6 +581,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); @@ -629,6 +662,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -661,6 +696,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -699,6 +736,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -787,6 +826,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -821,6 +862,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -859,6 +902,8 @@ class ManagerTest extends TestCase { $this->logger, $this->time, $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) ->setMethods([ 'getCalendarsForPrincipal' @@ -945,4 +990,219 @@ END:VCALENDAR EOF; return Reader::read($data); } + + private function getFreeBusyResponse(): string { + return <<<EOF +<?xml version="1.0" encoding="utf-8"?> +<cal:schedule-response xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> + <cal:response> + <cal:recipient> + <d:href>mailto:admin@imap.localhost</d:href> + </cal:recipient> + <cal:request-status>2.0;Success</cal:request-status> + <cal:calendar-data>BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 4.5.6//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VFREEBUSY +DTSTART:20250116T060000Z +DTEND:20250117T060000Z +DTSTAMP:20250111T125634Z +FREEBUSY:20250116T060000Z/20250116T230000Z +FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20250116T230000Z/20250117T060000Z +ATTENDEE:mailto:admin@imap.localhost +UID:6099eab3-9bf1-4c7a-809e-4d46957cc372 +ORGANIZER;CN=admin:mailto:admin@imap.localhost +END:VFREEBUSY +END:VCALENDAR +</cal:calendar-data> + </cal:response> + <cal:response> + <cal:recipient> + <d:href>mailto:empty@imap.localhost</d:href> + </cal:recipient> + <cal:request-status>2.0;Success</cal:request-status> + <cal:calendar-data>BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 4.5.6//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VFREEBUSY +DTSTART:20250116T060000Z +DTEND:20250117T060000Z +DTSTAMP:20250111T125634Z +ATTENDEE:mailto:empty@imap.localhost +UID:6099eab3-9bf1-4c7a-809e-4d46957cc372 +ORGANIZER;CN=admin:mailto:admin@imap.localhost +END:VFREEBUSY +END:VCALENDAR +</cal:calendar-data> + </cal:response> + <cal:response> + <cal:recipient> + <d:href>mailto:user@imap.localhost</d:href> + </cal:recipient> + <cal:request-status>2.0;Success</cal:request-status> + <cal:calendar-data>BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 4.5.6//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VFREEBUSY +DTSTART:20250116T060000Z +DTEND:20250117T060000Z +DTSTAMP:20250111T125634Z +FREEBUSY:20250116T060000Z/20250116T230000Z +FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20250116T230000Z/20250117T060000Z +ATTENDEE:mailto:user@imap.localhost +UID:6099eab3-9bf1-4c7a-809e-4d46957cc372 +ORGANIZER;CN=admin:mailto:admin@imap.localhost +END:VFREEBUSY +END:VCALENDAR +</cal:calendar-data> + </cal:response> + <cal:response> + <cal:recipient> + <d:href>mailto:nouser@domain.tld</d:href> + </cal:recipient> + <cal:request-status>3.7;Could not find principal</cal:request-status> + </cal:response> +</cal:schedule-response> +EOF; + } + + public function testCheckAvailability(): void { + $organizer = $this->createMock(IUser::class); + $organizer->expects(self::once()) + ->method('getUID') + ->willReturn('admin'); + $organizer->expects(self::once()) + ->method('getEMailAddress') + ->willReturn('admin@imap.localhost'); + + $user1 = $this->createMock(IUser::class); + $user2 = $this->createMock(IUser::class); + + $this->userManager->expects(self::exactly(3)) + ->method('getByEmail') + ->willReturnMap([ + ['user@imap.localhost', [$user1]], + ['empty@imap.localhost', [$user2]], + ['nouser@domain.tld', []], + ]); + + $authPlugin = $this->createMock(CustomPrincipalPlugin::class); + $authPlugin->expects(self::once()) + ->method('setCurrentPrincipal') + ->with('principals/users/admin'); + + $server = $this->createMock(\OCA\DAV\Connector\Sabre\Server::class); + $server->expects(self::once()) + ->method('getPlugin') + ->with('auth') + ->willReturn($authPlugin); + $server->expects(self::once()) + ->method('invokeMethod') + ->willReturnCallback(function ( + RequestInterface $request, + ResponseInterface $response, + bool $sendResponse, + ) { + $requestBody = file_get_contents(__DIR__ . '/../../data/ics/free-busy-request.ics'); + $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals('calendars/admin/outbox', $request->getPath()); + $this->assertEquals('text/calendar', $request->getHeader('Content-Type')); + $this->assertEquals('0', $request->getHeader('Depth')); + $this->assertEquals($requestBody, $request->getBodyAsString()); + $this->assertFalse($sendResponse); + $response->setStatus(200); + $response->setBody($this->getFreeBusyResponse()); + }); + + $this->serverFactory->expects(self::once()) + ->method('createAttendeeAvailabilityServer') + ->willReturn($server); + + $start = new DateTimeImmutable('2025-01-16T06:00:00Z'); + $end = new DateTimeImmutable('2025-01-17T06:00:00Z'); + $actual = $this->manager->checkAvailability($start, $end, $organizer, [ + 'user@imap.localhost', + 'empty@imap.localhost', + 'nouser@domain.tld', + ]); + $expected = [ + new AvailabilityResult('admin@imap.localhost', false), + new AvailabilityResult('empty@imap.localhost', true), + new AvailabilityResult('user@imap.localhost', false), + ]; + $this->assertEquals($expected, $actual); + } + + public function testCheckAvailabilityWithMailtoPrefix(): void { + $organizer = $this->createMock(IUser::class); + $organizer->expects(self::once()) + ->method('getUID') + ->willReturn('admin'); + $organizer->expects(self::once()) + ->method('getEMailAddress') + ->willReturn('admin@imap.localhost'); + + $user1 = $this->createMock(IUser::class); + $user2 = $this->createMock(IUser::class); + + $this->userManager->expects(self::exactly(3)) + ->method('getByEmail') + ->willReturnMap([ + ['user@imap.localhost', [$user1]], + ['empty@imap.localhost', [$user2]], + ['nouser@domain.tld', []], + ]); + + $authPlugin = $this->createMock(CustomPrincipalPlugin::class); + $authPlugin->expects(self::once()) + ->method('setCurrentPrincipal') + ->with('principals/users/admin'); + + $server = $this->createMock(\OCA\DAV\Connector\Sabre\Server::class); + $server->expects(self::once()) + ->method('getPlugin') + ->with('auth') + ->willReturn($authPlugin); + $server->expects(self::once()) + ->method('invokeMethod') + ->willReturnCallback(function ( + RequestInterface $request, + ResponseInterface $response, + bool $sendResponse, + ) { + $requestBody = file_get_contents(__DIR__ . '/../../data/ics/free-busy-request.ics'); + $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals('calendars/admin/outbox', $request->getPath()); + $this->assertEquals('text/calendar', $request->getHeader('Content-Type')); + $this->assertEquals('0', $request->getHeader('Depth')); + $this->assertEquals($requestBody, $request->getBodyAsString()); + $this->assertFalse($sendResponse); + $response->setStatus(200); + $response->setBody($this->getFreeBusyResponse()); + }); + + $this->serverFactory->expects(self::once()) + ->method('createAttendeeAvailabilityServer') + ->willReturn($server); + + $start = new DateTimeImmutable('2025-01-16T06:00:00Z'); + $end = new DateTimeImmutable('2025-01-17T06:00:00Z'); + $actual = $this->manager->checkAvailability($start, $end, $organizer, [ + 'mailto:user@imap.localhost', + 'mailto:empty@imap.localhost', + 'mailto:nouser@domain.tld', + ]); + $expected = [ + new AvailabilityResult('admin@imap.localhost', false), + new AvailabilityResult('empty@imap.localhost', true), + new AvailabilityResult('user@imap.localhost', false), + ]; + $this->assertEquals($expected, $actual); + } } |