test calendar-query vevent filtering
This commit is contained in:
parent
54d10ed482
commit
a859fe38b1
4 changed files with 174 additions and 1 deletions
|
@ -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(
|
||||
|
|
|
@ -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?,
|
||||
|
|
|
@ -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(())
|
||||
})
|
||||
|
|
|
@ -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
|
||||
"#;
|
||||
|
|
Loading…
Reference in a new issue