Files
Oxicloud/tests/api/webdav_nested_move_cascade.hurl
T

165 lines
8.7 KiB
Plaintext
Raw Normal View History

2026-06-30 22:55:44 +02:00
# =============================================================
# OxiCloud — WebDAV: nested-folder MOVE descendant cascade
# =============================================================
# Regression guard for the litmus `copymove → move_coll`
# scenario: when a parent folder is renamed (or moved), every
# DESCENDANT folder row must have its `path` / `lpath` columns
# rewritten by the AFTER cascade trigger
# `trg_folders_cascade_path` so that path-keyed lookups
# (WebDAV, CalDAV, CardDAV, and a handful of REST endpoints)
# resolve the descendant at its new location.
#
# Why this needs a dedicated test:
# * REST API tests overwhelmingly use folder IDs, not paths —
# a stale `folders.path` column is invisible to `WHERE id =
# $1` lookups. So they can't catch this regression even when
# they MOVE.
# * Existing WebDAV tests are flat: MOVE a file, or MKCOL +
# DELETE on a single-level folder. None combine "MOVE a
# folder that has folder descendants" with "look the
# descendant up by its post-move path".
# * litmus's `copymove → move_coll` IS this test, but litmus
# isn't installed on every contributor's machine — it lives
# on the CI side only. This Hurl scenario runs in every
# standard `just api-test`.
#
# Bug shape it catches: the `UPDATE OF <cols>` column list on
# `trg_folders_cascade_path` must include `name` AND `parent_id`
# (not just `path, lpath, drive_id`) — otherwise the AFTER
# trigger never fires on the rename SQL `UPDATE folders SET
# name = $1` or the move SQL `UPDATE folders SET parent_id =
# $1`, descendant rows stay at their pre-move path, and any
# subsequent path-keyed lookup of a descendant returns 404.
#
# What this test does:
# 1. Login (admin).
# 2. MKCOL /webdav/regress-cascade-a/
# 3. MKCOL /webdav/regress-cascade-a/b/ (descendant folder)
# 4. PUT /webdav/regress-cascade-a/b/leaf.txt (leaf file)
# 5. MOVE /webdav/regress-cascade-a/ → /webdav/regress-cascade-c/
# 6. DELETE /webdav/regress-cascade-c/b/leaf.txt ← path-based file
# lookup at the
# new descendant
# location
# 7. DELETE /webdav/regress-cascade-c/b/ ← path-based
# descendant
# folder lookup
# (this is the
# one that 404s
# when the bug
# is present)
# 8. DELETE /webdav/regress-cascade-c/ (cleanup root)
#
# Steps 6 and 7 are the load-bearing assertions; without the
# cascade, the descendant's `path` column is still
# `Personal/regress-cascade-a/b` and both DELETEs return 404.
# =============================================================
# ─────────────────────────────────────────────────────────────
# Step 1 — Login, capture JWT.
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/auth/login
Content-Type: application/json
{ "username": "{{username}}", "password": "{{password}}" }
HTTP 200
[Captures]
token: jsonpath "$.access_token"
# ─────────────────────────────────────────────────────────────
# Step 2 — MKCOL the parent collection. Fresh names; 201 expected.
# ─────────────────────────────────────────────────────────────
MKCOL {{base_url}}/webdav/regress-cascade-a/
Authorization: Bearer {{token}}
HTTP 201
# ─────────────────────────────────────────────────────────────
# Step 3 — MKCOL the descendant collection inside the parent.
# This is the folder row whose `path` column the
# cascade trigger must rewrite when the parent is
# renamed in Step 5.
# ─────────────────────────────────────────────────────────────
MKCOL {{base_url}}/webdav/regress-cascade-a/b/
Authorization: Bearer {{token}}
HTTP 201
# ─────────────────────────────────────────────────────────────
# Step 4 — PUT a leaf file inside the descendant. We use it in
# Step 6 to verify the post-move file lookup works
# (files resolve via their parent folder's `path`, so
# this branch caught fire too when the cascade was
# broken — even though `storage.files` has no `path`
# column of its own).
# ─────────────────────────────────────────────────────────────
PUT {{base_url}}/webdav/regress-cascade-a/b/leaf.txt
Authorization: Bearer {{token}}
Content-Type: text/plain
```
nested cascade regression probe
```
HTTP 201
# ─────────────────────────────────────────────────────────────
# Step 5 — MOVE the parent collection. The SQL the service
# issues is `UPDATE storage.folders SET name = $1, ...`
# on the parent row (intra-drive same-parent rename).
# The BEFORE trigger `trg_folders_path` rewrites the
# parent's own `path`; the AFTER trigger
# `trg_folders_cascade_path` must fire to rewrite
# every descendant folder's `path` / `lpath`.
#
# RFC 4918 §9.9.4: destination is fresh → 201 Created.
# ─────────────────────────────────────────────────────────────
MOVE {{base_url}}/webdav/regress-cascade-a/
Authorization: Bearer {{token}}
Destination: {{base_url}}/webdav/regress-cascade-c/
HTTP 201
# ─────────────────────────────────────────────────────────────
# Step 6 — Resolve the leaf FILE by its post-move path. The
# DELETE handler's resolver joins `storage.files`
# against `storage.folders` on `folder_id`, then
# filters `fo.path = 'Personal/regress-cascade-c/b'`.
# That match depends on the descendant folder's
# `path` column having been cascade-rewritten in
# Step 5.
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/webdav/regress-cascade-c/b/leaf.txt
Authorization: Bearer {{token}}
HTTP 204
# ─────────────────────────────────────────────────────────────
# Step 7 — Resolve the descendant FOLDER by its post-move path.
# This is the assertion that was failing as litmus
# test 10. Lookup SQL: `SELECT … FROM storage.folders
# WHERE path = 'Personal/regress-cascade-c/b' …`.
# Without the cascade, the row still has path
# `Personal/regress-cascade-a/b` → 0 rows → 404.
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/webdav/regress-cascade-c/b/
Authorization: Bearer {{token}}
HTTP 204
# ─────────────────────────────────────────────────────────────
# Step 8 — Cleanup: DELETE the moved root so subsequent test
# runs start clean even on a non-pristine DB.
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/webdav/regress-cascade-c/
Authorization: Bearer {{token}}
HTTP 204