PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/Sabre/CalDAV/PluginTest.php

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