PageRenderTime 62ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/Sabre/CalDAV/PluginTest.php

https://github.com/agilastic/sabre-dav
PHP | 1150 lines | 852 code | 247 blank | 51 comment | 12 complexity | 9cb817f86fa71842075371f017d1fd6e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. namespace Sabre\CalDAV;
  3. use Sabre\DAVACL;
  4. use Sabre\DAV;
  5. use Sabre\HTTP;
  6. require_once 'Sabre/HTTP/ResponseMock.php';
  7. require_once 'Sabre/CalDAV/TestUtil.php';
  8. class PluginTest extends \PHPUnit_Framework_TestCase {
  9. /**
  10. * @var Sabre\DAV\Server
  11. */
  12. protected $server;
  13. /**
  14. * @var Sabre\CalDAV\Plugin
  15. */
  16. protected $plugin;
  17. protected $response;
  18. /**
  19. * @var Sabre\CalDAV\Backend\PDO
  20. */
  21. protected $caldavBackend;
  22. function setup() {
  23. $this->caldavBackend = new Backend\Mock(array(
  24. array(
  25. 'id' => 1,
  26. 'uri' => 'UUID-123467',
  27. 'principaluri' => 'principals/user1',
  28. '{DAV:}displayname' => 'user1 calendar',
  29. '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
  30. '{http://apple.com/ns/ical/}calendar-order' => '1',
  31. '{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
  32. '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')),
  33. ),
  34. array(
  35. 'id' => 2,
  36. 'uri' => 'UUID-123468',
  37. 'principaluri' => 'principals/user1',
  38. '{DAV:}displayname' => 'user1 calendar2',
  39. '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
  40. '{http://apple.com/ns/ical/}calendar-order' => '1',
  41. '{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
  42. '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')),
  43. )
  44. ), array(
  45. 1 => array(
  46. 'UUID-2345' => array(
  47. 'calendardata' => TestUtil::getTestCalendarData(),
  48. )
  49. )
  50. ));
  51. $principalBackend = new DAVACL\PrincipalBackend\Mock();
  52. $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read',array('principals/user1'));
  53. $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write',array('principals/user1'));
  54. $principalBackend->addPrincipal(array(
  55. 'uri' => 'principals/admin/calendar-proxy-read',
  56. ));
  57. $principalBackend->addPrincipal(array(
  58. 'uri' => 'principals/admin/calendar-proxy-write',
  59. ));
  60. $calendars = new CalendarRootNode($principalBackend,$this->caldavBackend);
  61. $principals = new Principal\Collection($principalBackend);
  62. $root = new DAV\SimpleCollection('root');
  63. $root->addChild($calendars);
  64. $root->addChild($principals);
  65. $objectTree = new DAV\ObjectTree($root);
  66. $this->server = new DAV\Server($objectTree);
  67. $this->server->debugExceptions = true;
  68. $this->server->setBaseUri('/');
  69. $this->plugin = new Plugin();
  70. $this->server->addPlugin($this->plugin);
  71. // Adding ACL plugin
  72. $this->server->addPlugin(new DAVACL\Plugin());
  73. // Adding Auth plugin, and ensuring that we are logged in.
  74. $authBackend = new DAV\Auth\Backend\Mock();
  75. $authBackend->defaultUser = 'user1';
  76. $authPlugin = new DAV\Auth\Plugin($authBackend, 'SabreDAV');
  77. $this->server->addPlugin($authPlugin);
  78. // This forces a login
  79. $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response());
  80. $this->response = new HTTP\ResponseMock();
  81. $this->server->httpResponse = $this->response;
  82. }
  83. function testSimple() {
  84. $this->assertEquals(array('MKCALENDAR'), $this->plugin->getHTTPMethods('calendars/user1/randomnewcalendar'));
  85. $this->assertEquals(array('calendar-access','calendar-proxy'), $this->plugin->getFeatures());
  86. $this->assertArrayHasKey('urn:ietf:params:xml:ns:caldav', $this->server->xmlNamespaces);
  87. }
  88. function testUnknownMethodPassThrough() {
  89. $request = HTTP\Request::createFromServerArray(array(
  90. 'REQUEST_METHOD' => 'MKBREAKFAST',
  91. 'REQUEST_URI' => '/',
  92. ));
  93. $this->server->httpRequest = $request;
  94. $this->server->exec();
  95. $this->assertEquals('501 Not Implemented', $this->response->status,'Incorrect status returned. Full response body:' . $this->response->body);
  96. }
  97. function testReportPassThrough() {
  98. $request = HTTP\Request::createFromServerArray(array(
  99. 'REQUEST_METHOD' => 'REPORT',
  100. 'HTTP_CONTENT_TYPE' => 'application/xml',
  101. 'REQUEST_URI' => '/',
  102. ));
  103. $request->setBody('<?xml version="1.0"?><s:somereport xmlns:s="http://www.rooftopsolutions.nl/NS/example" />');
  104. $this->server->httpRequest = $request;
  105. $this->server->exec();
  106. $this->assertEquals('403 Forbidden', $this->response->status);
  107. }
  108. function testMkCalendarBadLocation() {
  109. $request = HTTP\Request::createFromServerArray(array(
  110. 'REQUEST_METHOD' => 'MKCALENDAR',
  111. 'REQUEST_URI' => '/blabla',
  112. ));
  113. $body = '<?xml version="1.0" encoding="utf-8" ?>
  114. <C:mkcalendar xmlns:D="DAV:"
  115. xmlns:C="urn:ietf:params:xml:ns:caldav">
  116. <D:set>
  117. <D:prop>
  118. <D:displayname>Lisa\'s Events</D:displayname>
  119. <C:calendar-description xml:lang="en"
  120. >Calendar restricted to events.</C:calendar-description>
  121. <C:supported-calendar-component-set>
  122. <C:comp name="VEVENT"/>
  123. </C:supported-calendar-component-set>
  124. <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
  125. PRODID:-//Example Corp.//CalDAV Client//EN
  126. VERSION:2.0
  127. BEGIN:VTIMEZONE
  128. TZID:US-Eastern
  129. LAST-MODIFIED:19870101T000000Z
  130. BEGIN:STANDARD
  131. DTSTART:19671029T020000
  132. RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
  133. TZOFFSETFROM:-0400
  134. TZOFFSETTO:-0500
  135. TZNAME:Eastern Standard Time (US & Canada)
  136. END:STANDARD
  137. BEGIN:DAYLIGHT
  138. DTSTART:19870405T020000
  139. RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
  140. TZOFFSETFROM:-0500
  141. TZOFFSETTO:-0400
  142. TZNAME:Eastern Daylight Time (US & Canada)
  143. END:DAYLIGHT
  144. END:VTIMEZONE
  145. END:VCALENDAR
  146. ]]></C:calendar-timezone>
  147. </D:prop>
  148. </D:set>
  149. </C:mkcalendar>';
  150. $request->setBody($body);
  151. $this->server->httpRequest = $request;
  152. $this->server->exec();
  153. $this->assertEquals('403 Forbidden', $this->response->status);
  154. }
  155. function testMkCalendarNoParentNode() {
  156. $request = HTTP\Request::createFromServerArray(array(
  157. 'REQUEST_METHOD' => 'MKCALENDAR',
  158. 'REQUEST_URI' => '/doesntexist/calendar',
  159. ));
  160. $body = '<?xml version="1.0" encoding="utf-8" ?>
  161. <C:mkcalendar xmlns:D="DAV:"
  162. xmlns:C="urn:ietf:params:xml:ns:caldav">
  163. <D:set>
  164. <D:prop>
  165. <D:displayname>Lisa\'s Events</D:displayname>
  166. <C:calendar-description xml:lang="en"
  167. >Calendar restricted to events.</C:calendar-description>
  168. <C:supported-calendar-component-set>
  169. <C:comp name="VEVENT"/>
  170. </C:supported-calendar-component-set>
  171. <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
  172. PRODID:-//Example Corp.//CalDAV Client//EN
  173. VERSION:2.0
  174. BEGIN:VTIMEZONE
  175. TZID:US-Eastern
  176. LAST-MODIFIED:19870101T000000Z
  177. BEGIN:STANDARD
  178. DTSTART:19671029T020000
  179. RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
  180. TZOFFSETFROM:-0400
  181. TZOFFSETTO:-0500
  182. TZNAME:Eastern Standard Time (US & Canada)
  183. END:STANDARD
  184. BEGIN:DAYLIGHT
  185. DTSTART:19870405T020000
  186. RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
  187. TZOFFSETFROM:-0500
  188. TZOFFSETTO:-0400
  189. TZNAME:Eastern Daylight Time (US & Canada)
  190. END:DAYLIGHT
  191. END:VTIMEZONE
  192. END:VCALENDAR
  193. ]]></C:calendar-timezone>
  194. </D:prop>
  195. </D:set>
  196. </C:mkcalendar>';
  197. $request->setBody($body);
  198. $this->server->httpRequest = $request;
  199. $this->server->exec();
  200. $this->assertEquals('409 Conflict', $this->response->status);
  201. }
  202. function testMkCalendarExistingCalendar() {
  203. $request = HTTP\Request::createFromServerArray(array(
  204. 'REQUEST_METHOD' => 'MKCALENDAR',
  205. 'REQUEST_URI' => '/calendars/user1/UUID-123467',
  206. ));
  207. $body = '<?xml version="1.0" encoding="utf-8" ?>
  208. <C:mkcalendar xmlns:D="DAV:"
  209. xmlns:C="urn:ietf:params:xml:ns:caldav">
  210. <D:set>
  211. <D:prop>
  212. <D:displayname>Lisa\'s Events</D:displayname>
  213. <C:calendar-description xml:lang="en"
  214. >Calendar restricted to events.</C:calendar-description>
  215. <C:supported-calendar-component-set>
  216. <C:comp name="VEVENT"/>
  217. </C:supported-calendar-component-set>
  218. <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
  219. PRODID:-//Example Corp.//CalDAV Client//EN
  220. VERSION:2.0
  221. BEGIN:VTIMEZONE
  222. TZID:US-Eastern
  223. LAST-MODIFIED:19870101T000000Z
  224. BEGIN:STANDARD
  225. DTSTART:19671029T020000
  226. RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
  227. TZOFFSETFROM:-0400
  228. TZOFFSETTO:-0500
  229. TZNAME:Eastern Standard Time (US & Canada)
  230. END:STANDARD
  231. BEGIN:DAYLIGHT
  232. DTSTART:19870405T020000
  233. RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
  234. TZOFFSETFROM:-0500
  235. TZOFFSETTO:-0400
  236. TZNAME:Eastern Daylight Time (US & Canada)
  237. END:DAYLIGHT
  238. END:VTIMEZONE
  239. END:VCALENDAR
  240. ]]></C:calendar-timezone>
  241. </D:prop>
  242. </D:set>
  243. </C:mkcalendar>';
  244. $request->setBody($body);
  245. $this->server->httpRequest = $request;
  246. $this->server->exec();
  247. $this->assertEquals('405 Method Not Allowed', $this->response->status);
  248. }
  249. function testMkCalendarSucceed() {
  250. $request = HTTP\Request::createFromServerArray(array(
  251. 'REQUEST_METHOD' => 'MKCALENDAR',
  252. 'REQUEST_URI' => '/calendars/user1/NEWCALENDAR',
  253. ));
  254. $timezone = 'BEGIN:VCALENDAR
  255. PRODID:-//Example Corp.//CalDAV Client//EN
  256. VERSION:2.0
  257. BEGIN:VTIMEZONE
  258. TZID:US-Eastern
  259. LAST-MODIFIED:19870101T000000Z
  260. BEGIN:STANDARD
  261. DTSTART:19671029T020000
  262. RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
  263. TZOFFSETFROM:-0400
  264. TZOFFSETTO:-0500
  265. TZNAME:Eastern Standard Time (US & Canada)
  266. END:STANDARD
  267. BEGIN:DAYLIGHT
  268. DTSTART:19870405T020000
  269. RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
  270. TZOFFSETFROM:-0500
  271. TZOFFSETTO:-0400
  272. TZNAME:Eastern Daylight Time (US & Canada)
  273. END:DAYLIGHT
  274. END:VTIMEZONE
  275. END:VCALENDAR';
  276. $body = '<?xml version="1.0" encoding="utf-8" ?>
  277. <C:mkcalendar xmlns:D="DAV:"
  278. xmlns:C="urn:ietf:params:xml:ns:caldav">
  279. <D:set>
  280. <D:prop>
  281. <D:displayname>Lisa\'s Events</D:displayname>
  282. <C:calendar-description xml:lang="en"
  283. >Calendar restricted to events.</C:calendar-description>
  284. <C:supported-calendar-component-set>
  285. <C:comp name="VEVENT"/>
  286. </C:supported-calendar-component-set>
  287. <C:calendar-timezone><![CDATA[' . $timezone . ']]></C:calendar-timezone>
  288. </D:prop>
  289. </D:set>
  290. </C:mkcalendar>';
  291. $request->setBody($body);
  292. $this->server->httpRequest = $request;
  293. $this->server->exec();
  294. $this->assertEquals('201 Created', $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body);
  295. $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
  296. $this->assertEquals(3, count($calendars));
  297. $newCalendar = null;
  298. foreach($calendars as $calendar) {
  299. if ($calendar['uri'] === 'NEWCALENDAR') {
  300. $newCalendar = $calendar;
  301. break;
  302. }
  303. }
  304. $this->assertInternalType('array',$newCalendar);
  305. $keys = array(
  306. 'uri' => 'NEWCALENDAR',
  307. 'id' => null,
  308. '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar restricted to events.',
  309. '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => $timezone,
  310. '{DAV:}displayname' => 'Lisa\'s Events',
  311. '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null,
  312. );
  313. foreach($keys as $key=>$value) {
  314. $this->assertArrayHasKey($key, $newCalendar);
  315. if (is_null($value)) continue;
  316. $this->assertEquals($value, $newCalendar[$key]);
  317. }
  318. $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
  319. $this->assertTrue($newCalendar[$sccs] instanceof Property\SupportedCalendarComponentSet);
  320. $this->assertEquals(array('VEVENT'),$newCalendar[$sccs]->getValue());
  321. }
  322. function testMkCalendarEmptyBodySucceed() {
  323. $request = HTTP\Request::createFromServerArray(array(
  324. 'REQUEST_METHOD' => 'MKCALENDAR',
  325. 'REQUEST_URI' => '/calendars/user1/NEWCALENDAR',
  326. ));
  327. $request->setBody('');
  328. $this->server->httpRequest = $request;
  329. $this->server->exec();
  330. $this->assertEquals('201 Created', $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body);
  331. $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
  332. $this->assertEquals(3, count($calendars));
  333. $newCalendar = null;
  334. foreach($calendars as $calendar) {
  335. if ($calendar['uri'] === 'NEWCALENDAR') {
  336. $newCalendar = $calendar;
  337. break;
  338. }
  339. }
  340. $this->assertInternalType('array',$newCalendar);
  341. $keys = array(
  342. 'uri' => 'NEWCALENDAR',
  343. 'id' => null,
  344. '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null,
  345. );
  346. foreach($keys as $key=>$value) {
  347. $this->assertArrayHasKey($key, $newCalendar);
  348. if (is_null($value)) continue;
  349. $this->assertEquals($value, $newCalendar[$key]);
  350. }
  351. $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
  352. $this->assertTrue($newCalendar[$sccs] instanceof Property\SupportedCalendarComponentSet);
  353. $this->assertEquals(array('VEVENT','VTODO'),$newCalendar[$sccs]->getValue());
  354. }
  355. function testPrincipalProperties() {
  356. $httpRequest = HTTP\Request::createFromServerArray(array(
  357. 'HTTP_HOST' => 'sabredav.org',
  358. ));
  359. $this->server->httpRequest = $httpRequest;
  360. $props = $this->server->getPropertiesForPath('/principals/user1',array(
  361. '{urn:ietf:params:xml:ns:caldav}calendar-home-set',
  362. '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL',
  363. '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',
  364. '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for',
  365. '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for',
  366. '{' . Plugin::NS_CALENDARSERVER . '}notification-URL',
  367. ));
  368. $this->assertArrayHasKey(0,$props);
  369. $this->assertArrayHasKey(200,$props[0]);
  370. $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-home-set',$props[0][200]);
  371. $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-home-set'];
  372. $this->assertTrue($prop instanceof DAV\Property\Href);
  373. $this->assertEquals('calendars/user1/',$prop->getHref());
  374. $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL',$props[0][200]);
  375. $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL'];
  376. $this->assertTrue($prop instanceof DAV\Property\Href);
  377. $this->assertEquals('calendars/user1/outbox',$prop->getHref());
  378. $this->assertArrayHasKey('{'.Plugin::NS_CALENDARSERVER .'}notification-URL',$props[0][200]);
  379. $prop = $props[0][200]['{'.Plugin::NS_CALENDARSERVER .'}notification-URL'];
  380. $this->assertTrue($prop instanceof DAV\Property\Href);
  381. $this->assertEquals('calendars/user1/notifications/',$prop->getHref());
  382. $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',$props[0][200]);
  383. $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set'];
  384. $this->assertTrue($prop instanceof DAV\Property\HrefList);
  385. $this->assertEquals(array('mailto:user1.sabredav@sabredav.org','/principals/user1/'),$prop->getHrefs());
  386. $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-read-for', $props[0][200]);
  387. $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-read-for'];
  388. $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $prop);
  389. $this->assertEquals(array('principals/admin'), $prop->getHrefs());
  390. $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-write-for', $props[0][200]);
  391. $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-write-for'];
  392. $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $prop);
  393. $this->assertEquals(array('principals/admin'), $prop->getHrefs());
  394. }
  395. function testSupportedReportSetPropertyNonCalendar() {
  396. $props = $this->server->getPropertiesForPath('/calendars/user1',array(
  397. '{DAV:}supported-report-set',
  398. ));
  399. $this->assertArrayHasKey(0,$props);
  400. $this->assertArrayHasKey(200,$props[0]);
  401. $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
  402. $prop = $props[0][200]['{DAV:}supported-report-set'];
  403. $this->assertInstanceOf('\\Sabre\\DAV\\Property\\SupportedReportSet', $prop);
  404. $value = array(
  405. '{DAV:}expand-property',
  406. '{DAV:}principal-property-search',
  407. '{DAV:}principal-search-property-set'
  408. );
  409. $this->assertEquals($value,$prop->getValue());
  410. }
  411. /**
  412. * @depends testSupportedReportSetPropertyNonCalendar
  413. */
  414. function testSupportedReportSetProperty() {
  415. $props = $this->server->getPropertiesForPath('/calendars/user1/UUID-123467',array(
  416. '{DAV:}supported-report-set',
  417. ));
  418. $this->assertArrayHasKey(0,$props);
  419. $this->assertArrayHasKey(200,$props[0]);
  420. $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
  421. $prop = $props[0][200]['{DAV:}supported-report-set'];
  422. $this->assertTrue($prop instanceof \Sabre\DAV\Property\SupportedReportSet);
  423. $value = array(
  424. '{urn:ietf:params:xml:ns:caldav}calendar-multiget',
  425. '{urn:ietf:params:xml:ns:caldav}calendar-query',
  426. '{urn:ietf:params:xml:ns:caldav}free-busy-query',
  427. '{DAV:}expand-property',
  428. '{DAV:}principal-property-search',
  429. '{DAV:}principal-search-property-set'
  430. );
  431. $this->assertEquals($value,$prop->getValue());
  432. }
  433. function testSupportedReportSetUserCalendars() {
  434. $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
  435. $props = $this->server->getPropertiesForPath('/calendars/user1',array(
  436. '{DAV:}supported-report-set',
  437. ));
  438. $this->assertArrayHasKey(0,$props);
  439. $this->assertArrayHasKey(200,$props[0]);
  440. $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]);
  441. $prop = $props[0][200]['{DAV:}supported-report-set'];
  442. $this->assertTrue($prop instanceof \Sabre\DAV\Property\SupportedReportSet);
  443. $value = array(
  444. '{DAV:}sync-collection',
  445. '{DAV:}expand-property',
  446. '{DAV:}principal-property-search',
  447. '{DAV:}principal-search-property-set',
  448. );
  449. $this->assertEquals($value,$prop->getValue());
  450. }
  451. /**
  452. * @depends testSupportedReportSetProperty
  453. */
  454. function testCalendarMultiGetReport() {
  455. $body =
  456. '<?xml version="1.0"?>' .
  457. '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  458. '<d:prop>' .
  459. ' <c:calendar-data />' .
  460. ' <d:getetag />' .
  461. '</d:prop>' .
  462. '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
  463. '</c:calendar-multiget>';
  464. $request = HTTP\Request::createFromServerArray(array(
  465. 'REQUEST_METHOD' => 'REPORT',
  466. 'REQUEST_URI' => '/calendars/user1',
  467. 'HTTP_DEPTH' => '1',
  468. ));
  469. $request->setBody($body);
  470. $this->server->httpRequest = $request;
  471. $this->server->exec();
  472. $this->assertEquals('207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
  473. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  474. $xml->registerXPathNamespace('d','urn:DAV');
  475. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  476. $check = array(
  477. '/d:multistatus',
  478. '/d:multistatus/d:response',
  479. '/d:multistatus/d:response/d:href',
  480. '/d:multistatus/d:response/d:propstat',
  481. '/d:multistatus/d:response/d:propstat/d:prop',
  482. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  483. '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data',
  484. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  485. );
  486. foreach($check as $v1=>$v2) {
  487. $xpath = is_int($v1)?$v2:$v1;
  488. $result = $xml->xpath($xpath);
  489. $this->assertEquals(1,count($result));
  490. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  491. }
  492. // The response object should have a reference to the Asia/Seoul
  493. // timezone.
  494. $this->assertTrue(strpos($this->response->body,'Asia/Seoul')!==false);
  495. }
  496. /**
  497. * @depends testCalendarMultiGetReport
  498. */
  499. function testCalendarMultiGetReportExpand() {
  500. $body =
  501. '<?xml version="1.0"?>' .
  502. '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  503. '<d:prop>' .
  504. ' <c:calendar-data>' .
  505. ' <c:expand start="20110101T000000Z" end="20111231T235959Z" />' .
  506. ' </c:calendar-data>' .
  507. ' <d:getetag />' .
  508. '</d:prop>' .
  509. '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
  510. '</c:calendar-multiget>';
  511. $request = HTTP\Request::createFromServerArray(array(
  512. 'REQUEST_METHOD' => 'REPORT',
  513. 'REQUEST_URI' => '/calendars/user1',
  514. 'HTTP_DEPTH' => '1',
  515. ));
  516. $request->setBody($body);
  517. $this->server->httpRequest = $request;
  518. $this->server->exec();
  519. $this->assertEquals('207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
  520. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  521. $xml->registerXPathNamespace('d','urn:DAV');
  522. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  523. $check = array(
  524. '/d:multistatus',
  525. '/d:multistatus/d:response',
  526. '/d:multistatus/d:response/d:href',
  527. '/d:multistatus/d:response/d:propstat',
  528. '/d:multistatus/d:response/d:propstat/d:prop',
  529. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  530. '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data',
  531. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  532. );
  533. foreach($check as $v1=>$v2) {
  534. $xpath = is_int($v1)?$v2:$v1;
  535. $result = $xml->xpath($xpath);
  536. $this->assertEquals(1,count($result));
  537. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  538. }
  539. // The response object should no longer hold references to timezones.
  540. $this->assertTrue(strpos($this->response->body,'Asia/Seoul')===false);
  541. }
  542. /**
  543. * @depends testSupportedReportSetProperty
  544. * @depends testCalendarMultiGetReport
  545. */
  546. function testCalendarQueryReport() {
  547. $body =
  548. '<?xml version="1.0"?>' .
  549. '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  550. '<d:prop>' .
  551. ' <c:calendar-data>' .
  552. ' <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
  553. ' </c:calendar-data>' .
  554. ' <d:getetag />' .
  555. '</d:prop>' .
  556. '<c:filter>' .
  557. ' <c:comp-filter name="VCALENDAR">' .
  558. ' <c:comp-filter name="VEVENT" />' .
  559. ' </c:comp-filter>' .
  560. '</c:filter>' .
  561. '</c:calendar-query>';
  562. $request = HTTP\Request::createFromServerArray(array(
  563. 'REQUEST_METHOD' => 'REPORT',
  564. 'REQUEST_URI' => '/calendars/user1/UUID-123467',
  565. 'HTTP_DEPTH' => '1',
  566. ));
  567. $request->setBody($body);
  568. $this->server->httpRequest = $request;
  569. $this->server->exec();
  570. $this->assertEquals('207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
  571. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  572. $xml->registerXPathNamespace('d','urn:DAV');
  573. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  574. $check = array(
  575. '/d:multistatus',
  576. '/d:multistatus/d:response',
  577. '/d:multistatus/d:response/d:href',
  578. '/d:multistatus/d:response/d:propstat',
  579. '/d:multistatus/d:response/d:propstat/d:prop',
  580. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  581. '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data',
  582. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  583. );
  584. foreach($check as $v1=>$v2) {
  585. $xpath = is_int($v1)?$v2:$v1;
  586. $result = $xml->xpath($xpath);
  587. $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body);
  588. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  589. }
  590. }
  591. /**
  592. * @depends testCalendarQueryReport
  593. */
  594. function testCalendarQueryReportNoCalData() {
  595. $body =
  596. '<?xml version="1.0"?>' .
  597. '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  598. '<d:prop>' .
  599. ' <d:getetag />' .
  600. '</d:prop>' .
  601. '<c:filter>' .
  602. ' <c:comp-filter name="VCALENDAR">' .
  603. ' <c:comp-filter name="VEVENT" />' .
  604. ' </c:comp-filter>' .
  605. '</c:filter>' .
  606. '</c:calendar-query>';
  607. $request = HTTP\Request::createFromServerArray(array(
  608. 'REQUEST_METHOD' => 'REPORT',
  609. 'REQUEST_URI' => '/calendars/user1//UUID-123467',
  610. 'HTTP_DEPTH' => '1',
  611. ));
  612. $request->setBody($body);
  613. $this->server->httpRequest = $request;
  614. $this->server->exec();
  615. $this->assertEquals('207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
  616. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  617. $xml->registerXPathNamespace('d','urn:DAV');
  618. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  619. $check = array(
  620. '/d:multistatus',
  621. '/d:multistatus/d:response',
  622. '/d:multistatus/d:response/d:href',
  623. '/d:multistatus/d:response/d:propstat',
  624. '/d:multistatus/d:response/d:propstat/d:prop',
  625. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  626. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  627. );
  628. foreach($check as $v1=>$v2) {
  629. $xpath = is_int($v1)?$v2:$v1;
  630. $result = $xml->xpath($xpath);
  631. $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body);
  632. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  633. }
  634. }
  635. /**
  636. * @depends testCalendarQueryReport
  637. */
  638. function testCalendarQueryReportNoFilters() {
  639. $body =
  640. '<?xml version="1.0"?>' .
  641. '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  642. '<d:prop>' .
  643. ' <c:calendar-data />' .
  644. ' <d:getetag />' .
  645. '</d:prop>' .
  646. '</c:calendar-query>';
  647. $request = HTTP\Request::createFromServerArray(array(
  648. 'REQUEST_METHOD' => 'REPORT',
  649. 'REQUEST_URI' => '/calendars/user1//UUID-123467',
  650. ));
  651. $request->setBody($body);
  652. $this->server->httpRequest = $request;
  653. $this->server->exec();
  654. $this->assertEquals('400 Bad request',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
  655. }
  656. /**
  657. * @depends testSupportedReportSetProperty
  658. * @depends testCalendarMultiGetReport
  659. */
  660. function testCalendarQueryReport1Object() {
  661. $body =
  662. '<?xml version="1.0"?>' .
  663. '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  664. '<d:prop>' .
  665. ' <c:calendar-data>' .
  666. ' <c:expand start="20000101T000000Z" end="20101231T235959Z" />' .
  667. ' </c:calendar-data>' .
  668. ' <d:getetag />' .
  669. '</d:prop>' .
  670. '<c:filter>' .
  671. ' <c:comp-filter name="VCALENDAR">' .
  672. ' <c:comp-filter name="VEVENT" />' .
  673. ' </c:comp-filter>' .
  674. '</c:filter>' .
  675. '</c:calendar-query>';
  676. $request = HTTP\Request::createFromServerArray(array(
  677. 'REQUEST_METHOD' => 'REPORT',
  678. 'REQUEST_URI' => '/calendars/user1/UUID-123467/UUID-2345',
  679. 'HTTP_DEPTH' => '0',
  680. ));
  681. $request->setBody($body);
  682. $this->server->httpRequest = $request;
  683. $this->server->exec();
  684. $this->assertEquals('207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
  685. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  686. $xml->registerXPathNamespace('d','urn:DAV');
  687. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  688. $check = array(
  689. '/d:multistatus',
  690. '/d:multistatus/d:response',
  691. '/d:multistatus/d:response/d:href',
  692. '/d:multistatus/d:response/d:propstat',
  693. '/d:multistatus/d:response/d:propstat/d:prop',
  694. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  695. '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data',
  696. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  697. );
  698. foreach($check as $v1=>$v2) {
  699. $xpath = is_int($v1)?$v2:$v1;
  700. $result = $xml->xpath($xpath);
  701. $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body);
  702. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  703. }
  704. }
  705. /**
  706. * @depends testSupportedReportSetProperty
  707. * @depends testCalendarMultiGetReport
  708. */
  709. function testCalendarQueryReport1ObjectNoCalData() {
  710. $body =
  711. '<?xml version="1.0"?>' .
  712. '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  713. '<d:prop>' .
  714. ' <d:getetag />' .
  715. '</d:prop>' .
  716. '<c:filter>' .
  717. ' <c:comp-filter name="VCALENDAR">' .
  718. ' <c:comp-filter name="VEVENT" />' .
  719. ' </c:comp-filter>' .
  720. '</c:filter>' .
  721. '</c:calendar-query>';
  722. $request = HTTP\Request::createFromServerArray(array(
  723. 'REQUEST_METHOD' => 'REPORT',
  724. 'REQUEST_URI' => '/calendars/user1/UUID-123467/UUID-2345',
  725. 'HTTP_DEPTH' => '0',
  726. ));
  727. $request->setBody($body);
  728. $this->server->httpRequest = $request;
  729. $this->server->exec();
  730. $this->assertEquals('207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
  731. $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body));
  732. $xml->registerXPathNamespace('d','urn:DAV');
  733. $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
  734. $check = array(
  735. '/d:multistatus',
  736. '/d:multistatus/d:response',
  737. '/d:multistatus/d:response/d:href',
  738. '/d:multistatus/d:response/d:propstat',
  739. '/d:multistatus/d:response/d:propstat/d:prop',
  740. '/d:multistatus/d:response/d:propstat/d:prop/d:getetag',
  741. '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK',
  742. );
  743. foreach($check as $v1=>$v2) {
  744. $xpath = is_int($v1)?$v2:$v1;
  745. $result = $xml->xpath($xpath);
  746. $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body);
  747. if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]);
  748. }
  749. }
  750. function testHTMLActionsPanel() {
  751. $output = '';
  752. $r = $this->server->emit('onHTMLActionsPanel', [$this->server->tree->getNodeForPath('calendars/user1'), &$output]);
  753. $this->assertFalse($r);
  754. $this->assertTrue(!!strpos($output,'Display name'));
  755. }
  756. function testBrowserPostAction() {
  757. $r = $this->server->emit('onBrowserPostAction', ['calendars/user1', 'mkcalendar', [
  758. 'name' => 'NEWCALENDAR',
  759. '{DAV:}displayname' => 'foo',
  760. ]]);
  761. $this->assertFalse($r);
  762. $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
  763. $this->assertEquals(3, count($calendars));
  764. $newCalendar = null;
  765. foreach($calendars as $calendar) {
  766. if ($calendar['uri'] === 'NEWCALENDAR') {
  767. $newCalendar = $calendar;
  768. break;
  769. }
  770. }
  771. if (!$newCalendar)
  772. $this->fail('Could not find newly created calendar');
  773. }
  774. /**
  775. * @depends testCalendarMultiGetReport
  776. */
  777. function testCalendarMultiGetReportNoEnd() {
  778. $body =
  779. '<?xml version="1.0"?>' .
  780. '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  781. '<d:prop>' .
  782. ' <c:calendar-data>' .
  783. ' <c:expand start="20110101T000000Z" />' .
  784. ' </c:calendar-data>' .
  785. ' <d:getetag />' .
  786. '</d:prop>' .
  787. '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
  788. '</c:calendar-multiget>';
  789. $request = HTTP\Request::createFromServerArray(array(
  790. 'REQUEST_METHOD' => 'REPORT',
  791. 'REQUEST_URI' => '/calendars/user1',
  792. 'HTTP_DEPTH' => '1',
  793. ));
  794. $request->setBody($body);
  795. $this->server->httpRequest = $request;
  796. $this->server->exec();
  797. $this->assertEquals('400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
  798. }
  799. /**
  800. * @depends testCalendarMultiGetReport
  801. */
  802. function testCalendarMultiGetReportNoStart() {
  803. $body =
  804. '<?xml version="1.0"?>' .
  805. '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  806. '<d:prop>' .
  807. ' <c:calendar-data>' .
  808. ' <c:expand end="20110101T000000Z" />' .
  809. ' </c:calendar-data>' .
  810. ' <d:getetag />' .
  811. '</d:prop>' .
  812. '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
  813. '</c:calendar-multiget>';
  814. $request = HTTP\Request::createFromServerArray(array(
  815. 'REQUEST_METHOD' => 'REPORT',
  816. 'REQUEST_URI' => '/calendars/user1',
  817. 'HTTP_DEPTH' => '1',
  818. ));
  819. $request->setBody($body);
  820. $this->server->httpRequest = $request;
  821. $this->server->exec();
  822. $this->assertEquals('400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
  823. }
  824. /**
  825. * @depends testCalendarMultiGetReport
  826. */
  827. function testCalendarMultiGetReportEndBeforeStart() {
  828. $body =
  829. '<?xml version="1.0"?>' .
  830. '<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' .
  831. '<d:prop>' .
  832. ' <c:calendar-data>' .
  833. ' <c:expand start="20200101T000000Z" end="20110101T000000Z" />' .
  834. ' </c:calendar-data>' .
  835. ' <d:getetag />' .
  836. '</d:prop>' .
  837. '<d:href>/calendars/user1/UUID-123467/UUID-2345</d:href>' .
  838. '</c:calendar-multiget>';
  839. $request = HTTP\Request::createFromServerArray(array(
  840. 'REQUEST_METHOD' => 'REPORT',
  841. 'REQUEST_URI' => '/calendars/user1',
  842. 'HTTP_DEPTH' => '1',
  843. ));
  844. $request->setBody($body);
  845. $this->server->httpRequest = $request;
  846. $this->server->exec();
  847. $this->assertEquals('400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
  848. }
  849. function testNotificationProperties() {
  850. $request = array(
  851. '{' . Plugin::NS_CALENDARSERVER . '}notificationtype',
  852. );
  853. $result = array();
  854. $notification = new Notifications\Node(
  855. $this->caldavBackend,
  856. 'principals/user1',
  857. new Notifications\Notification\SystemStatus('foo','"1"')
  858. );
  859. $this->plugin->beforeGetProperties('foo', $notification, $request, $result);
  860. $this->assertEquals(
  861. array(
  862. 200 => array(
  863. '{' . Plugin::NS_CALENDARSERVER . '}notificationtype' => $notification->getNotificationType()
  864. )
  865. ), $result);
  866. }
  867. function testNotificationGet() {
  868. $notification = new Notifications\Node(
  869. $this->caldavBackend,
  870. 'principals/user1',
  871. new Notifications\Notification\SystemStatus('foo','"1"')
  872. );
  873. $server = new DAV\Server(array($notification));
  874. $caldav = new Plugin();
  875. $server->httpRequest = HTTP\Request::createFromServerArray(array(
  876. 'REQUEST_URI' => '/foo.xml',
  877. ));
  878. $httpResponse = new HTTP\ResponseMock();
  879. $server->httpResponse = $httpResponse;
  880. $server->addPlugin($caldav);
  881. $caldav->httpGet($server->httpRequest, $server->httpResponse);
  882. $this->assertEquals('200 OK', $httpResponse->status);
  883. $this->assertEquals(array(
  884. 'Content-Type' => 'application/xml',
  885. 'ETag' => '"1"',
  886. ), $httpResponse->headers);
  887. $expected =
  888. '<?xml version="1.0" encoding="UTF-8"?>
  889. <cs:notification xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
  890. <cs:systemstatus type="high"/>
  891. </cs:notification>
  892. ';
  893. $this->assertEquals($expected, $httpResponse->body);
  894. }
  895. function testGETPassthrough() {
  896. $server = new DAV\Server();
  897. $caldav = new Plugin();
  898. $httpResponse = new HTTP\ResponseMock();
  899. $server->httpResponse = $httpResponse;
  900. $server->addPlugin($caldav);
  901. $this->assertNull($caldav->httpGet(new HTTP\Request('GET','/foozz'), $server->httpResponse));
  902. }
  903. }