Files
Oxicloud/tests/api/caldav_calendar_query.hurl
T
Edouard Vanbelle a67fcadeea fix(ical): fix timerange issue
accept iCal DATE-TIME + RFC 3339 fallback
2026-07-14 23:13:50 +02:00

262 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================
# OxiCloud — CalDAV calendar-query REPORT time-range regression
# =============================================================
# Regression pin for the time-range parser fix on
# fix/caldav-time-range-parser.
#
# Pre-fix: caldav_adapter.rs::parse_report used
# `DateTime::parse_from_rfc3339` on the `<C:time-range start="..."
# end="..."/>` attribute values. That parser expects
# `YYYY-MM-DDTHH:MM:SSZ` (dashes + colons). CalDAV clients send
# iCalendar DATE-TIME format (`YYYYMMDDTHHMMSSZ` — no separators)
# per RFC 4791 §9.9 / RFC 5545 §3.3.5. Result: parse silently
# failed, `time_range` was `None`, and the REPORT handler fell
# through to `list_events`, returning the ENTIRE calendar
# regardless of the requested window.
#
# Post-fix: `parse_caldav_datetime` accepts iCal DATE-TIME
# (the standard) with RFC 3339 as a defensive fallback. Time-
# range filters now actually filter.
#
# Test shape: create two events at 09:00 UTC and 15:00 UTC, then
# calendar-query REPORT with an iCal-DATE-TIME window covering
# only the 09:00 event. Assert the response contains the 09:00
# event's UID and does NOT contain the 15:00 event's UID.
# =============================================================
# ─────────────────────────────────────────────────────────────
# Step 1 — Admin login.
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/auth/login
Content-Type: application/json
{ "username": "{{username}}", "password": "{{password}}" }
HTTP 200
[Captures]
admin_token: jsonpath "$.access_token"
# ─────────────────────────────────────────────────────────────
# Step 2 — Provision a fresh calendar (`tr-cal`) so the seeded
# events don't collide with anything downstream tests provisioned.
# MKCALENDAR returns 201; the server assigns its own UUID which
# we capture via PROPFIND in Step 3.
# ─────────────────────────────────────────────────────────────
MKCALENDAR {{base_url}}/caldav/tr-cal/
Authorization: Bearer {{admin_token}}
HTTP 201
# ─────────────────────────────────────────────────────────────
# Step 3 — Discover the server-assigned UUID via PROPFIND. The
# `(?s).*` anchor greedy-matches to the LAST /caldav/<uuid>/ in
# the body — that's `tr-cal`, freshest by created_at.
# ─────────────────────────────────────────────────────────────
PROPFIND {{base_url}}/caldav/
Authorization: Bearer {{admin_token}}
Depth: 1
Content-Type: application/xml
```
<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:">
<D:prop><D:displayname/><D:resourcetype/></D:prop>
</D:propfind>
```
HTTP 207
[Captures]
tr_cal_id: body regex "(?s).*/caldav/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/"
[Asserts]
body contains "tr-cal"
# ─────────────────────────────────────────────────────────────
# Step 4 — Seed the morning event (09:00–10:00 UTC).
# ─────────────────────────────────────────────────────────────
PUT {{base_url}}/caldav/{{tr_cal_id}}/tr-morning.ics
Authorization: Bearer {{admin_token}}
Content-Type: text/calendar
```
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//OxiCloud time-range test//EN
BEGIN:VEVENT
UID:tr-morning
DTSTAMP:20260101T080000Z
DTSTART:20260101T090000Z
DTEND:20260101T100000Z
SUMMARY:Morning event
END:VEVENT
END:VCALENDAR
```
HTTP *
[Asserts]
status >= 200
status < 300
# ─────────────────────────────────────────────────────────────
# Step 5 — Seed the afternoon event (15:00–16:00 UTC).
# ─────────────────────────────────────────────────────────────
PUT {{base_url}}/caldav/{{tr_cal_id}}/tr-afternoon.ics
Authorization: Bearer {{admin_token}}
Content-Type: text/calendar
```
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//OxiCloud time-range test//EN
BEGIN:VEVENT
UID:tr-afternoon
DTSTAMP:20260101T080000Z
DTSTART:20260101T150000Z
DTEND:20260101T160000Z
SUMMARY:Afternoon event
END:VEVENT
END:VCALENDAR
```
HTTP *
[Asserts]
status >= 200
status < 300
# ─────────────────────────────────────────────────────────────
# Step 6 — calendar-query REPORT with iCal-DATE-TIME time-range
# covering the morning event only (08:00 → 13:00 UTC). Post-fix
# the response must contain `tr-morning` and MUST NOT contain
# `tr-afternoon`.
#
# Pre-fix: `time_range` parses as None → falls through to
# `list_events`, response contains BOTH events. This test's
# "body not contains tr-afternoon" assertion catches that.
# ─────────────────────────────────────────────────────────────
REPORT {{base_url}}/caldav/{{tr_cal_id}}/
Authorization: Bearer {{admin_token}}
Content-Type: application/xml
Depth: 1
```
<?xml version="1.0" encoding="UTF-8"?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20260101T080000Z" end="20260101T130000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
```
HTTP 207
[Asserts]
body contains "tr-morning"
body not contains "tr-afternoon"
# ─────────────────────────────────────────────────────────────
# Step 7 — Symmetric window: afternoon only (14:00 → 17:00 UTC).
# Guards against a fix that accidentally hardcodes the morning
# window or reverses start/end.
# ─────────────────────────────────────────────────────────────
REPORT {{base_url}}/caldav/{{tr_cal_id}}/
Authorization: Bearer {{admin_token}}
Content-Type: application/xml
Depth: 1
```
<?xml version="1.0" encoding="UTF-8"?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20260101T140000Z" end="20260101T170000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
```
HTTP 207
[Asserts]
body contains "tr-afternoon"
body not contains "tr-morning"
# ─────────────────────────────────────────────────────────────
# Step 8 — Window with no overlap (year 2027) returns neither
# event. Proves the filter is actually applied (pre-fix this
# returned both).
# ─────────────────────────────────────────────────────────────
REPORT {{base_url}}/caldav/{{tr_cal_id}}/
Authorization: Bearer {{admin_token}}
Content-Type: application/xml
Depth: 1
```
<?xml version="1.0" encoding="UTF-8"?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20270101T000000Z" end="20270102T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
```
HTTP 207
[Asserts]
body not contains "tr-morning"
body not contains "tr-afternoon"
# ─────────────────────────────────────────────────────────────
# Step 9 — Sanity: a filter-less REPORT still returns both
# events. Guards against a fix that over-corrects and starts
# treating "no time-range" as "empty window".
# ─────────────────────────────────────────────────────────────
REPORT {{base_url}}/caldav/{{tr_cal_id}}/
Authorization: Bearer {{admin_token}}
Content-Type: application/xml
Depth: 1
```
<?xml version="1.0" encoding="UTF-8"?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
</C:calendar-query>
```
HTTP 207
[Asserts]
body contains "tr-morning"
body contains "tr-afternoon"
# ─────────────────────────────────────────────────────────────
# Step 10 — Cleanup: delete the calendar so downstream test
# files don't inherit an extra collection (per memory
# feedback_hurl_teardown_shared_db).
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/caldav/{{tr_cal_id}}/
Authorization: Bearer {{admin_token}}
HTTP 204