test_base.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. # This file is part of Radicale Server - Calendar Server
  2. # Copyright © 2012-2016 Guillaume Ayoub
  3. #
  4. # This library is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  16. """
  17. Radicale tests with simple requests.
  18. """
  19. import logging
  20. import posixpath
  21. import shutil
  22. import tempfile
  23. from radicale import Application, config
  24. from . import BaseTest
  25. from .helpers import get_file_content
  26. class BaseRequestsMixIn:
  27. """Tests with simple requests."""
  28. def test_root(self):
  29. """GET request at "/"."""
  30. status, headers, answer = self.request("GET", "/")
  31. assert status == 200
  32. assert "Radicale works!" in answer
  33. # Test the creation of the collection
  34. self.request("MKCOL", "/calendar.ics/")
  35. self.request(
  36. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  37. status, headers, answer = self.request("GET", "/calendar.ics/")
  38. assert "BEGIN:VCALENDAR" in answer
  39. assert "END:VCALENDAR" in answer
  40. def test_add_event(self):
  41. """Add an event."""
  42. self.request("MKCOL", "/calendar.ics/")
  43. self.request(
  44. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  45. event = get_file_content("event1.ics")
  46. path = "/calendar.ics/event1.ics"
  47. status, headers, answer = self.request("PUT", path, event)
  48. assert status == 201
  49. status, headers, answer = self.request("GET", path)
  50. assert "ETag" in headers.keys()
  51. assert status == 200
  52. assert "VEVENT" in answer
  53. assert "Event" in answer
  54. assert "UID:event" in answer
  55. def test_add_todo(self):
  56. """Add a todo."""
  57. self.request("MKCOL", "/calendar.ics/")
  58. self.request(
  59. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  60. todo = get_file_content("todo1.ics")
  61. path = "/calendar.ics/todo1.ics"
  62. status, headers, answer = self.request("PUT", path, todo)
  63. assert status == 201
  64. status, headers, answer = self.request("GET", path)
  65. assert "ETag" in headers.keys()
  66. assert "VTODO" in answer
  67. assert "Todo" in answer
  68. assert "UID:todo" in answer
  69. def test_update(self):
  70. """Update an event."""
  71. self.request("MKCOL", "/calendar.ics/")
  72. self.request(
  73. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  74. event = get_file_content("event1.ics")
  75. path = "/calendar.ics/event1.ics"
  76. status, headers, answer = self.request("PUT", path, event)
  77. assert status == 201
  78. status, headers, answer = self.request("GET", path)
  79. assert "ETag" in headers.keys()
  80. assert status == 200
  81. assert "VEVENT" in answer
  82. assert "Event" in answer
  83. assert "UID:event" in answer
  84. assert "DTSTART;TZID=Europe/Paris:20130901T180000" in answer
  85. assert "DTEND;TZID=Europe/Paris:20130901T190000" in answer
  86. # Then we send another PUT request
  87. event = get_file_content("event1-prime.ics")
  88. status, headers, answer = self.request("PUT", path, event)
  89. assert status == 201
  90. status, headers, answer = self.request("GET", "/calendar.ics/")
  91. assert answer.count("BEGIN:VEVENT") == 1
  92. status, headers, answer = self.request("GET", path)
  93. assert "ETag" in headers.keys()
  94. assert status == 200
  95. assert "VEVENT" in answer
  96. assert "Event" in answer
  97. assert "UID:event" in answer
  98. assert "DTSTART;TZID=Europe/Paris:20130901T180000" not in answer
  99. assert "DTEND;TZID=Europe/Paris:20130901T190000" not in answer
  100. assert "DTSTART;TZID=Europe/Paris:20140901T180000" in answer
  101. assert "DTEND;TZID=Europe/Paris:20140901T210000" in answer
  102. def test_put_whole_collection(self):
  103. """Create and overwrite a whole collection."""
  104. event = get_file_content("event1.ics")
  105. status, headers, answer = self.request("PUT", "/calendar.ics/", event)
  106. assert status == 201
  107. status, headers, answer = self.request(
  108. "PUT", "/calendar.ics/event1.ics", event)
  109. assert status == 201
  110. # Overwrite
  111. status, headers, answer = self.request("PUT", "/calendar.ics/", event)
  112. assert status == 201
  113. status, headers, answer = self.request(
  114. "GET", "/calendar.ics/event1.ics")
  115. assert status == 404
  116. def test_delete(self):
  117. """Delete an event."""
  118. self.request("MKCOL", "/calendar.ics/")
  119. self.request(
  120. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  121. event = get_file_content("event1.ics")
  122. path = "/calendar.ics/event1.ics"
  123. status, headers, answer = self.request("PUT", path, event)
  124. # Then we send a DELETE request
  125. status, headers, answer = self.request("DELETE", path)
  126. assert status == 200
  127. assert "href>%s</" % path in answer
  128. status, headers, answer = self.request("GET", "/calendar.ics/")
  129. assert "VEVENT" not in answer
  130. def test_mkcalendar(self):
  131. """Make a calendar."""
  132. self.request("MKCALENDAR", "/calendar.ics/")
  133. status, headers, answer = self.request("GET", "/calendar.ics/")
  134. assert status == 200
  135. def test_move(self):
  136. """Move a item."""
  137. self.request("MKCALENDAR", "/calendar.ics/")
  138. event = get_file_content("event1.ics")
  139. path1 = "/calendar.ics/event1.ics"
  140. path2 = "/calendar.ics/event2.ics"
  141. status, headers, answer = self.request("PUT", path1, event)
  142. status, headers, answer = self.request(
  143. "MOVE", path1, HTTP_DESTINATION=path2, HTTP_HOST="")
  144. assert status == 201
  145. status, headers, answer = self.request("GET", path1)
  146. assert status == 404
  147. status, headers, answer = self.request("GET", path2)
  148. assert status == 200
  149. def test_head(self):
  150. status, headers, answer = self.request("HEAD", "/")
  151. assert status == 200
  152. def test_options(self):
  153. status, headers, answer = self.request("OPTIONS", "/")
  154. assert status == 200
  155. assert "DAV" in headers
  156. def test_delete_collection(self):
  157. """Delete a collection."""
  158. self.request("MKCOL", "/calendar.ics/")
  159. event = get_file_content("event1.ics")
  160. self.request("PUT", "/calendar.ics/event1.ics", event)
  161. status, headers, answer = self.request("DELETE", "/calendar.ics/")
  162. assert status == 200
  163. assert "href>/calendar.ics/</" in answer
  164. status, headers, answer = self.request("GET", "/calendar.ics/")
  165. assert status == 404
  166. def test_delete_root_collection(self):
  167. """Delete the root collection."""
  168. self.request("MKCOL", "/calendar.ics/")
  169. event = get_file_content("event1.ics")
  170. self.request("PUT", "/event1.ics", event)
  171. self.request("PUT", "/calendar.ics/event1.ics", event)
  172. status, headers, answer = self.request("DELETE", "/")
  173. assert status == 200
  174. assert "href>/</" in answer
  175. status, headers, answer = self.request("GET", "/calendar.ics/")
  176. assert status == 404
  177. status, headers, answer = self.request("GET", "/event1.ics")
  178. assert status == 404
  179. def test_propfind(self):
  180. calendar_path = "/calendar.ics/"
  181. self.request("MKCALENDAR", calendar_path)
  182. event = get_file_content("event1.ics")
  183. event_path = posixpath.join(calendar_path, "event.ics")
  184. self.request("PUT", event_path, event)
  185. status, headers, answer = self.request("PROPFIND", "/", HTTP_DEPTH="1")
  186. assert status == 207
  187. assert "href>/</" in answer
  188. assert "href>%s</" % calendar_path in answer
  189. status, headers, answer = self.request("PROPFIND", calendar_path, HTTP_DEPTH="1")
  190. assert status == 207
  191. assert "href>%s</" % calendar_path in answer
  192. assert "href>%s</" % event_path in answer
  193. def test_multiple_events_with_same_uid(self):
  194. """Add two events with the same UID."""
  195. self.request("MKCOL", "/calendar.ics/")
  196. self.request("PUT", "/calendar.ics/", get_file_content("event2.ics"))
  197. status, headers, answer = self.request(
  198. "REPORT", "/calendar.ics/",
  199. """<?xml version="1.0" encoding="utf-8" ?>
  200. <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
  201. <D:prop xmlns:D="DAV:"><D:getetag/></D:prop>
  202. </C:calendar-query>""")
  203. assert answer.count("<getetag>") == 1
  204. status, headers, answer = self.request("GET", "/calendar.ics/")
  205. assert answer.count("BEGIN:VEVENT") == 2
  206. def _test_filter(self, filters, kind="event", items=1):
  207. filters_text = "".join(
  208. "<C:filter>%s</C:filter>" % filter_ for filter_ in filters)
  209. self.request("MKCOL", "/calendar.ics/")
  210. self.request(
  211. "PUT", "/calendar.ics/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  212. for i in range(items):
  213. filename = "{}{}.ics".format(kind, i + 1)
  214. event = get_file_content(filename)
  215. self.request("PUT", "/calendar.ics/{}".format(filename), event)
  216. status, headers, answer = self.request(
  217. "REPORT", "/calendar.ics",
  218. """<?xml version="1.0" encoding="utf-8" ?>
  219. <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
  220. <D:prop xmlns:D="DAV:">
  221. <D:getetag/>
  222. </D:prop>
  223. %s
  224. </C:calendar-query>""" % filters_text)
  225. return answer
  226. def test_calendar_tag_filter(self):
  227. """Report request with tag-based filter on calendar."""
  228. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  229. <C:comp-filter name="VCALENDAR"></C:comp-filter>"""])
  230. def test_item_tag_filter(self):
  231. """Report request with tag-based filter on an item."""
  232. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  233. <C:comp-filter name="VCALENDAR">
  234. <C:comp-filter name="VEVENT"></C:comp-filter>
  235. </C:comp-filter>"""])
  236. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  237. <C:comp-filter name="VCALENDAR">
  238. <C:comp-filter name="VTODO"></C:comp-filter>
  239. </C:comp-filter>"""])
  240. def test_item_not_tag_filter(self):
  241. """Report request with tag-based is-not filter on an item."""
  242. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  243. <C:comp-filter name="VCALENDAR">
  244. <C:comp-filter name="VEVENT">
  245. <C:is-not-defined />
  246. </C:comp-filter>
  247. </C:comp-filter>"""])
  248. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  249. <C:comp-filter name="VCALENDAR">
  250. <C:comp-filter name="VTODO">
  251. <C:is-not-defined />
  252. </C:comp-filter>
  253. </C:comp-filter>"""])
  254. def test_item_prop_filter(self):
  255. """Report request with prop-based filter on an item."""
  256. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  257. <C:comp-filter name="VCALENDAR">
  258. <C:comp-filter name="VEVENT">
  259. <C:prop-filter name="SUMMARY"></C:prop-filter>
  260. </C:comp-filter>
  261. </C:comp-filter>"""])
  262. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  263. <C:comp-filter name="VCALENDAR">
  264. <C:comp-filter name="VEVENT">
  265. <C:prop-filter name="UNKNOWN"></C:prop-filter>
  266. </C:comp-filter>
  267. </C:comp-filter>"""])
  268. def test_item_not_prop_filter(self):
  269. """Report request with prop-based is-not filter on an item."""
  270. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  271. <C:comp-filter name="VCALENDAR">
  272. <C:comp-filter name="VEVENT">
  273. <C:prop-filter name="SUMMARY">
  274. <C:is-not-defined />
  275. </C:prop-filter>
  276. </C:comp-filter>
  277. </C:comp-filter>"""])
  278. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  279. <C:comp-filter name="VCALENDAR">
  280. <C:comp-filter name="VEVENT">
  281. <C:prop-filter name="UNKNOWN">
  282. <C:is-not-defined />
  283. </C:prop-filter>
  284. </C:comp-filter>
  285. </C:comp-filter>"""])
  286. def test_mutiple_filters(self):
  287. """Report request with multiple filters on an item."""
  288. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  289. <C:comp-filter name="VCALENDAR">
  290. <C:comp-filter name="VEVENT">
  291. <C:prop-filter name="SUMMARY">
  292. <C:is-not-defined />
  293. </C:prop-filter>
  294. </C:comp-filter>
  295. </C:comp-filter>""", """
  296. <C:comp-filter name="VCALENDAR">
  297. <C:comp-filter name="VEVENT">
  298. <C:prop-filter name="UNKNOWN">
  299. <C:is-not-defined />
  300. </C:prop-filter>
  301. </C:comp-filter>
  302. </C:comp-filter>"""])
  303. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  304. <C:comp-filter name="VCALENDAR">
  305. <C:comp-filter name="VEVENT">
  306. <C:prop-filter name="SUMMARY"></C:prop-filter>
  307. </C:comp-filter>
  308. </C:comp-filter>""", """
  309. <C:comp-filter name="VCALENDAR">
  310. <C:comp-filter name="VEVENT">
  311. <C:prop-filter name="UNKNOWN">
  312. <C:is-not-defined />
  313. </C:prop-filter>
  314. </C:comp-filter>
  315. </C:comp-filter>"""])
  316. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  317. <C:comp-filter name="VCALENDAR">
  318. <C:comp-filter name="VEVENT">
  319. <C:prop-filter name="SUMMARY"></C:prop-filter>
  320. <C:prop-filter name="UNKNOWN">
  321. <C:is-not-defined />
  322. </C:prop-filter>
  323. </C:comp-filter>
  324. </C:comp-filter>"""])
  325. def test_text_match_filter(self):
  326. """Report request with text-match filter on calendar."""
  327. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  328. <C:comp-filter name="VCALENDAR">
  329. <C:comp-filter name="VEVENT">
  330. <C:prop-filter name="SUMMARY">
  331. <C:text-match>event</C:text-match>
  332. </C:prop-filter>
  333. </C:comp-filter>
  334. </C:comp-filter>"""])
  335. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  336. <C:comp-filter name="VCALENDAR">
  337. <C:comp-filter name="VEVENT">
  338. <C:prop-filter name="UNKNOWN">
  339. <C:text-match>event</C:text-match>
  340. </C:prop-filter>
  341. </C:comp-filter>
  342. </C:comp-filter>"""])
  343. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  344. <C:comp-filter name="VCALENDAR">
  345. <C:comp-filter name="VEVENT">
  346. <C:prop-filter name="SUMMARY">
  347. <C:text-match>unknown</C:text-match>
  348. </C:prop-filter>
  349. </C:comp-filter>
  350. </C:comp-filter>"""])
  351. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  352. <C:comp-filter name="VCALENDAR">
  353. <C:comp-filter name="VEVENT">
  354. <C:prop-filter name="SUMMARY">
  355. <C:text-match negate-condition="yes">event</C:text-match>
  356. </C:prop-filter>
  357. </C:comp-filter>
  358. </C:comp-filter>"""])
  359. def test_param_filter(self):
  360. """Report request with param-filter on calendar."""
  361. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  362. <C:comp-filter name="VCALENDAR">
  363. <C:comp-filter name="VEVENT">
  364. <C:prop-filter name="ATTENDEE">
  365. <C:param-filter name="PARTSTAT">
  366. <C:text-match collation="i;ascii-casemap"
  367. >ACCEPTED</C:text-match>
  368. </C:param-filter>
  369. </C:prop-filter>
  370. </C:comp-filter>
  371. </C:comp-filter>"""])
  372. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  373. <C:comp-filter name="VCALENDAR">
  374. <C:comp-filter name="VEVENT">
  375. <C:prop-filter name="ATTENDEE">
  376. <C:param-filter name="PARTSTAT">
  377. <C:text-match collation="i;ascii-casemap"
  378. >UNKNOWN</C:text-match>
  379. </C:param-filter>
  380. </C:prop-filter>
  381. </C:comp-filter>
  382. </C:comp-filter>"""])
  383. assert "href>/calendar.ics/event1.ics</" not in self._test_filter(["""
  384. <C:comp-filter name="VCALENDAR">
  385. <C:comp-filter name="VEVENT">
  386. <C:prop-filter name="ATTENDEE">
  387. <C:param-filter name="PARTSTAT">
  388. <C:is-not-defined />
  389. </C:param-filter>
  390. </C:prop-filter>
  391. </C:comp-filter>
  392. </C:comp-filter>"""])
  393. assert "href>/calendar.ics/event1.ics</" in self._test_filter(["""
  394. <C:comp-filter name="VCALENDAR">
  395. <C:comp-filter name="VEVENT">
  396. <C:prop-filter name="ATTENDEE">
  397. <C:param-filter name="UNKNOWN">
  398. <C:is-not-defined />
  399. </C:param-filter>
  400. </C:prop-filter>
  401. </C:comp-filter>
  402. </C:comp-filter>"""])
  403. def test_time_range_filter_events(self):
  404. """Report request with time-range filter on events."""
  405. answer = self._test_filter(["""
  406. <C:comp-filter name="VCALENDAR">
  407. <C:comp-filter name="VEVENT">
  408. <C:time-range start="20130801T000000Z" end="20131001T000000Z"/>
  409. </C:comp-filter>
  410. </C:comp-filter>"""], "event", items=5)
  411. assert "href>/calendar.ics/event1.ics</" in answer
  412. assert "href>/calendar.ics/event2.ics</" in answer
  413. assert "href>/calendar.ics/event3.ics</" in answer
  414. assert "href>/calendar.ics/event4.ics</" in answer
  415. assert "href>/calendar.ics/event5.ics</" in answer
  416. answer = self._test_filter(["""
  417. <C:comp-filter name="VCALENDAR">
  418. <C:comp-filter name="VEVENT">
  419. <C:prop-filter name="ATTENDEE">
  420. <C:param-filter name="PARTSTAT">
  421. <C:is-not-defined />
  422. </C:param-filter>
  423. </C:prop-filter>
  424. <C:time-range start="20130801T000000Z" end="20131001T000000Z"/>
  425. </C:comp-filter>
  426. </C:comp-filter>"""], items=5)
  427. assert "href>/calendar.ics/event1.ics</" not in answer
  428. assert "href>/calendar.ics/event2.ics</" not in answer
  429. assert "href>/calendar.ics/event3.ics</" not in answer
  430. assert "href>/calendar.ics/event4.ics</" not in answer
  431. assert "href>/calendar.ics/event5.ics</" not in answer
  432. answer = self._test_filter(["""
  433. <C:comp-filter name="VCALENDAR">
  434. <C:comp-filter name="VEVENT">
  435. <C:time-range start="20130902T000000Z" end="20131001T000000Z"/>
  436. </C:comp-filter>
  437. </C:comp-filter>"""], items=5)
  438. assert "href>/calendar.ics/event1.ics</" not in answer
  439. assert "href>/calendar.ics/event2.ics</" in answer
  440. assert "href>/calendar.ics/event3.ics</" in answer
  441. assert "href>/calendar.ics/event4.ics</" in answer
  442. assert "href>/calendar.ics/event5.ics</" in answer
  443. answer = self._test_filter(["""
  444. <C:comp-filter name="VCALENDAR">
  445. <C:comp-filter name="VEVENT">
  446. <C:time-range start="20130903T000000Z" end="20130908T000000Z"/>
  447. </C:comp-filter>
  448. </C:comp-filter>"""], items=5)
  449. assert "href>/calendar.ics/event1.ics</" not in answer
  450. assert "href>/calendar.ics/event2.ics</" not in answer
  451. assert "href>/calendar.ics/event3.ics</" in answer
  452. assert "href>/calendar.ics/event4.ics</" in answer
  453. assert "href>/calendar.ics/event5.ics</" in answer
  454. answer = self._test_filter(["""
  455. <C:comp-filter name="VCALENDAR">
  456. <C:comp-filter name="VEVENT">
  457. <C:time-range start="20130903T000000Z" end="20130904T000000Z"/>
  458. </C:comp-filter>
  459. </C:comp-filter>"""], items=5)
  460. assert "href>/calendar.ics/event1.ics</" not in answer
  461. assert "href>/calendar.ics/event2.ics</" not in answer
  462. assert "href>/calendar.ics/event3.ics</" in answer
  463. assert "href>/calendar.ics/event4.ics</" not in answer
  464. assert "href>/calendar.ics/event5.ics</" not in answer
  465. answer = self._test_filter(["""
  466. <C:comp-filter name="VCALENDAR">
  467. <C:comp-filter name="VEVENT">
  468. <C:time-range start="20130805T000000Z" end="20130810T000000Z"/>
  469. </C:comp-filter>
  470. </C:comp-filter>"""], items=5)
  471. assert "href>/calendar.ics/event1.ics</" not in answer
  472. assert "href>/calendar.ics/event2.ics</" not in answer
  473. assert "href>/calendar.ics/event3.ics</" not in answer
  474. assert "href>/calendar.ics/event4.ics</" not in answer
  475. assert "href>/calendar.ics/event5.ics</" not in answer
  476. def test_time_range_filter_events_rrule(self):
  477. """Report request with time-range filter on events with rrules."""
  478. answer = self._test_filter(["""
  479. <C:comp-filter name="VCALENDAR">
  480. <C:comp-filter name="VEVENT">
  481. <C:time-range start="20130801T000000Z" end="20131001T000000Z"/>
  482. </C:comp-filter>
  483. </C:comp-filter>"""], "event", items=2)
  484. assert "href>/calendar.ics/event1.ics</" in answer
  485. assert "href>/calendar.ics/event2.ics</" in answer
  486. answer = self._test_filter(["""
  487. <C:comp-filter name="VCALENDAR">
  488. <C:comp-filter name="VEVENT">
  489. <C:time-range start="20140801T000000Z" end="20141001T000000Z"/>
  490. </C:comp-filter>
  491. </C:comp-filter>"""], "event", items=2)
  492. assert "href>/calendar.ics/event1.ics</" not in answer
  493. assert "href>/calendar.ics/event2.ics</" in answer
  494. answer = self._test_filter(["""
  495. <C:comp-filter name="VCALENDAR">
  496. <C:comp-filter name="VEVENT">
  497. <C:time-range start="20120801T000000Z" end="20121001T000000Z"/>
  498. </C:comp-filter>
  499. </C:comp-filter>"""], "event", items=2)
  500. assert "href>/calendar.ics/event1.ics</" not in answer
  501. assert "href>/calendar.ics/event2.ics</" not in answer
  502. answer = self._test_filter(["""
  503. <C:comp-filter name="VCALENDAR">
  504. <C:comp-filter name="VEVENT">
  505. <C:time-range start="20130903T000000Z" end="20130907T000000Z"/>
  506. </C:comp-filter>
  507. </C:comp-filter>"""], "event", items=2)
  508. assert "href>/calendar.ics/event1.ics</" not in answer
  509. assert "href>/calendar.ics/event2.ics</" not in answer
  510. def test_time_range_filter_todos(self):
  511. """Report request with time-range filter on todos."""
  512. answer = self._test_filter(["""
  513. <C:comp-filter name="VCALENDAR">
  514. <C:comp-filter name="VTODO">
  515. <C:time-range start="20130801T000000Z" end="20131001T000000Z"/>
  516. </C:comp-filter>
  517. </C:comp-filter>"""], "todo", items=8)
  518. assert "href>/calendar.ics/todo1.ics</" in answer
  519. assert "href>/calendar.ics/todo2.ics</" in answer
  520. assert "href>/calendar.ics/todo3.ics</" in answer
  521. assert "href>/calendar.ics/todo4.ics</" in answer
  522. assert "href>/calendar.ics/todo5.ics</" in answer
  523. assert "href>/calendar.ics/todo6.ics</" in answer
  524. assert "href>/calendar.ics/todo7.ics</" in answer
  525. assert "href>/calendar.ics/todo8.ics</" in answer
  526. answer = self._test_filter(["""
  527. <C:comp-filter name="VCALENDAR">
  528. <C:comp-filter name="VTODO">
  529. <C:time-range start="20130901T160000Z" end="20130901T183000Z"/>
  530. </C:comp-filter>
  531. </C:comp-filter>"""], "todo", items=8)
  532. assert "href>/calendar.ics/todo1.ics</" not in answer
  533. assert "href>/calendar.ics/todo2.ics</" in answer
  534. assert "href>/calendar.ics/todo3.ics</" in answer
  535. assert "href>/calendar.ics/todo4.ics</" not in answer
  536. assert "href>/calendar.ics/todo5.ics</" not in answer
  537. assert "href>/calendar.ics/todo6.ics</" not in answer
  538. assert "href>/calendar.ics/todo7.ics</" in answer
  539. assert "href>/calendar.ics/todo8.ics</" in answer
  540. answer = self._test_filter(["""
  541. <C:comp-filter name="VCALENDAR">
  542. <C:comp-filter name="VTODO">
  543. <C:time-range start="20130903T160000Z" end="20130901T183000Z"/>
  544. </C:comp-filter>
  545. </C:comp-filter>"""], "todo", items=8)
  546. assert "href>/calendar.ics/todo2.ics</" not in answer
  547. answer = self._test_filter(["""
  548. <C:comp-filter name="VCALENDAR">
  549. <C:comp-filter name="VTODO">
  550. <C:time-range start="20130903T160000Z" end="20130901T173000Z"/>
  551. </C:comp-filter>
  552. </C:comp-filter>"""], "todo", items=8)
  553. assert "href>/calendar.ics/todo2.ics</" not in answer
  554. answer = self._test_filter(["""
  555. <C:comp-filter name="VCALENDAR">
  556. <C:comp-filter name="VTODO">
  557. <C:time-range start="20130903T160000Z" end="20130903T173000Z"/>
  558. </C:comp-filter>
  559. </C:comp-filter>"""], "todo", items=8)
  560. assert "href>/calendar.ics/todo3.ics</" not in answer
  561. answer = self._test_filter(["""
  562. <C:comp-filter name="VCALENDAR">
  563. <C:comp-filter name="VTODO">
  564. <C:time-range start="20130903T160000Z" end="20130803T203000Z"/>
  565. </C:comp-filter>
  566. </C:comp-filter>"""], "todo", items=8)
  567. assert "href>/calendar.ics/todo7.ics</" in answer
  568. def test_time_range_filter_todos_rrule(self):
  569. """Report request with time-range filter on todos with rrules."""
  570. answer = self._test_filter(["""
  571. <C:comp-filter name="VCALENDAR">
  572. <C:comp-filter name="VTODO">
  573. <C:time-range start="20130801T000000Z" end="20131001T000000Z"/>
  574. </C:comp-filter>
  575. </C:comp-filter>"""], "todo", items=2)
  576. assert "href>/calendar.ics/todo1.ics</" in answer
  577. assert "href>/calendar.ics/todo2.ics</" in answer
  578. answer = self._test_filter(["""
  579. <C:comp-filter name="VCALENDAR">
  580. <C:comp-filter name="VTODO">
  581. <C:time-range start="20140801T000000Z" end="20141001T000000Z"/>
  582. </C:comp-filter>
  583. </C:comp-filter>"""], "todo", items=2)
  584. assert "href>/calendar.ics/todo1.ics</" not in answer
  585. assert "href>/calendar.ics/todo2.ics</" in answer
  586. answer = self._test_filter(["""
  587. <C:comp-filter name="VCALENDAR">
  588. <C:comp-filter name="VTODO">
  589. <C:time-range start="20140902T000000Z" end="20140903T000000Z"/>
  590. </C:comp-filter>
  591. </C:comp-filter>"""], "todo", items=2)
  592. assert "href>/calendar.ics/todo1.ics</" not in answer
  593. assert "href>/calendar.ics/todo2.ics</" in answer
  594. answer = self._test_filter(["""
  595. <C:comp-filter name="VCALENDAR">
  596. <C:comp-filter name="VTODO">
  597. <C:time-range start="20140904T000000Z" end="20140914T000000Z"/>
  598. </C:comp-filter>
  599. </C:comp-filter>"""], "todo", items=2)
  600. assert "href>/calendar.ics/todo1.ics</" not in answer
  601. assert "href>/calendar.ics/todo2.ics</" not in answer
  602. def test_time_range_filter_journals(self):
  603. """Report request with time-range filter on journals."""
  604. answer = self._test_filter(["""
  605. <C:comp-filter name="VCALENDAR">
  606. <C:comp-filter name="VJOURNAL">
  607. <C:time-range start="19991229T000000Z" end="20000202T000000Z"/>
  608. </C:comp-filter>
  609. </C:comp-filter>"""], "journal", items=3)
  610. assert "href>/calendar.ics/journal1.ics</" not in answer
  611. assert "href>/calendar.ics/journal2.ics</" in answer
  612. assert "href>/calendar.ics/journal3.ics</" in answer
  613. answer = self._test_filter(["""
  614. <C:comp-filter name="VCALENDAR">
  615. <C:comp-filter name="VJOURNAL">
  616. <C:time-range start="19991229T000000Z" end="20000202T000000Z"/>
  617. </C:comp-filter>
  618. </C:comp-filter>"""], "journal", items=3)
  619. assert "href>/calendar.ics/journal1.ics</" not in answer
  620. assert "href>/calendar.ics/journal2.ics</" in answer
  621. assert "href>/calendar.ics/journal3.ics</" in answer
  622. answer = self._test_filter(["""
  623. <C:comp-filter name="VCALENDAR">
  624. <C:comp-filter name="VJOURNAL">
  625. <C:time-range start="19981229T000000Z" end="19991012T000000Z"/>
  626. </C:comp-filter>
  627. </C:comp-filter>"""], "journal", items=3)
  628. assert "href>/calendar.ics/journal1.ics</" not in answer
  629. assert "href>/calendar.ics/journal2.ics</" not in answer
  630. assert "href>/calendar.ics/journal3.ics</" not in answer
  631. answer = self._test_filter(["""
  632. <C:comp-filter name="VCALENDAR">
  633. <C:comp-filter name="VJOURNAL">
  634. <C:time-range start="20131229T000000Z" end="21520202T000000Z"/>
  635. </C:comp-filter>
  636. </C:comp-filter>"""], "journal", items=3)
  637. assert "href>/calendar.ics/journal1.ics</" not in answer
  638. assert "href>/calendar.ics/journal2.ics</" in answer
  639. assert "href>/calendar.ics/journal3.ics</" not in answer
  640. answer = self._test_filter(["""
  641. <C:comp-filter name="VCALENDAR">
  642. <C:comp-filter name="VJOURNAL">
  643. <C:time-range start="20000101T000000Z" end="20000202T000000Z"/>
  644. </C:comp-filter>
  645. </C:comp-filter>"""], "journal", items=3)
  646. assert "href>/calendar.ics/journal1.ics</" not in answer
  647. assert "href>/calendar.ics/journal2.ics</" in answer
  648. assert "href>/calendar.ics/journal3.ics</" in answer
  649. def test_time_range_filter_journals_rrule(self):
  650. """Report request with time-range filter on journals with rrules."""
  651. answer = self._test_filter(["""
  652. <C:comp-filter name="VCALENDAR">
  653. <C:comp-filter name="VJOURNAL">
  654. <C:time-range start="19991229T000000Z" end="20000202T000000Z"/>
  655. </C:comp-filter>
  656. </C:comp-filter>"""], "journal", items=2)
  657. assert "href>/calendar.ics/journal1.ics</" not in answer
  658. assert "href>/calendar.ics/journal2.ics</" in answer
  659. answer = self._test_filter(["""
  660. <C:comp-filter name="VCALENDAR">
  661. <C:comp-filter name="VJOURNAL">
  662. <C:time-range start="20051229T000000Z" end="20060202T000000Z"/>
  663. </C:comp-filter>
  664. </C:comp-filter>"""], "journal", items=2)
  665. assert "href>/calendar.ics/journal1.ics</" not in answer
  666. assert "href>/calendar.ics/journal2.ics</" in answer
  667. answer = self._test_filter(["""
  668. <C:comp-filter name="VCALENDAR">
  669. <C:comp-filter name="VJOURNAL">
  670. <C:time-range start="20060102T000000Z" end="20060202T000000Z"/>
  671. </C:comp-filter>
  672. </C:comp-filter>"""], "journal", items=2)
  673. assert "href>/calendar.ics/journal1.ics</" not in answer
  674. assert "href>/calendar.ics/journal2.ics</" not in answer
  675. class BaseFileSystemTest(BaseTest):
  676. """Base class for filesystem backend tests."""
  677. storage_type = None
  678. def setup(self):
  679. self.configuration = config.load()
  680. self.configuration.set("storage", "type", self.storage_type)
  681. self.logger = logging.getLogger("radicale_test")
  682. self.colpath = tempfile.mkdtemp()
  683. self.configuration.set("storage", "filesystem_folder", self.colpath)
  684. # Disable syncing to disk for better performance
  685. self.configuration.set("storage", "fsync", "False")
  686. self.application = Application(self.configuration, self.logger)
  687. def teardown(self):
  688. shutil.rmtree(self.colpath)
  689. class TestMultiFileSystem(BaseFileSystemTest, BaseRequestsMixIn):
  690. """Test BaseRequests on multifilesystem."""
  691. storage_type = "multifilesystem"
  692. class TestCustomStorageSystem(BaseFileSystemTest, BaseRequestsMixIn):
  693. """Test BaseRequests on custom backend."""
  694. storage_type = "tests.custom.storage"