Files
Oxicloud/tests/webdav/test_thumbnail_update.sh
T
2026-05-13 15:55:34 +02:00

237 lines
9.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# =============================================================
# OxiCloud – Bug 1 & 2: thumbnail refresh after WebDAV PUT
# =============================================================
# Bug 1: stale moka cache served after blob swap (overwrite)
# Bug 2: no background thumbnail generation after update
#
# Fix (webdav_handler.rs handle_put): after update branch,
# refresh_thumbnails_after_update() calls delete_thumbnails()
# (evicts moka) then spawns background regen from new blob.
#
# Test strategy:
# 1. PUT dedup-test.jpg via /webdav → thumbnail generated
# 2. Prime the moka cache with GET /thumbnail
# 3. PUT oxicloud-logo.jpg to the same path (overwrite)
# 4. GET /thumbnail again → must return different bytes
#
# Bug 1 detection: if moka is not evicted, step 4 returns the
# cached dedup-test thumbnail → SHA-256 matches step 2 → test fails.
#
# Prerequisites:
# - Server running at base_url with credentials from test.env
# - OXICLOUD_ENABLE_AUTH=true (/webdav uses JWT Bearer auth)
# - jq in PATH
#
# Run (from repo root):
# bash tests/webdav/test_thumbnail_update.sh
# =============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$SCRIPT_DIR"
source test.env
source common.sh
# ── helpers ──────────────────────────────────────────────────
PASS=0
FAIL=0
pass() { PASS=$(( PASS + 1 )); echo " PASS: $*"; }
fail() { FAIL=$(( FAIL + 1 )); echo " FAIL: $*" >&2; exit 1; }
# WebDAV PUT: returns HTTP status code
webdav_put() {
local remote_name="$1" local_file="$2" mime="${3:-application/octet-stream}"
curl -s -o /dev/null -w "%{http_code}" \
-X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: $mime" \
--data-binary "@$local_file" \
"$base_url/webdav/$remote_name"
}
# WebDAV DELETE: returns HTTP status code
webdav_delete() {
local remote_name="$1"
curl -s -o /dev/null -w "%{http_code}" \
-X DELETE \
-H "Authorization: Bearer $TOKEN" \
"$base_url/webdav/$remote_name"
}
# REST GET with JWT bearer
rest_get() {
curl -s \
-H "Authorization: Bearer $TOKEN" \
"$base_url$1"
}
# REST DELETE with JWT bearer, returns HTTP status code
rest_delete() {
curl -s -o /dev/null -w "%{http_code}" \
-X DELETE \
-H "Authorization: Bearer $TOKEN" \
"$base_url$1"
}
# Download thumbnail and return its SHA-256 checksum
thumbnail_sha256() {
local file_id="$1"
curl -s \
-H "Authorization: Bearer $TOKEN" \
"$base_url/api/files/$file_id/thumbnail/icon" \
| sha256sum | cut -d' ' -f1
}
# SHA-256 of an empty stream (thumbnail missing = empty body)
EMPTY_SHA="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
FIXTURE_V1="$REPO_ROOT/tests/fixtures/dedup-test.jpg"
FIXTURE_V2="$REPO_ROOT/tests/fixtures/oxicloud-logo.jpg"
[[ -f "$FIXTURE_V1" ]] || { echo "Missing fixture: $FIXTURE_V1" >&2; exit 1; }
[[ -f "$FIXTURE_V2" ]] || { echo "Missing fixture: $FIXTURE_V2" >&2; exit 1; }
echo
echo "=== Bug 1 & 2: thumbnail refresh after WebDAV PUT overwrite ==="
echo
# ── authenticate ─────────────────────────────────────────────
oxicloud_login
# ── home folder ID ────────────────────────────────────────────
echo " home folder..."
HOME_FOLDER_ID=$(rest_get "/api/folders" | jq -r '.[0].id')
[[ -n "$HOME_FOLDER_ID" && "$HOME_FOLDER_ID" != "null" ]] \
|| fail "Could not retrieve home folder ID"
echo " home folder id: $HOME_FOLDER_ID"
REMOTE="webdav-thumb-bug12.jpg"
# ── Pre-test cleanup (idempotent) ─────────────────────────────
# Remove any leftover from a previous run via the REST API so that
# the first WebDAV PUT below is guaranteed to be a CREATE (201).
echo " cleanup: checking regular listing for '$REMOTE'..."
EXISTING_ID=$(rest_get "/api/files?folder_id=$HOME_FOLDER_ID" \
| jq -r --arg n "$REMOTE" 'first(.[] | select(.name == $n) | .id) // empty')
if [[ -n "$EXISTING_ID" ]]; then
echo " cleanup: found existing file id=$EXISTING_ID — deleting..."
ST=$(rest_delete "/api/files/$EXISTING_ID")
echo " cleanup: DELETE /api/files/$EXISTING_ID → $ST"
else
echo " cleanup: no existing file in regular listing"
fi
echo " cleanup: checking trash for '$REMOTE'..."
STALE=$(rest_get "/api/trash" \
| jq -r --arg n "$REMOTE" 'first(.[] | select(.name == $n) | .id) // empty')
if [[ -n "$STALE" ]]; then
echo " cleanup: found trash item id=$STALE — purging..."
ST=$(rest_delete "/api/trash/$STALE")
echo " cleanup: DELETE /api/trash/$STALE → $ST"
else
echo " cleanup: trash is clean"
fi
# ── Step 1: PUT dedup-test.jpg ───────────────────────────────
# /webdav always returns 204 (update_file_streaming handles create+update)
echo " step 1: PUT $REMOTE..."
STATUS=$(webdav_put "$REMOTE" "$FIXTURE_V1" "image/jpeg")
echo " step 1: WebDAV PUT → $STATUS"
[[ "$STATUS" == "204" ]] || fail "WebDAV PUT expected 204, got $STATUS"
pass "WebDAV PUT dedup-test.jpg → 204"
# ── find file_id from REST listing ───────────────────────────
echo " step 1: resolving file_id..."
FILE_ID=$(rest_get "/api/files?folder_id=$HOME_FOLDER_ID" \
| jq -r --arg n "$REMOTE" '.[] | select(.name == $n) | .id')
[[ -n "$FILE_ID" && "$FILE_ID" != "null" ]] \
|| fail "File '$REMOTE' not found in folder listing after WebDAV PUT"
pass "File found via REST API — id=$FILE_ID"
# ── Step 2: GET thumbnail to prime moka cache ────────────────
# Background generation may still be running; wait briefly.
echo " step 2: waiting 1s for background thumbnail generation..."
sleep 1
echo " step 2: GET /thumbnail/icon..."
HTTP=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"$base_url/api/files/$FILE_ID/thumbnail/icon")
echo " step 2: GET /thumbnail → $HTTP"
[[ "$HTTP" == "200" ]] \
|| fail "GET /thumbnail after initial upload expected 200, got $HTTP"
THUMB_V1=$(thumbnail_sha256 "$FILE_ID")
echo " step 2: thumbnail sha256=$THUMB_V1"
[[ -n "$THUMB_V1" && "$THUMB_V1" != "$EMPTY_SHA" ]] \
|| fail "Thumbnail after initial upload is empty (sha256=$THUMB_V1)"
pass "Initial thumbnail present and non-empty (sha256=$THUMB_V1)"
# ── Step 3: PUT oxicloud-logo.jpg (overwrite) ────────────────
echo " step 3: PUT $REMOTE (overwrite)..."
STATUS=$(webdav_put "$REMOTE" "$FIXTURE_V2" "image/jpeg")
echo " step 3: WebDAV PUT → $STATUS"
[[ "$STATUS" == "204" ]] || fail "WebDAV PUT (overwrite) expected 204, got $STATUS"
pass "WebDAV PUT oxicloud-logo.jpg overwrite → 204 No Content"
# ── Step 4: GET thumbnail after overwrite ────────────────────
# Fix: delete_thumbnails() evicts moka (bug 1),
# background regen populates new blob thumbnail (bug 2).
# Without the fix the stale dedup-test thumbnail is served from moka.
echo " step 4: waiting 1s for background thumbnail regeneration..."
sleep 1
echo " step 4: GET /thumbnail/icon after overwrite..."
HTTP=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"$base_url/api/files/$FILE_ID/thumbnail/icon")
echo " step 4: GET /thumbnail → $HTTP"
[[ "$HTTP" == "200" ]] \
|| fail "GET /thumbnail after overwrite expected 200, got $HTTP"
THUMB_V2=$(thumbnail_sha256 "$FILE_ID")
echo " step 4: thumbnail sha256=$THUMB_V2"
[[ -n "$THUMB_V2" && "$THUMB_V2" != "$EMPTY_SHA" ]] \
|| fail "Thumbnail after overwrite is empty"
[[ "$THUMB_V1" != "$THUMB_V2" ]] \
|| fail "Bug 1 present: moka cache not evicted — thumbnail unchanged after overwrite (sha256=$THUMB_V1)"
pass "Thumbnail changed after overwrite — bugs 1 & 2 fixed (sha256=$THUMB_V2)"
# ── cleanup ───────────────────────────────────────────────────
echo " cleanup: WebDAV DELETE $REMOTE..."
STATUS=$(webdav_delete "$REMOTE")
echo " cleanup: WebDAV DELETE → $STATUS"
[[ "$STATUS" == "204" ]] || fail "WebDAV DELETE expected 204, got $STATUS"
pass "WebDAV DELETE → 204"
TRASH_ITEM=$(rest_get "/api/trash" \
| jq -r --arg n "$REMOTE" '.[] | select(.name == $n) | .id // empty')
if [[ -n "$TRASH_ITEM" ]]; then
ST=$(rest_delete "/api/trash/$TRASH_ITEM")
echo " cleanup: DELETE /api/trash/$TRASH_ITEM → $ST"
pass "Permanently deleted from trash"
fi
# ── summary ───────────────────────────────────────────────────
echo
echo "Results: $PASS passed, $FAIL failed."
[[ "$FAIL" -eq 0 ]] && echo "All tests passed." || exit 1