2020-02-10 10:04:38 -05:00
< ? php
2024-07-24 10:11:47 -04:00
declare ( strict_types = 1 );
2020-02-10 10:04:38 -05:00
/**
2024-05-28 06:34:11 -04:00
* SPDX - FileCopyrightText : 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX - License - Identifier : AGPL - 3.0 - or - later
2020-02-10 10:04:38 -05:00
*/
2022-03-31 09:34:43 -04:00
namespace OCA\DAV\Tests\unit\CalDAV\WebcalCaching ;
2020-02-10 10:04:38 -05:00
use OCA\DAV\CalDAV\CalDavBackend ;
2024-07-24 10:11:47 -04:00
use OCA\DAV\CalDAV\WebcalCaching\Connection ;
2020-02-10 10:04:38 -05:00
use OCA\DAV\CalDAV\WebcalCaching\RefreshWebcalService ;
2024-07-24 10:11:47 -04:00
use OCP\AppFramework\Utility\ITimeFactory ;
2020-02-10 10:04:38 -05:00
use PHPUnit\Framework\MockObject\MockObject ;
2022-03-31 09:34:57 -04:00
use Psr\Log\LoggerInterface ;
2020-09-20 01:47:30 -04:00
use Sabre\DAV\Exception\BadRequest ;
2020-02-10 10:04:38 -05:00
use Sabre\VObject ;
2020-09-20 01:47:30 -04:00
use Sabre\VObject\Recur\NoInstancesException ;
2020-02-10 10:04:38 -05:00
use Test\TestCase ;
class RefreshWebcalServiceTest extends TestCase {
2024-07-24 10:11:47 -04:00
private CalDavBackend | MockObject $caldavBackend ;
private Connection | MockObject $connection ;
private LoggerInterface | MockObject $logger ;
private ITimeFactory | MockObject $time ;
2020-02-10 10:04:38 -05:00
protected function setUp () : void {
parent :: setUp ();
$this -> caldavBackend = $this -> createMock ( CalDavBackend :: class );
2024-07-24 10:11:47 -04:00
$this -> connection = $this -> createMock ( Connection :: class );
2022-03-31 09:34:57 -04:00
$this -> logger = $this -> createMock ( LoggerInterface :: class );
2024-07-24 10:11:47 -04:00
$this -> time = $this -> createMock ( ITimeFactory :: class );
2020-02-10 10:04:38 -05:00
}
/**
* @ param string $body
* @ param string $contentType
* @ param string $result
*
* @ dataProvider runDataProvider
*/
2023-01-20 02:38:43 -05:00
public function testRun ( string $body , string $contentType , string $result ) : void {
2020-03-16 10:04:21 -04:00
$refreshWebcalService = $this -> getMockBuilder ( RefreshWebcalService :: class )
2022-03-18 13:07:24 -04:00
-> onlyMethods ([ 'getRandomCalendarObjectUri' ])
2024-07-24 10:11:47 -04:00
-> setConstructorArgs ([ $this -> caldavBackend , $this -> logger , $this -> connection , $this -> time ])
2020-03-16 10:04:21 -04:00
-> getMock ();
$refreshWebcalService
-> method ( 'getRandomCalendarObjectUri' )
-> willReturn ( 'uri-1.ics' );
2020-02-10 10:04:38 -05:00
2024-07-24 10:11:47 -04:00
$this -> caldavBackend -> expects ( self :: once ())
2020-02-10 10:04:38 -05:00
-> method ( 'getSubscriptionsForUser' )
-> with ( 'principals/users/testuser' )
2020-03-25 17:21:27 -04:00
-> willReturn ([
2020-02-10 10:04:38 -05:00
[
'id' => '99' ,
'uri' => 'sub456' ,
2024-07-24 10:11:47 -04:00
RefreshWebcalService :: REFRESH_RATE => 'P1D' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla' ,
'lastmodified' => 0 ,
2020-02-10 10:04:38 -05:00
],
[
'id' => '42' ,
'uri' => 'sub123' ,
2024-07-24 10:11:47 -04:00
RefreshWebcalService :: REFRESH_RATE => 'PT1H' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla2' ,
'lastmodified' => 0 ,
2020-02-10 10:04:38 -05:00
],
2020-03-25 17:21:27 -04:00
]);
2020-02-10 10:04:38 -05:00
2024-07-24 10:11:47 -04:00
$this -> connection -> expects ( self :: once ())
-> method ( 'queryWebcalFeed' )
-> willReturn ( $result );
$this -> caldavBackend -> expects ( self :: once ())
2020-02-10 10:04:38 -05:00
-> method ( 'createCalendarObject' )
2020-03-16 10:04:21 -04:00
-> with ( 42 , 'uri-1.ics' , $result , 1 );
2020-02-10 10:04:38 -05:00
$refreshWebcalService -> refreshSubscription ( 'principals/users/testuser' , 'sub123' );
}
2022-03-31 09:34:57 -04:00
2024-07-24 10:11:47 -04:00
/**
* @ param string $body
* @ param string $contentType
* @ param string $result
*
* @ dataProvider identicalDataProvider
*/
public function testRunIdentical ( string $uid , array $calendarObject , string $body , string $contentType , string $result ) : void {
$refreshWebcalService = $this -> getMockBuilder ( RefreshWebcalService :: class )
-> onlyMethods ([ 'getRandomCalendarObjectUri' ])
-> setConstructorArgs ([ $this -> caldavBackend , $this -> logger , $this -> connection , $this -> time ])
-> getMock ();
$refreshWebcalService
-> method ( 'getRandomCalendarObjectUri' )
-> willReturn ( 'uri-1.ics' );
$this -> caldavBackend -> expects ( self :: once ())
-> method ( 'getSubscriptionsForUser' )
-> with ( 'principals/users/testuser' )
-> willReturn ([
[
'id' => '99' ,
'uri' => 'sub456' ,
RefreshWebcalService :: REFRESH_RATE => 'P1D' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla' ,
'lastmodified' => 0 ,
],
[
'id' => '42' ,
'uri' => 'sub123' ,
RefreshWebcalService :: REFRESH_RATE => 'PT1H' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla2' ,
'lastmodified' => 0 ,
],
]);
$this -> connection -> expects ( self :: once ())
-> method ( 'queryWebcalFeed' )
-> willReturn ( $result );
$this -> caldavBackend -> expects ( self :: once ())
-> method ( 'getLimitedCalendarObjects' )
-> willReturn ( $calendarObject );
$denormalised = [
'etag' => 100 ,
'size' => strlen ( $calendarObject [ $uid ][ 'calendardata' ]),
'uid' => 'sub456'
];
$this -> caldavBackend -> expects ( self :: once ())
-> method ( 'getDenormalizedData' )
-> willReturn ( $denormalised );
$this -> caldavBackend -> expects ( self :: never ())
-> method ( 'createCalendarObject' );
$refreshWebcalService -> refreshSubscription ( 'principals/users/testuser' , 'sub456' );
}
public function testRunJustUpdated () : void {
$refreshWebcalService = $this -> getMockBuilder ( RefreshWebcalService :: class )
-> onlyMethods ([ 'getRandomCalendarObjectUri' ])
-> setConstructorArgs ([ $this -> caldavBackend , $this -> logger , $this -> connection , $this -> time ])
-> getMock ();
$refreshWebcalService
-> method ( 'getRandomCalendarObjectUri' )
-> willReturn ( 'uri-1.ics' );
$this -> caldavBackend -> expects ( self :: once ())
-> method ( 'getSubscriptionsForUser' )
-> with ( 'principals/users/testuser' )
-> willReturn ([
[
'id' => '99' ,
'uri' => 'sub456' ,
RefreshWebcalService :: REFRESH_RATE => 'P1D' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla' ,
'lastmodified' => time (),
],
[
'id' => '42' ,
'uri' => 'sub123' ,
RefreshWebcalService :: REFRESH_RATE => 'PT1H' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla2' ,
'lastmodified' => time (),
],
]);
$timeMock = $this -> createMock ( \DateTime :: class );
$this -> time -> expects ( self :: once ())
-> method ( 'getDateTime' )
-> willReturn ( $timeMock );
$timeMock -> expects ( self :: once ())
-> method ( 'getTimestamp' )
-> willReturn ( 2101724667 );
$this -> time -> expects ( self :: once ())
-> method ( 'getTime' )
-> willReturn ( time ());
$this -> connection -> expects ( self :: never ())
-> method ( 'queryWebcalFeed' );
$this -> caldavBackend -> expects ( self :: never ())
-> method ( 'createCalendarObject' );
$refreshWebcalService -> refreshSubscription ( 'principals/users/testuser' , 'sub123' );
}
2020-09-20 01:47:30 -04:00
/**
* @ param string $body
* @ param string $contentType
* @ param string $result
*
* @ dataProvider runDataProvider
*/
2023-01-20 02:38:43 -05:00
public function testRunCreateCalendarNoException ( string $body , string $contentType , string $result ) : void {
2020-09-20 01:47:30 -04:00
$refreshWebcalService = $this -> getMockBuilder ( RefreshWebcalService :: class )
2024-07-24 10:11:47 -04:00
-> onlyMethods ([ 'getRandomCalendarObjectUri' , 'getSubscription' ,])
-> setConstructorArgs ([ $this -> caldavBackend , $this -> logger , $this -> connection , $this -> time ])
2020-09-20 01:47:30 -04:00
-> getMock ();
$refreshWebcalService
-> method ( 'getRandomCalendarObjectUri' )
-> willReturn ( 'uri-1.ics' );
$refreshWebcalService
-> method ( 'getSubscription' )
-> willReturn ([
'id' => '42' ,
'uri' => 'sub123' ,
2024-07-24 10:11:47 -04:00
RefreshWebcalService :: REFRESH_RATE => 'PT1H' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla2' ,
'lastmodified' => 0 ,
2020-09-20 01:47:30 -04:00
]);
2024-07-24 10:11:47 -04:00
$this -> connection -> expects ( self :: once ())
-> method ( 'queryWebcalFeed' )
-> willReturn ( $result );
$this -> caldavBackend -> expects ( self :: once ())
2020-09-20 01:47:30 -04:00
-> method ( 'createCalendarObject' )
-> with ( 42 , 'uri-1.ics' , $result , 1 );
2022-03-31 09:34:57 -04:00
2020-09-20 01:47:30 -04:00
$noInstanceException = new NoInstancesException ( " can't add calendar object " );
2024-07-24 10:11:47 -04:00
$this -> caldavBackend -> expects ( self :: once ())
2020-09-20 01:47:30 -04:00
-> method ( 'createCalendarObject' )
-> willThrowException ( $noInstanceException );
2022-03-31 09:34:57 -04:00
2024-07-24 10:11:47 -04:00
$this -> logger -> expects ( self :: once ())
2024-09-25 06:29:12 -04:00
-> method ( 'warning' )
2022-03-18 13:07:24 -04:00
-> with ( 'Unable to create calendar object from subscription {subscriptionId}' , [ 'exception' => $noInstanceException , 'subscriptionId' => '42' , 'source' => 'webcal://foo.bar/bla2' ]);
2020-09-20 01:47:30 -04:00
$refreshWebcalService -> refreshSubscription ( 'principals/users/testuser' , 'sub123' );
}
/**
* @ param string $body
* @ param string $contentType
* @ param string $result
*
* @ dataProvider runDataProvider
*/
2023-01-20 02:38:43 -05:00
public function testRunCreateCalendarBadRequest ( string $body , string $contentType , string $result ) : void {
2020-09-20 01:47:30 -04:00
$refreshWebcalService = $this -> getMockBuilder ( RefreshWebcalService :: class )
2024-07-24 10:11:47 -04:00
-> onlyMethods ([ 'getRandomCalendarObjectUri' , 'getSubscription' ])
-> setConstructorArgs ([ $this -> caldavBackend , $this -> logger , $this -> connection , $this -> time ])
2020-09-20 01:47:30 -04:00
-> getMock ();
$refreshWebcalService
-> method ( 'getRandomCalendarObjectUri' )
-> willReturn ( 'uri-1.ics' );
$refreshWebcalService
-> method ( 'getSubscription' )
-> willReturn ([
'id' => '42' ,
'uri' => 'sub123' ,
2024-07-24 10:11:47 -04:00
RefreshWebcalService :: REFRESH_RATE => 'PT1H' ,
RefreshWebcalService :: STRIP_TODOS => '1' ,
RefreshWebcalService :: STRIP_ALARMS => '1' ,
RefreshWebcalService :: STRIP_ATTACHMENTS => '1' ,
'source' => 'webcal://foo.bar/bla2' ,
'lastmodified' => 0 ,
2020-09-20 01:47:30 -04:00
]);
2024-07-24 10:11:47 -04:00
$this -> connection -> expects ( self :: once ())
-> method ( 'queryWebcalFeed' )
-> willReturn ( $result );
$this -> caldavBackend -> expects ( self :: once ())
2020-09-20 01:47:30 -04:00
-> method ( 'createCalendarObject' )
-> with ( 42 , 'uri-1.ics' , $result , 1 );
2022-03-31 09:34:57 -04:00
2020-09-20 01:47:30 -04:00
$badRequestException = new BadRequest ( " can't add reach calendar url " );
2024-07-24 10:11:47 -04:00
$this -> caldavBackend -> expects ( self :: once ())
2020-09-20 01:47:30 -04:00
-> method ( 'createCalendarObject' )
-> willThrowException ( $badRequestException );
2022-03-31 09:34:57 -04:00
2024-07-24 10:11:47 -04:00
$this -> logger -> expects ( self :: once ())
2024-09-25 06:29:12 -04:00
-> method ( 'warning' )
2022-03-18 13:07:24 -04:00
-> with ( 'Unable to create calendar object from subscription {subscriptionId}' , [ 'exception' => $badRequestException , 'subscriptionId' => '42' , 'source' => 'webcal://foo.bar/bla2' ]);
2020-09-20 01:47:30 -04:00
$refreshWebcalService -> refreshSubscription ( 'principals/users/testuser' , 'sub123' );
}
2020-02-10 10:04:38 -05:00
2024-07-24 10:11:47 -04:00
/**
* @ return array
*/
public static function identicalDataProvider () : array {
return [
[
'12345' ,
[
'12345' => [
'id' => 42 ,
'etag' => 100 ,
'uri' => 'sub456' ,
'calendardata' => " BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject 4.1.1//EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n UID:12345 \r \n DTSTAMP:20160218T133704Z \r \n DTSTART;VALUE=DATE:19000101 \r \n DTEND;VALUE=DATE:19000102 \r \n RRULE:FREQ=YEARLY \r \n SUMMARY:12345's Birthday (1900) \r \n TRANSP:TRANSPARENT \r \n END:VEVENT \r \n END:VCALENDAR \r \n " ,
],
],
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject 4.1.1//EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n UID:12345 \r \n DTSTAMP:20160218T133704Z \r \n DTSTART;VALUE=DATE:19000101 \r \n DTEND;VALUE=DATE:19000102 \r \n RRULE:FREQ=YEARLY \r \n SUMMARY:12345's Birthday (1900) \r \n TRANSP:TRANSPARENT \r \n END:VEVENT \r \n END:VCALENDAR \r \n " ,
'text/calendar;charset=utf8' ,
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject 4.1.1//EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n UID:12345 \r \n DTSTAMP:20180218T133704Z \r \n DTSTART;VALUE=DATE:19000101 \r \n DTEND;VALUE=DATE:19000102 \r \n RRULE:FREQ=YEARLY \r \n SUMMARY:12345's Birthday (1900) \r \n TRANSP:TRANSPARENT \r \n END:VEVENT \r \n END:VCALENDAR \r \n " ,
],
];
}
2020-02-10 10:04:38 -05:00
/**
* @ return array
*/
public function runDataProvider () : array {
return [
[
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject 4.1.1//EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n UID:12345 \r \n DTSTAMP:20160218T133704Z \r \n DTSTART;VALUE=DATE:19000101 \r \n DTEND;VALUE=DATE:19000102 \r \n RRULE:FREQ=YEARLY \r \n SUMMARY:12345's Birthday (1900) \r \n TRANSP:TRANSPARENT \r \n END:VEVENT \r \n END:VCALENDAR \r \n " ,
'text/calendar;charset=utf8' ,
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject " . VObject\Version :: VERSION . " //EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n UID:12345 \r \n DTSTAMP:20160218T133704Z \r \n DTSTART;VALUE=DATE:19000101 \r \n DTEND;VALUE=DATE:19000102 \r \n RRULE:FREQ=YEARLY \r \n SUMMARY:12345's Birthday (1900) \r \n TRANSP:TRANSPARENT \r \n END:VEVENT \r \n END:VCALENDAR \r \n " ,
],
[
'["vcalendar",[["prodid",{},"text","-//Example Corp.//Example Client//EN"],["version",{},"text","2.0"]],[["vtimezone",[["last-modified",{},"date-time","2004-01-10T03:28:45Z"],["tzid",{},"text","US/Eastern"]],[["daylight",[["dtstart",{},"date-time","2000-04-04T02:00:00"],["rrule",{},"recur",{"freq":"YEARLY","byday":"1SU","bymonth":4}],["tzname",{},"text","EDT"],["tzoffsetfrom",{},"utc-offset","-05:00"],["tzoffsetto",{},"utc-offset","-04:00"]],[]],["standard",[["dtstart",{},"date-time","2000-10-26T02:00:00"],["rrule",{},"recur",{"freq":"YEARLY","byday":"1SU","bymonth":10}],["tzname",{},"text","EST"],["tzoffsetfrom",{},"utc-offset","-04:00"],["tzoffsetto",{},"utc-offset","-05:00"]],[]]]],["vevent",[["dtstamp",{},"date-time","2006-02-06T00:11:21Z"],["dtstart",{"tzid":"US/Eastern"},"date-time","2006-01-02T14:00:00"],["duration",{},"duration","PT1H"],["recurrence-id",{"tzid":"US/Eastern"},"date-time","2006-01-04T12:00:00"],["summary",{},"text","Event #2"],["uid",{},"text","12345"]],[]]]]' ,
'application/calendar+json' ,
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject " . VObject\Version :: VERSION . " //EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VTIMEZONE \r \n LAST-MODIFIED:20040110T032845Z \r \n TZID:US/Eastern \r \n BEGIN:DAYLIGHT \r \n DTSTART:20000404T020000 \r \n RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 \r \n TZNAME:EDT \r \n TZOFFSETFROM:-0500 \r \n TZOFFSETTO:-0400 \r \n END:DAYLIGHT \r \n BEGIN:STANDARD \r \n DTSTART:20001026T020000 \r \n RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=10 \r \n TZNAME:EST \r \n TZOFFSETFROM:-0400 \r \n TZOFFSETTO:-0500 \r \n END:STANDARD \r \n END:VTIMEZONE \r \n BEGIN:VEVENT \r \n DTSTAMP:20060206T001121Z \r \n DTSTART;TZID=US/Eastern:20060102T140000 \r \n DURATION:PT1H \r \n RECURRENCE-ID;TZID=US/Eastern:20060104T120000 \r \n SUMMARY:Event #2 \r \n UID:12345 \r \n END:VEVENT \r \n END:VCALENDAR \r \n "
],
[
'<?xml version="1.0" encoding="utf-8" ?><icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"><vcalendar><properties><prodid><text>-//Example Inc.//Example Client//EN</text></prodid><version><text>2.0</text></version></properties><components><vevent><properties><dtstamp><date-time>2006-02-06T00:11:21Z</date-time></dtstamp><dtstart><parameters><tzid><text>US/Eastern</text></tzid></parameters><date-time>2006-01-04T14:00:00</date-time></dtstart><duration><duration>PT1H</duration></duration><recurrence-id><parameters><tzid><text>US/Eastern</text></tzid></parameters><date-time>2006-01-04T12:00:00</date-time></recurrence-id><summary><text>Event #2 bis</text></summary><uid><text>12345</text></uid></properties></vevent></components></vcalendar></icalendar>' ,
'application/calendar+xml' ,
" BEGIN:VCALENDAR \r \n VERSION:2.0 \r \n PRODID:-//Sabre//Sabre VObject " . VObject\Version :: VERSION . " //EN \r \n CALSCALE:GREGORIAN \r \n BEGIN:VEVENT \r \n DTSTAMP:20060206T001121Z \r \n DTSTART;TZID=US/Eastern:20060104T140000 \r \n DURATION:PT1H \r \n RECURRENCE-ID;TZID=US/Eastern:20060104T120000 \r \n SUMMARY:Event #2 bis \r \n UID:12345 \r \n END:VEVENT \r \n END:VCALENDAR \r \n "
]
];
}
}