44 "context"
55 "fmt"
66 "io"
7- "io/ioutil"
87 "net/http/httptest"
98 "strings"
109 "testing"
@@ -38,7 +37,7 @@ func TestPropFindSupportedCalendarComponent(t *testing.T) {
3837
3938 res := w .Result ()
4039 defer res .Body .Close ()
41- data , err := ioutil .ReadAll (res .Body )
40+ data , err := io .ReadAll (res .Body )
4241 if err != nil {
4342 t .Error (err )
4443 }
@@ -73,7 +72,7 @@ func TestPropFindRoot(t *testing.T) {
7372
7473 res := w .Result ()
7574 defer res .Body .Close ()
76- data , err := ioutil .ReadAll (res .Body )
75+ data , err := io .ReadAll (res .Body )
7776 if err != nil {
7877 t .Error (err )
7978 }
@@ -128,7 +127,7 @@ func TestMultiCalendarBackend(t *testing.T) {
128127
129128 res := w .Result ()
130129 defer res .Body .Close ()
131- data , err := ioutil .ReadAll (res .Body )
130+ data , err := io .ReadAll (res .Body )
132131 if err != nil {
133132 t .Error (err )
134133 }
@@ -147,7 +146,7 @@ func TestMultiCalendarBackend(t *testing.T) {
147146
148147 res = w .Result ()
149148 defer res .Body .Close ()
150- data , err = ioutil .ReadAll (res .Body )
149+ data , err = io .ReadAll (res .Body )
151150 if err != nil {
152151 t .Error (err )
153152 }
@@ -167,7 +166,7 @@ func TestMultiCalendarBackend(t *testing.T) {
167166
168167 res = w .Result ()
169168 defer res .Body .Close ()
170- data , err = ioutil .ReadAll (res .Body )
169+ data , err = io .ReadAll (res .Body )
171170 if err != nil {
172171 t .Error (err )
173172 }
@@ -177,6 +176,311 @@ func TestMultiCalendarBackend(t *testing.T) {
177176 }
178177}
179178
179+ var propFindAllProp = `
180+ <?xml version="1.0" encoding="utf-8" ?>
181+ <D:propfind xmlns:D="DAV:">
182+ <D:allprop/>
183+ </D:propfind>
184+ `
185+
186+ var reportTest1 = `
187+ <?xml version="1.0" encoding="utf-8"?>
188+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
189+ <D:prop xmlns:D="DAV:">
190+ <D:getetag/>
191+ <D:getcontenttype/>
192+ <D:getcontentlength/>
193+ <D:getlastmodified/>
194+ <C:calendar-data/>
195+ </D:prop>
196+ <C:filter>
197+ <C:comp-filter name="VCALENDAR">
198+ <C:comp-filter name="VEVENT"/>
199+ </C:comp-filter>
200+ </C:filter>
201+ </C:calendar-query>
202+ `
203+
204+ var propFindTest1 = `
205+ <?xml version="1.0" encoding="UTF-8"?>
206+ <A:propfind xmlns:A="DAV:">
207+ <A:prop>
208+ <B:calendar-home-set xmlns:B="urn:ietf:params:xml:ns:caldav"/>
209+ <B:calendar-user-address-set xmlns:B="urn:ietf:params:xml:ns:caldav"/>
210+ <B:max-attendees-per-instance xmlns:B="urn:ietf:params:xml:ns:caldav"/>
211+ <A:principal-collection-set/>
212+ <A:principal-URL/>
213+ <A:resource-id/>
214+ <A:supported-report-set/>
215+ <B:supported-calendar-component-set xmlns:B="urn:ietf:params:xml:ns:caldav"/>
216+ <B:max-resource-size xmlns:B="urn:ietf:params:xml:ns:caldav"/>
217+ <B:calendar-timezone xmlns:B="urn:ietf:params:xml:ns:caldav"/>
218+ <A:current-user-principal/>
219+ <A:displayname/>
220+ <B:calendar-description xmlns:B="urn:ietf:params:xml:ns:caldav"/>
221+ <B:calendar-data xmlns:B="urn:ietf:params:xml:ns:caldav"/>
222+ <A:resourcetype/>
223+ <A:getcontenttype/>
224+ <A:getetag/>
225+ </A:prop>
226+ </A:propfind>
227+ `
228+
229+ var calendarTestData1 = `
230+ BEGIN:VCALENDAR
231+ VERSION:2.0
232+ PRODID:-//Example Corp.//CalDAV Client//EN
233+ BEGIN:VTIMEZONE
234+ LAST-MODIFIED:20040110T032845Z
235+ TZID:US/Eastern
236+ BEGIN:DAYLIGHT
237+ DTSTART:20000404T020000
238+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
239+ TZNAME:EDT
240+ TZOFFSETFROM:-0500
241+ TZOFFSETTO:-0400
242+ END:DAYLIGHT
243+ BEGIN:STANDARD
244+ DTSTART:20001026T020000
245+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
246+ TZNAME:EST
247+ TZOFFSETFROM:-0400
248+ TZOFFSETTO:-0500
249+ END:STANDARD
250+ END:VTIMEZONE
251+ BEGIN:VEVENT
252+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:[email protected] 253+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:[email protected] 254+ DTSTAMP:20060206T001220Z
255+ DTSTART;TZID=US/Eastern:20060104T100000
256+ DURATION:PT1H
257+ LAST-MODIFIED:20060206T001330Z
258+ ORGANIZER:mailto:[email protected] 259+ SEQUENCE:1
260+ STATUS:TENTATIVE
261+ SUMMARY:Event #3
262+ 263+ 264+ END:VEVENT
265+ END:VCALENDAR
266+ `
267+
268+ func TestPropFindAllPropAndQuery (t * testing.T ) {
269+ calendar := Calendar {
270+ Description : "This is a description which SHOULD NOT be returned in allprop" ,
271+ Path : "/user/calendars/default/" ,
272+ SupportedComponentSet : []string {"VEVENT" , "VTODO" },
273+ }
274+ cal , err := ical .NewDecoder (strings .NewReader (calendarTestData1 )).Decode ()
275+ if err != nil {
276+ t .Fatal (err )
277+ }
278+ object := CalendarObject {
279+ Path : "/user/calendars/default/DC6C50A017428C5216A2F1CD.ics" ,
280+ Data : cal ,
281+ ETag : "191382932849" ,
282+ }
283+ handler := Handler {Backend : testBackend {
284+ calendars : []Calendar {calendar },
285+ objectMap : map [string ][]CalendarObject {
286+ calendar .Path : []CalendarObject {object },
287+ },
288+ }}
289+
290+ req := httptest .NewRequest ("PROPFIND" , "/user/calendars/default/" , strings .NewReader (propFindAllProp ))
291+ req .Header .Set ("Content-Type" , "application/xml" )
292+ req .Header .Set ("Depth" , "0" )
293+ w := httptest .NewRecorder ()
294+ handler .ServeHTTP (w , req )
295+
296+ res := w .Result ()
297+ defer res .Body .Close ()
298+ data , err := io .ReadAll (res .Body )
299+ if err != nil {
300+ t .Fatal (err )
301+ }
302+ resp := string (data )
303+ if ! strings .Contains (resp , "<resourcetype xmlns=\" DAV:\" >" ) {
304+ t .Fatalf ("want resourcetype prop in allprop" )
305+ } else if ! strings .Contains (resp , "<collection xmlns=\" DAV:\" >" ) {
306+ t .Fatalf ("want collection resourcetype" )
307+ } else if ! strings .Contains (resp , "<calendar xmlns=\" urn:ietf:params:xml:ns:caldav\" >" ) {
308+ t .Fatalf ("expect calendar resourcetype" )
309+ } else if strings .Contains (resp , "<calendar-description xmlns=\" urn:ietf:params:xml:ns:caldav\" >" ) {
310+ t .Fatalf ("do not want calendar-description in allprop" )
311+ } else if strings .Contains (resp , "DC6C50A017428C5216A2F1CD.ics" ) {
312+ t .Fatalf ("do not want children if Depth: 0" )
313+ }
314+
315+ req = httptest .NewRequest ("PROPFIND" , "/user/calendars/default/" , strings .NewReader (propFindAllProp ))
316+ req .Header .Set ("Content-Type" , "application/xml" )
317+ req .Header .Set ("Depth" , "1" )
318+ w = httptest .NewRecorder ()
319+ handler .ServeHTTP (w , req )
320+
321+ res = w .Result ()
322+ defer res .Body .Close ()
323+ data , err = io .ReadAll (res .Body )
324+ if err != nil {
325+ t .Fatal (err )
326+ }
327+ resp = string (data )
328+ if ! strings .Contains (resp , fmt .Sprintf ("<href>%s</href>" , object .Path )) {
329+ t .Fatalf ("want child href in allprop" )
330+ } else if ! strings .Contains (resp , object .ETag ) {
331+ t .Fatalf ("want child ETag in allprop" )
332+ } else if ! strings .Contains (resp , "<getcontenttype xmlns=\" DAV:\" >text/calendar</getcontenttype>" ) {
333+ t .Fatalf ("want child getcontenttype in allprop" )
334+ } else if strings .Contains (resp , "<calendar-data xmlns=\" urn:ietf:params:xml:ns:caldav\" >" ) {
335+ t .Fatalf ("do not want calendar-data in allprop" )
336+ }
337+
338+ req = httptest .NewRequest ("REPORT" , "/user/calendars/default/" , strings .NewReader (reportTest1 ))
339+ req .Header .Set ("Content-Type" , "application/xml" )
340+ w = httptest .NewRecorder ()
341+ handler .ServeHTTP (w , req )
342+
343+ res = w .Result ()
344+ defer res .Body .Close ()
345+ data , err = io .ReadAll (res .Body )
346+ if err != nil {
347+ t .Fatal (err )
348+ }
349+ resp = string (data )
350+ if ! strings .Contains (resp , fmt .Sprintf ("<href>%s</href>" , object .Path )) {
351+ t .Fatalf ("want child href in REPORT" )
352+ } else if ! strings .Contains (resp , object .ETag ) {
353+ t .Fatalf ("want child ETag in REPORT" )
354+ } else if ! strings .Contains (resp , "<getcontenttype xmlns=\" DAV:\" >text/calendar</getcontenttype>" ) {
355+ t .Fatalf ("want child getcontenttype in REPORT" )
356+ } else if ! strings .Contains (resp , "<calendar-data xmlns=\" urn:ietf:params:xml:ns:caldav\" >" ) {
357+ t .Fatalf ("do want calendar-data in REPORT" )
358+ }
else if ! strings .
Contains (
resp ,
"UID:[email protected] " ) {
359+ t .Fatalf ("calendar-data improperly returned" )
360+ }
361+
362+ req = httptest .NewRequest ("PROPFIND" , object .Path , strings .NewReader (propFindTest1 ))
363+ req .Header .Set ("Content-Type" , "application/xml" )
364+ w = httptest .NewRecorder ()
365+ handler .ServeHTTP (w , req )
366+
367+ res = w .Result ()
368+ defer res .Body .Close ()
369+ data , err = io .ReadAll (res .Body )
370+ if err != nil {
371+ t .Fatal (err )
372+ }
373+ resp = string (data )
374+ if strings .
Contains (
resp ,
"UID:[email protected] " ) {
375+ t .Fatalf ("do not want calendar data in PROPFIND" )
376+ } else if ! strings .Contains (resp , object .ETag ) {
377+ t .Fatalf ("want child ETag in PROPFIND" )
378+ } else if ! strings .Contains (resp , "<getcontenttype xmlns=\" DAV:\" >text/calendar</getcontenttype>" ) {
379+ t .Fatalf ("want child getcontenttype in PROPFIND" )
380+ }
381+ }
382+
383+ var calendarTestData2 = `
384+ BEGIN:VCALENDAR
385+ VERSION:2.0
386+ PRODID:-//Example Corp.//CalDAV Client//EN
387+ BEGIN:VTIMEZONE
388+ LAST-MODIFIED:20040110T032845Z
389+ TZID:US/Eastern
390+ BEGIN:DAYLIGHT
391+ DTSTART:20000404T020000
392+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
393+ TZNAME:EDT
394+ TZOFFSETFROM:-0500
395+ TZOFFSETTO:-0400
396+ END:DAYLIGHT
397+ BEGIN:STANDARD
398+ DTSTART:20001026T020000
399+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
400+ TZNAME:EST
401+ TZOFFSETFROM:-0400
402+ TZOFFSETTO:-0500
403+ END:STANDARD
404+ END:VTIMEZONE
405+ BEGIN:VEVENT
406+ DTSTAMP:20060206T001102Z
407+ DTSTART;TZID=US/Eastern:20060102T100000
408+ DURATION:PT1H
409+ SUMMARY:Event #1
410+ Description:Go Steelers!
411+ 412+ END:VEVENT
413+ END:VCALENDAR
414+ `
415+
416+ var multigetTest1 = `
417+ <?xml version="1.0" encoding="utf-8" ?>
418+ <C:calendar-multiget xmlns:D="DAV:"
419+ xmlns:C="urn:ietf:params:xml:ns:caldav">
420+ <D:prop>
421+ <D:getetag/>
422+ <C:calendar-data/>
423+ </D:prop>
424+ <D:href>/user/calendars/default/74855313FA803DA593CD579A.ics</D:href>
425+ <D:href>/user/calendars/default/DC6C50A017428C5216A2F1CD.ics</D:href>
426+ </C:calendar-multiget>
427+ `
428+
429+ func TestFindMultiget (t * testing.T ) {
430+ calendar := Calendar {
431+ Description : "This is a description which SHOULD NOT be returned in allprop" ,
432+ Path : "/user/calendars/default/" ,
433+ SupportedComponentSet : []string {"VEVENT" },
434+ }
435+ cal , err := ical .NewDecoder (strings .NewReader (calendarTestData1 )).Decode ()
436+ if err != nil {
437+ t .Fatal (err )
438+ }
439+ object1 := CalendarObject {
440+ Path : "/user/calendars/default/DC6C50A017428C5216A2F1CD.ics" ,
441+ Data : cal ,
442+ ETag : "191382932849" ,
443+ }
444+ cal , err = ical .NewDecoder (strings .NewReader (calendarTestData2 )).Decode ()
445+ if err != nil {
446+ t .Fatal (err )
447+ }
448+ object2 := CalendarObject {
449+ Path : "/user/calendars/default/74855313FA803DA593CD579A.ics" ,
450+ Data : cal ,
451+ ETag : "191382932850" ,
452+ }
453+ handler := Handler {Backend : testBackend {
454+ calendars : []Calendar {calendar },
455+ objectMap : map [string ][]CalendarObject {
456+ calendar .Path : []CalendarObject {object1 , object2 },
457+ },
458+ }}
459+
460+ req := httptest .NewRequest ("REPORT" , "/user/calendars/default/" , strings .NewReader (multigetTest1 ))
461+ req .Header .Set ("Content-Type" , "application/xml" )
462+ req .Header .Set ("Depth" , "1" )
463+ w := httptest .NewRecorder ()
464+ handler .ServeHTTP (w , req )
465+
466+ res := w .Result ()
467+ defer res .Body .Close ()
468+ data , err := io .ReadAll (res .Body )
469+ if err != nil {
470+ t .Fatal (err )
471+ }
472+ resp := string (data )
473+ if ! strings .
Contains (
resp ,
"UID:[email protected] " ) {
474+ t .Fatalf ("want object1 in multiget report" )
475+ }
else if ! strings .
Contains (
resp ,
"UID:[email protected] " ) {
476+ t .Fatalf ("want object2 in multiget report" )
477+ } else if ! strings .Contains (resp , object1 .ETag ) {
478+ t .Fatalf ("want object1 ETag in multiget report" )
479+ } else if ! strings .Contains (resp , object2 .ETag ) {
480+ t .Fatalf ("want object2 ETag in multiget report" )
481+ }
482+ }
483+
180484type testBackend struct {
181485 calendars []Calendar
182486 objectMap map [string ][]CalendarObject
@@ -231,5 +535,9 @@ func (t testBackend) ListCalendarObjects(ctx context.Context, path string, req *
231535}
232536
233537func (t testBackend ) QueryCalendarObjects (ctx context.Context , path string , query * CalendarQuery ) ([]CalendarObject , error ) {
234- return nil , nil
538+ if cos , err := t .ListCalendarObjects (ctx , path , nil ); err != nil {
539+ return nil , err
540+ } else {
541+ return Filter (query , cos )
542+ }
235543}
0 commit comments