test(e2e): webdav + nextcloud full e2e test coverage
add a full coverage of Webdav and Nextcloud
purpose: prepare move to Drives and ensure no regression at all
test scenarios are in docs/plan/BASELINE_TESTS_NC_WEBDAV.md
current existing bugs identified via these tests:
┌──────────┬─────────┬────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Bug │ Surface │ Pin location │
├──────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ G4/G5/K5 │ NC │ AlreadyExists → 500 instead of 412 (handle_move + trashbin restore) │
├──────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ G9 │ NC │ Folder DELETE not row-recursive — orphan descendants stay live │
├──────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ M5/M7 │ Native │ resolve_path_for_user mismatch — PUT writes, GET reads via lenient lookup, MOVE/DELETE can't find │
│ │ │ via strict │
├──────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ M8 │ Native │ COPY discards destination filename — collides with source │
├──────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ N2 │ Native │ LOCK creates the token, mutators don't check it — class-2 advertisement is aspirational │
└──────────┴─────────┴────────────────────────────────────────────────────────────────────────────────────────────────────┘
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# =============================================================
|
||||
# OxiCloud — Baseline: NC avatar + preview
|
||||
# =============================================================
|
||||
# Group L from BASELINE_TESTS_NC_WEBDAV.md (3 scenarios).
|
||||
#
|
||||
# All NC routes (including avatars and previews) sit behind the
|
||||
# `basic_auth_middleware` wired in `interfaces/nextcloud/
|
||||
# routes.rs:174`. Even though the avatar payload is described as
|
||||
# "decorative, not security-critical" in `avatar_handler.rs`,
|
||||
# the request itself still requires a valid Basic Auth identity.
|
||||
# Both L1 and L3 therefore mint an app password and pass it.
|
||||
#
|
||||
# L1 / L3 pin the avatar handler's actual contract: once
|
||||
# authenticated, it ALWAYS returns 200 — stored profile image
|
||||
# when present, SVG-with-initials otherwise (including for
|
||||
# users that don't exist at all).
|
||||
#
|
||||
# L2 hits the authenticated preview endpoint with a fake file
|
||||
# id and pins the not-found path. A positive-path preview test
|
||||
# would require seeding an image file and resolving its NC
|
||||
# numeric id, which is more setup than this baseline needs.
|
||||
# =============================================================
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Setup 1 — JWT login (gives us a Bearer token to mint the
|
||||
# app password used by the avatar Basic Auth + the
|
||||
# preview JWT auth).
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/auth/login
|
||||
Content-Type: application/json
|
||||
{ "username": "{{username}}", "password": "{{password}}" }
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
jwt: jsonpath "$.access_token"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Setup 2 — Mint an app password for the L1/L3 Basic Auth.
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/auth/app-passwords
|
||||
Authorization: Bearer {{jwt}}
|
||||
Content-Type: application/json
|
||||
{ "label": "nc_avatar_preview hurl test" }
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
nc_username: jsonpath "$.username"
|
||||
nc_password: jsonpath "$.password"
|
||||
ap_id: jsonpath "$.id"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# L1 — Avatar for an existing user (admin) always 200
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/index.php/avatar/{{username}}/64
|
||||
[BasicAuth]
|
||||
{{nc_username}}: {{nc_password}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" startsWith "image/"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# L3 — Avatar for a nonexistent user
|
||||
#
|
||||
# Pinned current behaviour: 200 with the SVG-initials fallback.
|
||||
# The handler explicitly comments "decorative, not security-
|
||||
# critical" — it never returns 404 for an unknown name; it
|
||||
# renders initials from whatever string the caller passed.
|
||||
# RFC strictness would suggest 404 here, but NC desktop / Web
|
||||
# UI happily render the SVG.
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/index.php/avatar/nonexistent-user-deadbeef/64
|
||||
[BasicAuth]
|
||||
{{nc_username}}: {{nc_password}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" startsWith "image/"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# L2 — Preview of a non-existent file id → 404
|
||||
#
|
||||
# fileId=99999999 is well below any real NC id we'd ever
|
||||
# assign, so this exercises the "file not found" branch
|
||||
# without depending on a seeded image fixture.
|
||||
#
|
||||
# Auth: same Basic Auth as L1/L3 — the NC `/index.php/*`
|
||||
# surface is uniformly behind `basic_auth_middleware`, so Bearer
|
||||
# JWT is rejected at the middleware boundary before the handler
|
||||
# even sees the request.
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/index.php/core/preview?fileId=99999999&x=128&y=128
|
||||
[BasicAuth]
|
||||
{{nc_username}}: {{nc_password}}
|
||||
|
||||
HTTP 404
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Teardown — revoke the app password.
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
DELETE {{base_url}}/api/auth/app-passwords/{{ap_id}}
|
||||
Authorization: Bearer {{jwt}}
|
||||
HTTP 200
|
||||
Reference in New Issue
Block a user