595273277b
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 │
└──────────┴─────────┴────────────────────────────────────────────────────────────────────────────────────────────────────┘
110 lines
5.3 KiB
Plaintext
110 lines
5.3 KiB
Plaintext
# =============================================================
|
|
# 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
|