# Testing the Calendar Skill End-to-end tests for send, reply, todo, calendar sync, and local calendar. All commands use `--dry-run` first, then live. ```bash SKILL_DIR=~/.openclaw/workspace/skills/calendar # Use a date 3 days from now for test events TEST_DATE=$(date -d "+3 days" +%Y-%m-%d) ``` --- ## 1. Dry Run: Send Invite Generates the ICS and MIME email without sending. Check that: - ICS has `METHOD:REQUEST` - MIME has `Content-Type: text/calendar; method=REQUEST` - Only `--to` recipients appear as attendees - Times and timezone look correct ```bash $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Test Invite" \ --summary "Test Event" \ --start "${TEST_DATE}T15:00:00" \ --end "${TEST_DATE}T16:00:00" \ --dry-run ``` ## 2. Live Send: Self-Invite Send a real invite to `mail@luyx.org` only (no confirmation needed per email rules). ```bash $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Calendar Skill Test" \ --summary "Calendar Skill Test" \ --start "${TEST_DATE}T15:00:00" \ --end "${TEST_DATE}T16:00:00" \ --location "Test Location" ``` **Verify:** - [ ] Script exits without error - [ ] Email arrives at `mail@luyx.org` - [ ] Email shows Accept/Decline/Tentative buttons (not just an attachment) - [ ] `.ics` file saved to `~/.openclaw/workspace/calendars/home/` ## 3. Verify Calendar Sync and Local Calendar After sending in step 2, check that the event synced and appears locally. ```bash # Check vdirsyncer sync ran (should have printed "Synced to CalDAV server" in step 2) # If not, run manually: vdirsyncer sync # List .ics files in local calendar ls ~/.openclaw/workspace/calendars/home/ # Check the event shows up in khal khal list "$TEST_DATE" ``` **Verify:** - [ ] `vdirsyncer sync` completes without errors - [ ] `.ics` file exists in `~/.openclaw/workspace/calendars/home/` - [ ] `khal list` shows "Calendar Skill Test" on the test date ## 4. Reply: Accept the Self-Invite The invite sent in step 2 should be in the inbox. Find it, then accept it. This tests the full reply flow without needing an external sender. ```bash # Find the test invite in inbox himalaya envelope list # Confirm it's the calendar invite himalaya message read # Accept it $SKILL_DIR/scripts/calendar.sh reply \ --envelope-id \ --action accept ``` **Verify:** - [ ] Reply sent to organizer (youlu@luyanxin.com, i.e. ourselves) - [ ] Event saved to `~/.openclaw/workspace/calendars/home/` - [ ] `vdirsyncer sync` ran - [ ] `khal list "$TEST_DATE"` still shows the event ## 5. Reply: Decline an Invite Send another self-invite, then decline it. This verifies decline removes the event from local calendar. ```bash # Send a second test invite $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Decline Test" \ --summary "Decline Test Event" \ --start "${TEST_DATE}T17:00:00" \ --end "${TEST_DATE}T18:00:00" # Find it in inbox himalaya envelope list # Decline it $SKILL_DIR/scripts/calendar.sh reply \ --envelope-id \ --action decline \ --comment "Testing decline flow." ``` **Verify:** - [ ] Reply sent to organizer with comment - [ ] Event removed from local calendar - [ ] `khal list "$TEST_DATE"` does NOT show "Decline Test Event" ## 6. Verify Final Calendar State After all tests, confirm the calendar is in a clean state. ```bash # Sync one more time vdirsyncer sync # Only the accepted event should remain khal list "$TEST_DATE" # List all upcoming events khal list today 7d ``` --- ## 7. Dry Run: Add Todo Generates the VTODO ICS without saving. Check that: - ICS has `BEGIN:VTODO` - ICS has correct `PRIORITY` value (1 for high) - ICS has `STATUS:NEEDS-ACTION` - ICS has `BEGIN:VALARM` ```bash $SKILL_DIR/scripts/calendar.sh todo add \ --summary "Test Todo" \ --due "$TEST_DATE" \ --priority high \ --dry-run ``` ## 8. Live Add: Create a Todo ```bash $SKILL_DIR/scripts/calendar.sh todo add \ --summary "Test Todo" \ --due "$TEST_DATE" \ --priority medium \ --description "Test description" ``` **Verify:** - [ ] Script exits without error - [ ] `.ics` file created in `~/.openclaw/workspace/calendars/tasks/` - [ ] `todo list` (todoman directly) shows "Test Todo" - [ ] `vdirsyncer sync` ran ## 9. List Todos ```bash # Via our wrapper (formatted Chinese output) $SKILL_DIR/scripts/calendar.sh todo list # Via todoman directly (should show the same items) todo list # Include completed $SKILL_DIR/scripts/calendar.sh todo list --all ``` **Verify:** - [ ] "Test Todo" appears in both outputs - [ ] Priority grouping is correct in wrapper output - [ ] `--all` flag works (same output when none are completed) ## 10. Edit a Todo Change the due date and priority of the test todo from step 8. ```bash # Edit due date $SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --due "$(date -d '+5 days' +%Y-%m-%d)" # Verify change $SKILL_DIR/scripts/calendar.sh todo list ``` **Verify:** - [ ] Script exits without error - [ ] Output shows "Updated todo: Test Todo" with the change - [ ] `todo list` shows the new due date - [ ] `vdirsyncer sync` ran ```bash # Edit priority $SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --priority high # Verify change $SKILL_DIR/scripts/calendar.sh todo list ``` **Verify:** - [ ] Priority changed to high - [ ] Todo appears under the high priority group in formatted output ```bash # Edit multiple fields at once $SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --due "$TEST_DATE" --priority low ``` **Verify:** - [ ] Both due date and priority updated in one command ```bash # Error: no matching todo $SKILL_DIR/scripts/calendar.sh todo edit --match "nonexistent" --due "$TEST_DATE" # Should print error and exit non-zero # Error: no fields to edit $SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" # Should print "Nothing to change" message ``` ## 11. Complete a Todo ```bash $SKILL_DIR/scripts/calendar.sh todo complete --match "Test Todo" ``` **Verify:** - [ ] `todo list` (todoman) — "Test Todo" no longer appears - [ ] `$SKILL_DIR/scripts/calendar.sh todo list` — also gone - [ ] `$SKILL_DIR/scripts/calendar.sh todo list --all` — appears as completed (with checkmark) - [ ] `vdirsyncer sync` ran ## 12. Delete a Todo Create a second test todo, then delete it. ```bash # Create $SKILL_DIR/scripts/calendar.sh todo add \ --summary "Delete Me Todo" \ --due "$TEST_DATE" \ --priority low # Confirm it appears todo list # Delete $SKILL_DIR/scripts/calendar.sh todo delete --match "Delete Me" ``` **Verify:** - [ ] .ics file removed from tasks dir - [ ] `todo list` (todoman) does not show "Delete Me Todo" - [ ] `vdirsyncer sync` ran ## 13. Todo Check (Cron Output) ```bash # Create a test todo $SKILL_DIR/scripts/calendar.sh todo add \ --summary "Check Test Todo" \ --due "$TEST_DATE" # Run check $SKILL_DIR/scripts/calendar.sh todo check ``` **Verify:** - [ ] Output matches daily digest format (priority groups, urgency labels) - [ ] Complete the todo, run `todo check` again — silent exit (no output) ```bash $SKILL_DIR/scripts/calendar.sh todo complete --match "Check Test" $SKILL_DIR/scripts/calendar.sh todo check # Should produce no output ``` ## 14. Dry Run: Recurring Event (--rrule) Test recurring event generation. Use a date that falls on a Tuesday. ```bash # Find next Tuesday NEXT_TUE=$(python3 -c "from datetime import date,timedelta; d=date.today(); d+=timedelta((1-d.weekday())%7 or 7); print(d)") $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Recurring Test (Tue)" \ --summary "Recurring Test (Tue)" \ --start "${NEXT_TUE}T14:30:00" \ --end "${NEXT_TUE}T15:00:00" \ --rrule "FREQ=WEEKLY;COUNT=4;BYDAY=TU" \ --dry-run ``` **Verify:** - [ ] ICS has `RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=4` - [ ] DTSTART falls on a Tuesday - [ ] No validation errors ## 15. Validation: DTSTART/BYDAY Mismatch Verify the tool rejects mismatched DTSTART and BYDAY. ```bash # This should FAIL — start is on a Tuesday but BYDAY=TH $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Mismatch Test" \ --summary "Mismatch Test" \ --start "${NEXT_TUE}T09:00:00" \ --end "${NEXT_TUE}T09:30:00" \ --rrule "FREQ=WEEKLY;COUNT=4;BYDAY=TH" \ --dry-run ``` **Verify:** - [ ] Script exits with error - [ ] Error message says DTSTART falls on TU but RRULE says BYDAY=TH - [ ] Suggests changing --start to a date that falls on TH ## 16. Event List ```bash # List upcoming events $SKILL_DIR/scripts/calendar.sh event list # Search by text $SKILL_DIR/scripts/calendar.sh event list --search "Calendar Skill Test" # List with UIDs $SKILL_DIR/scripts/calendar.sh event list --format "{uid} {title}" ``` **Verify:** - [ ] Events from earlier tests appear - [ ] Search narrows results correctly - [ ] UIDs are displayed with --format ## 17. Event Delete ```bash # Send a throwaway event first $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "Delete Me Event" \ --summary "Delete Me Event" \ --start "${TEST_DATE}T20:00:00" \ --end "${TEST_DATE}T21:00:00" # Verify it exists $SKILL_DIR/scripts/calendar.sh event list --search "Delete Me" # Delete it $SKILL_DIR/scripts/calendar.sh event delete --match "Delete Me Event" # Verify it's gone $SKILL_DIR/scripts/calendar.sh event list --search "Delete Me" ``` **Verify:** - [ ] Event is created and visible - [ ] Delete removes exactly one event - [ ] Other events are untouched - [ ] `vdirsyncer sync` ran after delete ## 18. Event Delete: Cancel Single Occurrence (EXDATE) Test that `--date` cancels one occurrence of a recurring event without deleting the series. ```bash # Create a recurring event (weekly on Saturday, 4 weeks) NEXT_SAT=$(python3 -c "from datetime import date,timedelta; d=date.today(); d+=timedelta((5-d.weekday())%7 or 7); print(d)") $SKILL_DIR/scripts/calendar.sh send \ --to "mail@luyx.org" \ --subject "EXDATE Test (Sat)" \ --summary "EXDATE Test (Sat)" \ --start "${NEXT_SAT}T10:00:00" \ --end "${NEXT_SAT}T11:00:00" \ --rrule "FREQ=WEEKLY;COUNT=4;BYDAY=SA" # Verify it exists $SKILL_DIR/scripts/calendar.sh event list --search "EXDATE Test" # Cancel just the first occurrence $SKILL_DIR/scripts/calendar.sh event delete --match "EXDATE Test" --date "$NEXT_SAT" # Verify: .ics file still exists (not deleted) ls ~/.openclaw/workspace/calendars/home/ | grep -i exdate ``` **Verify:** - [ ] `event delete --match ... --date ...` prints "Cancelled ... (added EXDATE, series continues)" - [ ] `.ics` file still exists in calendar dir - [ ] `khal list` no longer shows the cancelled date but shows subsequent Saturdays ## 19. Event Delete: Recurring Without --date or --all (Safety Guard) ```bash # Try to delete the recurring event without --date or --all — should FAIL $SKILL_DIR/scripts/calendar.sh event delete --match "EXDATE Test" ``` **Verify:** - [ ] Script exits with error - [ ] Error message explains the two options: `--date` or `--all` ## 20. Event Delete: Recurring With --all ```bash # Delete the entire series $SKILL_DIR/scripts/calendar.sh event delete --match "EXDATE Test" --all ``` **Verify:** - [ ] .ics file is removed - [ ] `event list --search "EXDATE Test"` shows nothing ## 21. Regression: Existing Invite Commands (was #18) Verify new features didn't break VEVENT flow. ```bash $SKILL_DIR/scripts/calendar.sh send \ --to "test@example.com" \ --subject "Regression Test" \ --summary "Regression Test Event" \ --start "${TEST_DATE}T10:00:00" \ --end "${TEST_DATE}T11:00:00" \ --dry-run ``` **Verify:** - [ ] ICS has `BEGIN:VEVENT`, `METHOD:REQUEST` - [ ] No RRULE present (single event) - [ ] No errors --- ## Quick Health Checks Run these first if any step fails. ```bash # icalendar library is available uv run --project $SKILL_DIR python -c "import icalendar; print('ok')" # himalaya can list emails himalaya envelope list --page-size 5 # vdirsyncer can sync vdirsyncer sync # khal can read local calendar khal list today 7d # todoman can list todos todo list ``` ## Common Failures | Symptom | Likely Cause | |---------|-------------| | `himalaya message send` errors | SMTP config issue, check `~/.config/himalaya/config.toml` | | No `.ics` attachment found | Email doesn't have a calendar invite, or himalaya can't download attachments | | `vdirsyncer sync` fails | Check credentials in `~/.config/vdirsyncer/config`, or server is unreachable | | `ModuleNotFoundError: icalendar` | Run `uv sync --project $SKILL_DIR` to install dependencies | | Invite shows as attachment (no Accept/Decline) | Check MIME `Content-Type` includes `method=REQUEST` | | Event not in `khal list` after sync | Check `.ics` file exists in `~/.openclaw/workspace/calendars/home/` | | `todo` command not found | Install with `uv tool install todoman` | | `todo list` errors | Check `~/.config/todoman/config.py` exists and `path` points to tasks dir | | Todo not syncing | Check `~/.openclaw/workspace/calendars/tasks/` exists, verify vdirsyncer `cal/tasks` pair | | DTSTART/BYDAY mismatch error | `--start` date doesn't fall on the BYDAY day. Change the start date to match | | Recurring events on wrong day | DTSTART was not aligned with BYDAY. Delete the event and resend with correct `--start` | | SMTP rate limit / EOF error | Too many sends too fast. Wait 10+ seconds between sends (Migadu limit) | | Events disappeared after cleanup | **Never use `rm *.ics`** on calendar dirs. Use `event delete --match` instead | | Recurring series deleted when cancelling one date | Use `--date YYYY-MM-DD` to add EXDATE, not bare `event delete` (which requires `--all` for recurring) |