From f73658b32f78501e11e86407c65cf13dfc350a42 Mon Sep 17 00:00:00 2001
From: Lennart <18233294+lennart-k@users.noreply.github.com>
Date: Mon, 19 Jan 2026 12:09:34 +0100
Subject: [PATCH] Re-enable calendar-query test and fix calendar expansion
---
Cargo.lock | 79 +++++-----
Cargo.toml | 1 +
.../caldav/calendar_report.rs | 137 ++++++++++--------
src/integration_tests/caldav/mod.rs | 2 +-
.../caldav/resources/rfc4791_appb.ics | 1 +
...__caldav__calendar_import__1_get_body.snap | 1 +
...aldav__calendar_report__0_report_body.snap | 3 +-
...aldav__calendar_report__1_report_body.snap | 1 +
...aldav__calendar_report__2_report_body.snap | 11 +-
9 files changed, 128 insertions(+), 108 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 83a59e7..b4a8517 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -573,9 +573,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.2.52"
+version = "1.2.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
+checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -1241,9 +1241,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.7"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
[[package]]
name = "flume"
@@ -1771,7 +1771,7 @@ dependencies = [
[[package]]
name = "ical"
version = "0.12.0-dev"
-source = "git+https://github.com/lennart-k/ical-rs?branch=dev#5e61c25646c3785448d349e7d18b2833fc483c53"
+source = "git+https://github.com/lennart-k/ical-rs?branch=dev#8697656303f182ce173efdaf6aa7e842ffdb3f33"
dependencies = [
"chrono",
"chrono-tz",
@@ -1781,7 +1781,7 @@ dependencies = [
"phf 0.13.1",
"regex",
"rrule",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -2118,7 +2118,7 @@ dependencies = [
"matchit 0.9.1",
"percent-encoding",
"serde",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -2370,7 +2370,7 @@ dependencies = [
"futures-sink",
"js-sys",
"pin-project-lite",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tracing",
]
@@ -2400,7 +2400,7 @@ dependencies = [
"opentelemetry_sdk",
"prost",
"reqwest",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tonic",
"tracing",
@@ -2437,7 +2437,7 @@ dependencies = [
"opentelemetry",
"percent-encoding",
"rand 0.9.2",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tokio-stream",
]
@@ -2891,7 +2891,7 @@ dependencies = [
"rustc-hash",
"rustls",
"socket2",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tracing",
"web-time",
@@ -2912,7 +2912,7 @@ dependencies = [
"rustls",
"rustls-pki-types",
"slab",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tinyvec",
"tracing",
"web-time",
@@ -3187,7 +3187,7 @@ dependencies = [
"chrono-tz",
"log",
"regex",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -3349,6 +3349,7 @@ dependencies = [
"rustical_store",
"rustical_store_sqlite",
"serde",
+ "similar-asserts",
"sqlx",
"tokio",
"toml 0.9.11+spec-1.1.0",
@@ -3393,7 +3394,7 @@ dependencies = [
"similar-asserts",
"strum",
"strum_macros",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tower",
"tower-http",
@@ -3428,7 +3429,7 @@ dependencies = [
"serde",
"strum",
"strum_macros",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tower",
"tower-http",
@@ -3457,7 +3458,7 @@ dependencies = [
"rustical_xml",
"serde",
"strum",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tower",
"tracing",
@@ -3483,7 +3484,7 @@ dependencies = [
"rustical_store",
"rustical_xml",
"serde",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tracing",
]
@@ -3513,7 +3514,7 @@ dependencies = [
"rustical_store",
"serde",
"serde_json",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tower",
"tower-http",
@@ -3540,7 +3541,7 @@ dependencies = [
"serde",
"sha2",
"similar-asserts",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
]
[[package]]
@@ -3554,7 +3555,7 @@ dependencies = [
"openidconnect",
"reqwest",
"serde",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tower-sessions",
"tracing",
]
@@ -3584,7 +3585,7 @@ dependencies = [
"rustical_xml",
"serde",
"sha2",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tower",
"tower-sessions",
@@ -3611,7 +3612,7 @@ dependencies = [
"serde",
"sha2",
"sqlx",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tracing",
"uuid",
@@ -3622,7 +3623,7 @@ name = "rustical_xml"
version = "0.11.17"
dependencies = [
"quick-xml",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"xml_derive",
]
@@ -3655,9 +3656,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.13.3"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4910321ebe4151be888e35fe062169554e74aad01beafed60410131420ceffbc"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
dependencies = [
"web-time",
"zeroize",
@@ -3665,9 +3666,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
-version = "0.103.8"
+version = "0.103.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
+checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
dependencies = [
"ring",
"rustls-pki-types",
@@ -4047,7 +4048,7 @@ dependencies = [
"serde_json",
"sha2",
"smallvec",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tokio",
"tokio-stream",
"tracing",
@@ -4131,7 +4132,7 @@ dependencies = [
"smallvec",
"sqlx-core",
"stringprep",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tracing",
"uuid",
"whoami",
@@ -4170,7 +4171,7 @@ dependencies = [
"smallvec",
"sqlx-core",
"stringprep",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tracing",
"uuid",
"whoami",
@@ -4196,7 +4197,7 @@ dependencies = [
"serde",
"serde_urlencoded",
"sqlx-core",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"tracing",
"url",
"uuid",
@@ -4315,11 +4316,11 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "2.0.17"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
- "thiserror-impl 2.0.17",
+ "thiserror-impl 2.0.18",
]
[[package]]
@@ -4335,9 +4336,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
-version = "2.0.17"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
@@ -4719,7 +4720,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"serde_json",
- "thiserror 2.0.17",
+ "thiserror 2.0.18",
"time",
"tokio",
"tracing",
@@ -5562,6 +5563,6 @@ dependencies = [
[[package]]
name = "zmij"
-version = "1.0.14"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"
+checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2"
diff --git a/Cargo.toml b/Cargo.toml
index 488c0c1..c8ba8f2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -153,6 +153,7 @@ criterion = { version = "0.8", features = ["async_tokio"] }
rstest.workspace = true
rustical_store_sqlite = { workspace = true, features = ["test"] }
insta.workspace = true
+similar-asserts.workspace = true
[dependencies]
rustical_store.workspace = true
diff --git a/src/integration_tests/caldav/calendar_report.rs b/src/integration_tests/caldav/calendar_report.rs
index 879e6f3..02974ff 100644
--- a/src/integration_tests/caldav/calendar_report.rs
+++ b/src/integration_tests/caldav/calendar_report.rs
@@ -87,70 +87,79 @@ const REPORT_7_8_3: &str = r#"
"#;
-const OUTPUT_7_8_3: &str = r#"
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART:20060103T170000
- DURATION:PT1H
- RECURRENCE-ID:20060103T170000
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART:20060104T190000
- DURATION:PT1H
- RECURRENCE-ID:20060104T170000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART:20060104T150000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-"#;
+// Adapted from Example 7.8.3 of RFC 4791
+// In the RFC the output is wrong since it returns DTSTART in UTC as local time, e.g.
+// DTSTART:20060103T170000
+// instead of
+// DTSTART:20060103T170000Z
+// In https://datatracker.ietf.org/doc/html/rfc4791#section-9.6.5
+// it is clearly stated that times with timezone information MUST be returned in UTC.
+// Also, the RECURRENCE-ID needs to include the TIMEZONE, which is fixed here by converting it to
+// UTC
+const OUTPUT_7_8_3: &str = r#"
+
+
+ /caldav/principal/user/calendar/abcd2.ics
+
+
+ BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Example Corp.//CalDAV Client//EN
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART:20060103T170000Z
+DURATION:PT1H
+SUMMARY:Event #2
+UID:abcd2
+RECURRENCE-ID:20060103T170000Z
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART:20060104T190000Z
+DURATION:PT1H
+RECURRENCE-ID:20060104T170000Z
+SUMMARY:Event #2 bis
+UID:abcd2
+END:VEVENT
+END:VCALENDAR
+
+
+ HTTP/1.1 200 OK
+
+
+
+ /caldav/principal/user/calendar/abcd3.ics
+
+
+ BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Example Corp.//CalDAV Client//EN
+BEGIN:VEVENT
+ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+DTSTAMP:20060206T001220Z
+DTSTART:20060104T150000Z
+DURATION:PT1H
+LAST-MODIFIED:20060206T001330Z
+ORGANIZER:mailto:cyrus@example.com
+SEQUENCE:1
+STATUS:TENTATIVE
+SUMMARY:Event #3
+UID:abcd3
+X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+END:VEVENT
+END:VCALENDAR
+
+
+ HTTP/1.1 200 OK
+
+
+"#;
#[rstest]
-#[case(0, ICS_1, REPORT_7_8_1)]
-#[case(1, ICS_1, REPORT_7_8_2)]
-#[case(2, ICS_1, REPORT_7_8_3)]
+#[case(0, ICS_1, REPORT_7_8_1, None)]
+#[case(1, ICS_1, REPORT_7_8_2, None)]
+#[case(2, ICS_1, REPORT_7_8_3, Some(OUTPUT_7_8_3))]
#[tokio::test]
async fn test_report(
#[from(test_store_context)]
@@ -159,6 +168,7 @@ async fn test_report(
#[case] case: usize,
#[case] ics: &'static str,
#[case] report: &'static str,
+ #[case] output: Option<&'static str>,
) {
let context = context.await;
let app = get_app(context.clone());
@@ -193,4 +203,7 @@ async fn test_report(
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
let body = response.extract_string().await;
insta::assert_snapshot!(format!("{case}_report_body"), body);
+ if let Some(output) = output {
+ similar_asserts::assert_eq!(output, body.replace('\r', ""));
+ }
}
diff --git a/src/integration_tests/caldav/mod.rs b/src/integration_tests/caldav/mod.rs
index 3378fbe..4a91cd7 100644
--- a/src/integration_tests/caldav/mod.rs
+++ b/src/integration_tests/caldav/mod.rs
@@ -9,7 +9,7 @@ use tower::ServiceExt;
mod calendar;
mod calendar_import;
-// mod calendar_report;
+mod calendar_report;
#[rstest]
#[tokio::test]
diff --git a/src/integration_tests/caldav/resources/rfc4791_appb.ics b/src/integration_tests/caldav/resources/rfc4791_appb.ics
index ea74a96..4ab2a03 100644
--- a/src/integration_tests/caldav/resources/rfc4791_appb.ics
+++ b/src/integration_tests/caldav/resources/rfc4791_appb.ics
@@ -55,6 +55,7 @@ SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:abcd3
+X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
BEGIN:VTODO
DTSTAMP:20060205T235335Z
diff --git a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_import__1_get_body.snap b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_import__1_get_body.snap
index 2cdafb5..059168d 100644
--- a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_import__1_get_body.snap
+++ b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_import__1_get_body.snap
@@ -60,6 +60,7 @@ SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:[UID]
+X-ABC-GUID:[UID]
END:VEVENT
BEGIN:VTODO
DTSTAMP:20060205T235335Z
diff --git a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__0_report_body.snap b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__0_report_body.snap
index b179127..79834cc 100644
--- a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__0_report_body.snap
+++ b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__0_report_body.snap
@@ -56,7 +56,7 @@ END:VCALENDAR
/caldav/principal/user/calendar/abcd3.ics
- "c6a5b1cf6985805686df99e7f2e1cf286567dcb3383fc6fa1b12ce42d3fbc01c"
+ "a84fd022dfc742bf8f17ac04fca3aad687e9ae724180185e8e0df11e432dae30"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
@@ -90,6 +90,7 @@ SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:abcd3
+X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
diff --git a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__1_report_body.snap b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__1_report_body.snap
index f3e413b..09add03 100644
--- a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__1_report_body.snap
+++ b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__1_report_body.snap
@@ -88,6 +88,7 @@ SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:abcd3
+X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
diff --git a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__2_report_body.snap b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__2_report_body.snap
index 9801e29..0ae78e9 100644
--- a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__2_report_body.snap
+++ b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__calendar_report__2_report_body.snap
@@ -13,19 +13,19 @@ VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
+DTSTART:20060103T170000Z
DURATION:PT1H
SUMMARY:Event #2
UID:abcd2
RECURRENCE-ID:20060103T170000Z
-DTSTART:20060103T170000Z
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
+DTSTART:20060104T190000Z
DURATION:PT1H
-SUMMARY:Event #2
-UID:abcd2
RECURRENCE-ID:20060104T170000Z
-DTSTART:20060104T170000Z
+SUMMARY:Event #2 bis
+UID:abcd2
END:VEVENT
END:VCALENDAR
@@ -44,7 +44,7 @@ BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
-DTSTART;TZID=US/Eastern:20060104T100000
+DTSTART:20060104T150000Z
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
@@ -52,6 +52,7 @@ SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:abcd3
+X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR