test calendar-query vevent filtering

This commit is contained in:
Quentin 2024-05-23 08:55:53 +02:00
parent 54d10ed482
commit a859fe38b1
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 174 additions and 1 deletions

View file

@ -973,6 +973,17 @@ mod tests {
rdr.find().await.unwrap()
}
#[tokio::test]
async fn simple_comp_filter() {
let expected = CompFilter {
name: Component::VEvent,
additional_rules: None,
};
let src = r#"<C:comp-filter name="VEVENT" xmlns:C="urn:ietf:params:xml:ns:caldav" />"#;
let got = deserialize::<CompFilter>(src).await;
assert_eq!(got, expected);
}
#[tokio::test]
async fn basic_mkcalendar() {
let expected = MkCalendar(dav::Set(dav::PropValue(vec![dav::Property::DisplayName(

View file

@ -229,7 +229,10 @@ impl<T: IRead> Reader<T> {
}
pub async fn maybe_find<N: Node<N>>(&mut self) -> Result<Option<N>, ParsingError> {
self.ensure_parent_has_child()?;
// We can't find anything inside a self-closed tag
if !self.parent_has_child() {
return Ok(None);
}
loop {
// Try parse
@ -238,6 +241,7 @@ impl<T: IRead> Reader<T> {
otherwise => return otherwise.map(Some),
}
// Skip or stop
match self.peek() {
Event::End(_) => return Ok(None),
_ => self.skip().await?,

View file

@ -553,6 +553,45 @@ fn rfc5397_webdav_principal() {
fn rfc4791_webdav_caldav() {
println!("🧪 rfc4791_webdav_caldav");
common::aerogramme_provider_daemon_dev(|_imap, _lmtp, http| {
// --- INITIAL TEST SETUP ---
// Add entries (3 VEVENT, 1 FREEBUSY, 1 VTODO)
let resp = http
.put("http://localhost:8087/alice/calendar/Personal/rfc1.ics")
.header("If-None-Match", "*")
.body(ICAL_RFC1)
.send()?;
let obj1_etag = resp.headers().get("etag").expect("etag must be set");
assert_eq!(resp.status(), 201);
let resp = http
.put("http://localhost:8087/alice/calendar/Personal/rfc2.ics")
.header("If-None-Match", "*")
.body(ICAL_RFC2)
.send()?;
let obj2_etag = resp.headers().get("etag").expect("etag must be set");
assert_eq!(resp.status(), 201);
let resp = http
.put("http://localhost:8087/alice/calendar/Personal/rfc3.ics")
.header("If-None-Match", "*")
.body(ICAL_RFC3)
.send()?;
let obj3_etag = resp.headers().get("etag").expect("etag must be set");
assert_eq!(resp.status(), 201);
let resp = http
.put("http://localhost:8087/alice/calendar/Personal/rfc4.ics")
.header("If-None-Match", "*")
.body(ICAL_RFC4)
.send()?;
let obj4_etag = resp.headers().get("etag").expect("etag must be set");
assert_eq!(resp.status(), 201);
let resp = http
.put("http://localhost:8087/alice/calendar/Personal/rfc5.ics")
.header("If-None-Match", "*")
.body(ICAL_RFC5)
.send()?;
let obj5_etag = resp.headers().get("etag").expect("etag must be set");
assert_eq!(resp.status(), 201);
// --- AUTODISCOVERY ---
// Check calendar discovery from principal
let propfind_req = r#"<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
@ -595,7 +634,92 @@ fn rfc4791_webdav_caldav() {
.expect("request returns a calendar home set");
assert_eq!(calendar_home_set, "/alice/calendar/");
// Check calendar access support
let resp = http
.request(
reqwest::Method::from_bytes(b"OPTIONS")?,
"http://localhost:8087/alice/calendar/",
)
.send()?;
//@FIXME not yet supported. returns DAV: 1 ; expects DAV: 1 calendar-access
//@FIXME missing support for calendar-data...
//println!("{:?}", resp);
// --- REPORT calendar-query ---
// 7.8.8. Example: Retrieval of Events Only
let cal_query = r#"<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT"/>
</C:comp-filter>
</C:filter>
</C:calendar-query>"#;
let resp = http
.request(
reqwest::Method::from_bytes(b"REPORT")?,
"http://localhost:8087/alice/calendar/Personal/",
)
.body(cal_query)
.send()?;
assert_eq!(resp.status(), 207);
let multistatus = dav_deserialize::<dav::Multistatus<All>>(&resp.text()?);
assert_eq!(multistatus.responses.len(), 3);
[
("/alice/calendar/Personal/rfc1.ics", obj1_etag, ICAL_RFC1),
("/alice/calendar/Personal/rfc2.ics", obj2_etag, ICAL_RFC2),
("/alice/calendar/Personal/rfc3.ics", obj3_etag, ICAL_RFC3),
]
.iter()
.for_each(|(ref_path, ref_etag, ref_ical)| {
let obj_stats = multistatus
.responses
.iter()
.find_map(|v| match &v.status_or_propstat {
dav::StatusOrPropstat::PropStat(dav::Href(p), x) if p.as_str() == *ref_path => {
Some(x)
}
_ => None,
})
.expect("propstats must exist");
let obj_success = obj_stats
.iter()
.find(|p| p.status.0.as_u16() == 200)
.expect("some propstats must be 200");
let etag = obj_success
.prop
.0
.iter()
.find_map(|p| match p {
dav::AnyProperty::Value(dav::Property::GetEtag(x)) => Some(x),
_ => None,
})
.expect("etag is return in propstats");
assert_eq!(
etag.as_str(),
ref_etag
.to_str()
.expect("header value is convertible to string")
);
let calendar_data = obj_success
.prop
.0
.iter()
.find_map(|p| match p {
dav::AnyProperty::Value(dav::Property::Extension(
realization::Property::Cal(cal::Property::CalendarData(x)),
)) => Some(x),
_ => None,
})
.expect("calendar data is returned in propstats");
assert_eq!(calendar_data.payload.as_bytes(), *ref_ical);
});
Ok(())
})

View file

@ -124,3 +124,37 @@ UID:DC6C50A017428C5216A2F1CD@example.com
END:VEVENT
END:VCALENDAR
";
pub static ICAL_RFC4: &[u8] = br#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VFREEBUSY
ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
UID:76ef34-54a3d2@example.com
DTSTAMP:20050530T123421Z
DTSTART:20060101T000000Z
DTEND:20060108T000000Z
FREEBUSY:20050531T230000Z/20050601T010000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
FREEBUSY:20060103T100000Z/20060103T120000Z
FREEBUSY:20060104T100000Z/20060104T120000Z
FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20060105T100000Z/20060105T120000Z
FREEBUSY:20060106T100000Z/20060106T120000Z
END:VFREEBUSY
END:VCALENDAR
"#;
pub static ICAL_RFC5: &[u8] = br#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235600Z
DUE;VALUE=DATE:20060101
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:CANCELLED
SUMMARY:Task #4
UID:E10BA47467C5C69BB74E8725@example.com
END:VTODO
END:VCALENDAR
"#;