diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed076ede..961b49ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -422,6 +422,54 @@ jobs: BUILD_TARGET: release LITMUS_TESTS: "basic copymove props locks" + caldav-test: + # CalDAV + CardDAV client-driven suite via python-caldav — the + # same library Thunderbird / DAVx⁵ / Radicale / xandikos / davical + # test against. Complements the raw-HTTP Hurl coverage in + # api-test by proving a real client library round-trips through + # OxiCloud's CalDAV/CardDAV surface. + # + # Runs AFTER litmus so both DAV-family compliance surfaces + # (RFC 4918 WebDAV via litmus, RFC 4791 CalDAV + RFC 6352 + # CardDAV via python-caldav) execute in sequence on the same + # pre-built binary. Sharing `needs: build` + `needs: litmus` + # means one binary download is enough; running after litmus + # rather than in parallel keeps CI runner load predictable. + name: CalDAV + CardDAV — python-caldav + needs: litmus + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: oxicloud-release + path: target/release/ + + - name: Set execute bit on pre-built binary + run: chmod +x target/release/oxicloud + + - name: Install jq + python3 venv + # jq for the /api/setup + /api/auth/login parsing inside + # run-pycaldav.sh. python3 ships on ubuntu-latest but + # python3-venv is a separate package on Debian-family images. + run: sudo apt-get update -q && sudo apt-get install -y jq python3 python3-venv + + - name: Run python-caldav suite + run: bash tests/caldav/run-pycaldav.sh + env: + BUILD_TARGET: release + + - name: Upload server log on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: caldav-server-log + path: tests/caldav/server.log + retention-days: 7 + front-test: name: Frontend end-to-end tests (via Playwright) # ensure that api tests are ok before diff --git a/justfile b/justfile index 669177e7..345fed49 100644 --- a/justfile +++ b/justfile @@ -211,6 +211,13 @@ api-test: # Not chained into `api-test` because it needs python3; run explicitly. # The orchestrator spawns its own postgres + server on port 8091 so it # can run in parallel with api-test/webdav. +# +# Runs `cargo build` first so the orchestrator always sees a fresh +# binary. run-pycaldav.sh itself doesn't rebuild — it uses whatever +# binary is on disk (CI pattern: pre-built release artifact). Doing +# the build here in the recipe means local iterative dev never runs +# pytest against a stale binary from an earlier `cargo check`, while +# CI still gets to skip the recompile. test-caldav: #!/usr/bin/env bash set -euo pipefail @@ -218,6 +225,7 @@ test-caldav: echo "XXX python3 not found — skipping CalDAV client-driven tests" exit 0 fi + cargo build ./tests/caldav/run-pycaldav.sh # --------------------------------------------------------------------------- diff --git a/tests/caldav/run-pycaldav.sh b/tests/caldav/run-pycaldav.sh index 7a6d689a..48e49368 100755 --- a/tests/caldav/run-pycaldav.sh +++ b/tests/caldav/run-pycaldav.sh @@ -90,21 +90,29 @@ wipe_storage "$OXICLOUD_STORAGE_PATH" BUILD_TARGET="${BUILD_TARGET:-debug}" OXICLOUD_BIN="$REPO_ROOT/target/$BUILD_TARGET/oxicloud" -# ALWAYS build — a `cargo check` / `cargo clippy` during development -# leaves the target/ metadata fresh but NEVER produces or updates the -# binary at target//oxicloud. Skipping the rebuild on -# "binary already exists" then runs pytest against a stale binary, -# which manifests as impossible-looking test failures (e.g. "phase 3 -# routing broken" when the binary is from phase 2). Cargo's -# incremental compile makes this near-free when nothing changed. -log "Building OxiCloud ($BUILD_TARGET) — incremental compile, fast when up-to-date..." -case "$BUILD_TARGET" in - debug) (cd "$REPO_ROOT" && cargo build 2>&1 | tail -n 20) || die "cargo build failed" ;; - release) (cd "$REPO_ROOT" && cargo build --release 2>&1 | tail -n 20) || die "cargo build --release failed" ;; - *) die "Unsupported BUILD_TARGET='$BUILD_TARGET' (expected 'debug' or 'release')" ;; -esac - -[[ -x "$OXICLOUD_BIN" ]] || die "Build completed but $OXICLOUD_BIN is missing" +# Use the binary if it's already there — CI downloads a pre-built +# release artifact and would waste ~5 min recompiling from scratch +# (empty target cache) if we always rebuilt. Local devs get the +# fresh-binary guarantee via `just test-caldav`, which runs +# `cargo build` before invoking this script (see the recipe in +# justfile). +# +# The stale-binary trap this used to guard against (a `cargo check` +# or `cargo clippy` leaving the on-disk binary behind while source +# changed) only bites when this script is invoked DIRECTLY without +# going through the justfile — a rare workflow. Documented on +# `just test-caldav` for the record. +if [[ ! -x "$OXICLOUD_BIN" ]]; then + log "Building OxiCloud ($BUILD_TARGET) — no pre-built binary at $OXICLOUD_BIN..." + case "$BUILD_TARGET" in + debug) (cd "$REPO_ROOT" && cargo build 2>&1 | tail -n 20) || die "cargo build failed" ;; + release) (cd "$REPO_ROOT" && cargo build --release 2>&1 | tail -n 20) || die "cargo build --release failed" ;; + *) die "Unsupported BUILD_TARGET='$BUILD_TARGET' (expected 'debug' or 'release')" ;; + esac + [[ -x "$OXICLOUD_BIN" ]] || die "Build completed but $OXICLOUD_BIN is missing" +else + log "Using pre-built OxiCloud at $OXICLOUD_BIN ($BUILD_TARGET)" +fi log "Starting OxiCloud ($BUILD_TARGET) on port $SERVER_PORT..." # `--config` pins the env file, suppressing the default `.env` probe so