test(hash_content): check that hash matches
This commit is contained in:
@@ -90,6 +90,12 @@ file1_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
jsonpath "$.name" == "dedup-test.jpg"
|
||||
jsonpath "$.folder_id" == {{test_folder_id}}
|
||||
# Cross-check that the server's view of the uploaded content matches
|
||||
# the BLAKE3 we computed locally over fixtures/dedup-test.jpg. The
|
||||
# `content_hash` field is the raw blob hash, distinct from `etag`
|
||||
# (which folds in modified_at) — exposed in REST JSON by the
|
||||
# etag-centralization refactor.
|
||||
jsonpath "$.content_hash" == "cde1ca663a2e62e0dadb41c3194e11ecb7d971d84c7451db17063b55c09e8066"
|
||||
|
||||
|
||||
# ref_count == 1: blob has exactly one file reference after first upload
|
||||
@@ -118,6 +124,10 @@ file2_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
jsonpath "$.name" == "dedup-test-2.jpg"
|
||||
jsonpath "$.id" != "{{file1_id}}"
|
||||
# Same content as fixtures/dedup-test.jpg → identical content_hash.
|
||||
# This is the actual "dedup happened" assertion at the API surface,
|
||||
# independent of the /api/dedup/check probe below.
|
||||
jsonpath "$.content_hash" == "cde1ca663a2e62e0dadb41c3194e11ecb7d971d84c7451db17063b55c09e8066"
|
||||
|
||||
|
||||
# ref_count == 2: dedup hit — same blob now referenced by two file records
|
||||
|
||||
@@ -146,6 +146,18 @@ MIME=$(jq -r '.mime_type' <<< "$LISTED_FILE")
|
||||
|| fail "Expected MIME type video/mp4, got: $MIME"
|
||||
pass "File listed with MIME type: $MIME"
|
||||
|
||||
# ── Step 4b: server's content_hash matches our local BLAKE3 ──────────────────
|
||||
# Cross-check the file we just uploaded: the server's view of its
|
||||
# content identity (FileDto.content_hash, exposed in REST JSON since
|
||||
# the etag-centralization refactor) must equal the BLAKE3 we know
|
||||
# the fixture has. Catches any chunk-assembly bug that would
|
||||
# silently produce a different blob than the source bytes.
|
||||
|
||||
LISTED_HASH=$(jq -r '.content_hash // empty' <<< "$LISTED_FILE")
|
||||
[[ "$LISTED_HASH" == "$BLOB_HASH" ]] \
|
||||
|| fail "content_hash mismatch: server=$LISTED_HASH expected=$BLOB_HASH"
|
||||
pass "content_hash matches local BLAKE3 ($BLOB_HASH)"
|
||||
|
||||
# ── Step 5: Dedup check → ref_count == 1 ─────────────────────────────────────
|
||||
|
||||
echo " step 5: GET /api/dedup/check/$BLOB_HASH..."
|
||||
|
||||
@@ -141,6 +141,22 @@ FILE_B_ID=$(jq -r --arg n "$FILE_B" '.[] | select(.name == $n) | .id' <<< "$LIST
|
||||
|| fail "File A and B share the same ID — dedup must create two distinct records"
|
||||
pass "Two distinct file records: A=$FILE_A_ID B=$FILE_B_ID"
|
||||
|
||||
# ── Step 2b: server's content_hash matches our local BLAKE3 for both ─────────
|
||||
# Both files were uploaded from byte-identical bytes, so the server
|
||||
# MUST report the same content_hash for both — and that hash MUST
|
||||
# equal the BLAKE3 we computed locally. Without this check, a
|
||||
# subtle CDC-assembly bug could produce two distinct blobs that
|
||||
# happen to map to the same dedup key but differ from the source —
|
||||
# the ref_count assertions below would still pass.
|
||||
|
||||
FILE_A_HASH=$(jq -r --arg n "$FILE_A" '.[] | select(.name == $n) | .content_hash // empty' <<< "$LISTING")
|
||||
FILE_B_HASH=$(jq -r --arg n "$FILE_B" '.[] | select(.name == $n) | .content_hash // empty' <<< "$LISTING")
|
||||
[[ "$FILE_A_HASH" == "$BLOB_HASH" ]] \
|
||||
|| fail "content_hash mismatch for A: server=$FILE_A_HASH expected=$BLOB_HASH"
|
||||
[[ "$FILE_B_HASH" == "$BLOB_HASH" ]] \
|
||||
|| fail "content_hash mismatch for B: server=$FILE_B_HASH expected=$BLOB_HASH"
|
||||
pass "content_hash on both A and B matches local BLAKE3 ($BLOB_HASH)"
|
||||
|
||||
# ── Step 3: ref_count == 2 ────────────────────────────────────────────────────
|
||||
|
||||
echo " step 3: dedup/check → expect ref_count=2..."
|
||||
|
||||
@@ -147,6 +147,20 @@ FILE_B_ID=$(jq -r --arg n "$FILE_B" '.[] | select(.name == $n) | .id' <<< "$FILE
|
||||
|| fail "File A and B share the same ID — dedup must produce two distinct records"
|
||||
pass "Two distinct file records: A=$FILE_A_ID B=$FILE_B_ID"
|
||||
|
||||
# ── Step 3b: server's content_hash matches our local BLAKE3 for both ─────────
|
||||
# Both files were uploaded from byte-identical content — server's
|
||||
# `content_hash` field (exposed via the etag-centralization refactor)
|
||||
# must equal BLOB_HASH for both, proving the server's view of
|
||||
# content identity agrees with our local computation.
|
||||
|
||||
FILE_A_HASH=$(jq -r --arg n "$FILE_A" '.[] | select(.name == $n) | .content_hash // empty' <<< "$FILE_LISTING")
|
||||
FILE_B_HASH=$(jq -r --arg n "$FILE_B" '.[] | select(.name == $n) | .content_hash // empty' <<< "$FILE_LISTING")
|
||||
[[ "$FILE_A_HASH" == "$BLOB_HASH" ]] \
|
||||
|| fail "content_hash mismatch for A: server=$FILE_A_HASH expected=$BLOB_HASH"
|
||||
[[ "$FILE_B_HASH" == "$BLOB_HASH" ]] \
|
||||
|| fail "content_hash mismatch for B: server=$FILE_B_HASH expected=$BLOB_HASH"
|
||||
pass "content_hash on both A and B matches local BLAKE3 ($BLOB_HASH)"
|
||||
|
||||
# ── Step 4: Dedup check → ref_count == 2 ─────────────────────────────────────
|
||||
|
||||
echo " step 4: GET /api/dedup/check/$BLOB_HASH..."
|
||||
@@ -168,6 +182,25 @@ STATUS=$(webdav_put "$FILE_B" "$FIXTURE_OTHER" "image/jpeg")
|
||||
[[ "$STATUS" == "204" ]] || fail "PUT $FILE_B (overwrite) expected 204, got $STATUS"
|
||||
pass "PUT $FILE_B overwrite → 204"
|
||||
|
||||
# ── Step 5b: B's content_hash flipped, A's unchanged ─────────────────────────
|
||||
# After overwrite, B references a new blob (oxicloud-logo.jpg)
|
||||
# whose BLAKE3 differs from BLOB_HASH; A still holds the original.
|
||||
# A weaker but local-fixture-agnostic check than asserting B's new
|
||||
# exact hash (avoids hardcoding a second BLAKE3) — proves that the
|
||||
# COW-overwrite path swaps the blob identity rather than silently
|
||||
# keeping the old one.
|
||||
|
||||
REFRESHED=$(rest_get "/api/files?folder_id=$HOME_FOLDER_ID")
|
||||
FILE_A_HASH_AFTER=$(jq -r --arg n "$FILE_A" '.[] | select(.name == $n) | .content_hash // empty' <<< "$REFRESHED")
|
||||
FILE_B_HASH_AFTER=$(jq -r --arg n "$FILE_B" '.[] | select(.name == $n) | .content_hash // empty' <<< "$REFRESHED")
|
||||
[[ "$FILE_A_HASH_AFTER" == "$BLOB_HASH" ]] \
|
||||
|| fail "File A's content_hash changed unexpectedly: $FILE_A_HASH_AFTER (overwrite of B must not touch A)"
|
||||
[[ "$FILE_B_HASH_AFTER" != "$BLOB_HASH" ]] \
|
||||
|| fail "File B's content_hash unchanged after overwrite — COW path didn't swap the blob"
|
||||
[[ -n "$FILE_B_HASH_AFTER" ]] \
|
||||
|| fail "File B has empty content_hash after overwrite — server didn't compute a new blob"
|
||||
pass "post-overwrite: A still on $BLOB_HASH, B flipped to $FILE_B_HASH_AFTER"
|
||||
|
||||
# ── Step 6: Dedup check → ref_count == 1 ─────────────────────────────────────
|
||||
# File B now references a different blob; file A still holds the original.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user