Skip to content

Scheduling testing#646

Draft
tobixen wants to merge 17 commits intomasterfrom
scheduling-testing
Draft

Scheduling testing#646
tobixen wants to merge 17 commits intomasterfrom
scheduling-testing

Conversation

@tobixen
Copy link
Member

@tobixen tobixen commented Mar 21, 2026

Now that we have lots of docker containers supporting the scheduling RFC, we should get the test framework doing some real testing on it

tobixen and others added 12 commits March 20, 2026 20:38
- Fix config_loader._load_config_file to preserve top-level keys like
  rfc6638_users when unwrapping the test-servers dict — previously they
  were silently dropped, so TestScheduling was always skipped.
- Fix registry.load_from_config to skip non-dict entries (e.g. the
  rfc6638_users list) instead of raising ValueError.
- Add two new tests in test_config_loader.py covering these fixes.
- Add user1/testpass1, user2/testpass2, user3/testpass3 to the Baikal
  pre-seeded SQLite DB (create_baikal_db.py + regenerated db.sqlite),
  alongside the existing testuser account.
- Add user1-user3 to init-sogo-users.sql for SOGo.
- Add CI step that writes tests/caldav_test_servers.yaml with
  rfc6638_users pointing to Cyrus user1-user3 (password 'x'), which
  are pre-created by the ghcr.io/cyrusimap/cyrus-docker-test-server
  image and are expected to support calendar-auto-schedule.
- Update example config files with server-specific rfc6638_users
  snippets for Cyrus, Baikal and SOGo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new 'scheduling' feature entry to the compatibility hints,
corresponding to the legacy 'no_scheduling' flag, to enable structured
tracking of RFC6638 CalDAV Scheduling support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the old_flags no_scheduling / no_scheduling_mailbox /
no_scheduling_calendar_user_address_set with the new 'scheduling'
feature entry in the compatibility matrix, and adapt the test code to
use skip_unless_support("scheduling") / is_supported("scheduling").

Servers with no_scheduling → "scheduling": {"support": "unsupported"}:
xandikos_v0_2_12, xandikos, radicale, robur, posteo, purelymail

Servers with partial scheduling (mailbox/address-set missing) → noted
with a TODO for future sub-features: gmx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… sub-features

- Add scheduling.mailbox and scheduling.calendar-user-address-set to
  FeatureSet.FEATURES (RFC6638 sections 2.2-2.4.1)
- Set both to unsupported in the gmx server entry (scheduling is
  advertised but sub-features are non-functional)
- Adapt testSchedulingInfo/testSchedulingMailboxes to use the new
  sub-feature flags instead of the top-level scheduling flag
- Refactor TestScheduling into TestSchedulingBase with a configurable
  _users list; legacy TestScheduling created from rfc6638_users
- Generate TestSchedulingForServer* classes for servers with
  scheduling_users configured in their server entry
- Pass scheduling_users through in TestServer.get_server_params()
- Document and enable scheduling_users for Cyrus in the example config
  (Cyrus pre-creates user1-user5 with password 'x')

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename TestSchedulingBase → _TestSchedulingBase so pytest no longer
  collects the base class directly (it has _users=[] → noisy skip).
  The docstring already said "no Test prefix" but the code disagreed.

- Teach load_from_config to merge scheduling_users into an already-
  registered server (case-insensitive name match) instead of
  registering a duplicate.  This allows a caldav_test_servers.yaml
  entry like:
    cyrus:
      scheduling_users: [...]
  to augment the auto-discovered CyrusTestServer without doubling up.

- If a config entry contains only test-metadata keys (scheduling_users,
  type, enabled) and no matching server is already registered, skip it
  silently — it is intended to augment a running server, not create a
  new one (avoids spurious test runs when e.g. Cyrus isn't started
  locally but the CI-oriented config file is present).

- Update CI step to write per-server scheduling_users for both Cyrus
  and Baikal (instead of the previous global rfc6638_users approach).

- Update caldav_test_servers.yaml.example with Baikal and SOGo
  scheduling_users examples and explain when to use the legacy
  rfc6638_users fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rather than requiring a caldav_test_servers.yaml file to be written
by CI (or manually by the user), bake the scheduling_users directly
into CyrusTestServer and BaikalTestServer.__init__.

- Cyrus: user1-user3 / password 'x' (pre-created by the docker image)
- Baikal: user1-user3 / testpass1-3 (pre-seeded in the committed db.sqlite)

The per-server TestSchedulingForServer{Cyrus,Baikal} classes are now
generated automatically whenever those servers are running, with no
additional configuration required.

Also drop the now-unnecessary CI step that wrote caldav_test_servers.yaml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NextcloudTestServer: create user1-3 (testpass1-3) via setup_nextcloud.sh,
  set scheduling_users using base remote.php/dav URL
- DavicalTestServer: create user1-3 (testpass1-3) via setup_davical.sh
  (refactored to a create_user() function), set scheduling_users with
  per-user /caldav.php/userN/ URLs
- ZimbraTestServer: create testuser3@zimbra.io via start.sh,
  set scheduling_users for testuser/testuser2/testuser3 with ssl_verify_cert=False
- CI: create user1-3 in Nextcloud setup step
- Update caldav_test_servers.yaml.example with scheduling notes

This means TestSchedulingForServerNextcloud, TestSchedulingForServerDavical,
and TestSchedulingForServerZimbra classes will be auto-generated when those
servers are running, matching the existing Baikal/Cyrus pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Some servers (notably Cyrus) implement RFC6638 automatic scheduling
(section 3.2.3): incoming invitations are auto-processed and placed
directly on the attendee's calendar without appearing in the inbox.

- Add scheduling.inbox-delivery feature to compatibility_hints.py,
  with links to RFC6638 sections 3.1 and 3.2.3
- Mark Cyrus as scheduling.inbox-delivery: unsupported
- Modify testInviteAndRespond to detect auto-scheduling at runtime:
  if no inbox items appear after an invite, check that the event was
  auto-added to the attendee's calendar and return gracefully

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Check the attendee's inbox FIRST to determine whether the server uses
inbox delivery or automatic scheduling. This avoids a false assertion on
the organizer's inbox (which may receive an auto-reply from the server's
auto-processing) before we know we're in the auto-scheduling path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claud was hallucinating the RFC references!

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tobixen tobixen force-pushed the scheduling-testing branch from e257d0a to 54a45fb Compare March 22, 2026 09:30
tobixen and others added 5 commits March 22, 2026 14:29
…andling both auto-schedule+inbox

Root cause: Cyrus's iTIP scheduling delivery (caladdress_lookup) preserves
the full email form (user2@example.com) as sparam->userid when virtdomains
is enabled.  But mailbox ACLs and mbname_userid() use the short form (user2)
for default-domain users.  This mismatch causes caldav_store_preprocess() to
fail the ACL check with 403 Forbidden when delivering invites to the
attendee's Default calendar.

Fix 1 (tests/docker-test-servers/cyrus/):
- Add imapd.conf override with virtdomains: off so caladdress_lookup strips
  the domain from local email addresses, matching the IMAP userid in ACLs
- Mount the override in docker-compose.yml via a volume bind

Fix 2 (tests/test_caldav.py):
- With virtdomains: off, Cyrus auto-schedules the event into the attendee's
  Default calendar AND delivers an iTIP copy to the schedule-inbox
- The original test only handled pure auto-scheduling (empty inbox) or pure
  inbox-delivery; add a check for the "both" case: if the event is already
  in any attendee calendar, treat it as auto-scheduled and return early

Fix 3 (caldav/compatibility_hints.py):
- Update the Cyrus scheduling.inbox-delivery comment to document the actual
  behaviour: auto-scheduled + inbox notification for cross-user invites
  (the hint stays "unsupported" because the self-invite probe used by feature
  checkers correctly observes no inbox delivery — Cyrus skips self-invites)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
testCheckCompatibility now creates extra clients from scheduling_users[1:]
so that ServerQuirkChecker can perform cross-user checks (e.g. the
scheduling inbox-delivery probe).

Also update the Cyrus compatibility hint for scheduling.inbox-delivery:
Cyrus delivers an iTIP notification to the attendee's inbox AND
auto-schedules the event, so the correct level is 'quirk' (not
'unsupported' which was only accurate for the self-invite probe that
Cyrus skips entirely).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three fixes for TestSchedulingForServerNextcloud::testInviteAndRespond:

1. setup_nextcloud.sh: set email addresses for scheduling test users
   (user1@localhost etc.) — Nextcloud requires a mailto: address in
   calendar-user-address-set for scheduling to route invites correctly.
   Without it, get_vcal_address() returns a bare principal URL and
   Nextcloud silently drops the invite.

2. setup_nextcloud.sh: properly reset accumulated bruteforce attempts
   after creating users (enable→reset→disable pattern), and whitelist
   0.0.0.0/0 since the service is test-only and never externally exposed.

3. test_caldav.py (_TestSchedulingBase): change _getCalendar to find an
   existing calendar by name and clear its events, rather than deleting
   and recreating. Nextcloud soft-deletes calendars to a trash bin,
   leaving a deleted-calendar resource at the same URL that blocks
   MKCALENDAR on the next run. Likewise, teardown_method now clears
   events instead of deleting the calendar, so the namespace stays free.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes required for TestSchedulingForServerDavical::testInviteAndRespond:

1. Enable scheduling in config: uncomment $c->enable_scheduling = true in
   /etc/davical/config.php — without it, DAViCal does not route iTIP
   invites between local users.

2. Set default_privileges on scheduling user principals to 7168 (bit mask
   for schedule-deliver: schedule-deliver-invite + schedule-deliver-reply
   + schedule-query-freebusy).  Users created via direct SQL INSERT do not
   get the default_privileges that DAViCal's web UI would apply, so the
   path_privs() DB function returns 0 for any cross-user access, causing
   the schedule-deliver-invite privilege check to fail silently and drop
   the invite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Baikal:
- Add user1-user3 (testpass1-3) to the committed Specific/db/db.sqlite
  with correct digesta1 hashes (md5(user:BaikalDAV:pass)) and principal
  entries. The docker.py comment claimed these were pre-seeded but they
  were not, causing 401 during check_scheduling_support().
- Rewrite setup_baikal.sh to actually verify/seed users rather than just
  printing instructions.

Zimbra:
- Zimbra processes scheduling asynchronously: immediately after PUT the
  attendee's inbox and calendars are empty, but within ~500ms the invite
  is delivered and auto-scheduled. Replace the single-shot inbox/calendar
  check with a polling loop (up to 5 s, 0.5 s steps) so the test does
  not fail spuriously on the first check.

Also adds testuser3 to Zimbra (was missing from the running container;
start.sh already creates it but it must not have been run recently).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant