310 lines
9.0 KiB
Bash
Executable File
310 lines
9.0 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# BUD-06 Upload Requirements Test Suite
|
||
# Tests HEAD /upload endpoint for pre-flight validation
|
||
|
||
set -e
|
||
|
||
echo "=== BUD-06 Upload Requirements Test Suite ==="
|
||
|
||
# Test configuration
|
||
SERVER_URL="http://localhost:9001"
|
||
UPLOAD_ENDPOINT="${SERVER_URL}/upload"
|
||
|
||
# Test file properties
|
||
TEST_SHA256="24308d48eb498b593e55a87b6300ccffdea8432babc0bb898b1eff21ebbb72de"
|
||
TEST_CONTENT_TYPE="image/png"
|
||
TEST_CONTENT_LENGTH="71418"
|
||
|
||
# Helper function to make HEAD request with custom headers
|
||
make_head_request() {
|
||
local sha256="$1"
|
||
local content_type="$2"
|
||
local content_length="$3"
|
||
local auth_header="$4"
|
||
|
||
local curl_cmd="curl -s -I -X HEAD \"${UPLOAD_ENDPOINT}\""
|
||
|
||
if [ -n "$sha256" ]; then
|
||
curl_cmd="${curl_cmd} -H \"X-SHA-256: ${sha256}\""
|
||
fi
|
||
|
||
if [ -n "$content_type" ]; then
|
||
curl_cmd="${curl_cmd} -H \"X-Content-Type: ${content_type}\""
|
||
fi
|
||
|
||
if [ -n "$content_length" ]; then
|
||
curl_cmd="${curl_cmd} -H \"X-Content-Length: ${content_length}\""
|
||
fi
|
||
|
||
if [ -n "$auth_header" ]; then
|
||
curl_cmd="${curl_cmd} -H \"Authorization: ${auth_header}\""
|
||
fi
|
||
|
||
eval "$curl_cmd"
|
||
}
|
||
|
||
# Helper function to extract HTTP status code
|
||
get_status_code() {
|
||
echo "$1" | head -n1 | grep -o '[0-9]\{3\}'
|
||
}
|
||
|
||
# Helper function to extract X-Reason header
|
||
get_x_reason() {
|
||
echo "$1" | grep -i "x-reason:" | cut -d: -f2- | sed 's/^ *//'
|
||
}
|
||
|
||
# Test 1: Valid request should return 200 OK
|
||
echo ""
|
||
echo "=== Test 1: Valid Upload Requirements ==="
|
||
echo "Testing HEAD /upload with valid headers..."
|
||
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "200" ]; then
|
||
echo "✅ Test 1 PASSED: Valid request accepted (HTTP 200)"
|
||
else
|
||
echo "❌ Test 1 FAILED: Expected HTTP 200, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 2: Missing X-SHA-256 header
|
||
echo ""
|
||
echo "=== Test 2: Missing X-SHA-256 Header ==="
|
||
echo "Testing HEAD /upload without X-SHA-256..."
|
||
|
||
RESPONSE=$(make_head_request "" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: (missing)"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "400" ]; then
|
||
echo "✅ Test 2 PASSED: Missing X-SHA-256 rejected (HTTP 400)"
|
||
echo " X-Reason: $REASON"
|
||
else
|
||
echo "❌ Test 2 FAILED: Expected HTTP 400, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 3: Invalid X-SHA-256 format
|
||
echo ""
|
||
echo "=== Test 3: Invalid X-SHA-256 Format ==="
|
||
echo "Testing HEAD /upload with invalid hash format..."
|
||
|
||
INVALID_SHA256="invalid_hash_format"
|
||
RESPONSE=$(make_head_request "$INVALID_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $INVALID_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "400" ]; then
|
||
echo "✅ Test 3 PASSED: Invalid X-SHA-256 format rejected (HTTP 400)"
|
||
echo " X-Reason: $REASON"
|
||
else
|
||
echo "❌ Test 3 FAILED: Expected HTTP 400, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 4: Missing X-Content-Length header
|
||
echo ""
|
||
echo "=== Test 4: Missing X-Content-Length Header ==="
|
||
echo "Testing HEAD /upload without X-Content-Length..."
|
||
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: (missing)"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "411" ]; then
|
||
echo "✅ Test 4 PASSED: Missing X-Content-Length rejected (HTTP 411 Length Required)"
|
||
echo " X-Reason: $REASON"
|
||
else
|
||
echo "❌ Test 4 FAILED: Expected HTTP 411, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 5: File too large
|
||
echo ""
|
||
echo "=== Test 5: File Size Too Large ==="
|
||
echo "Testing HEAD /upload with oversized file..."
|
||
|
||
LARGE_SIZE="209715200" # 200MB (over 100MB limit)
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "$LARGE_SIZE")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $LARGE_SIZE (200MB)"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "413" ]; then
|
||
echo "✅ Test 5 PASSED: Oversized file rejected (HTTP 413 Content Too Large)"
|
||
echo " X-Reason: $REASON"
|
||
else
|
||
echo "❌ Test 5 FAILED: Expected HTTP 413, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 6: Invalid Content-Type
|
||
echo ""
|
||
echo "=== Test 6: Unsupported Media Type ==="
|
||
echo "Testing HEAD /upload with potentially unsupported MIME type..."
|
||
|
||
UNSUPPORTED_TYPE="application/x-malware"
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$UNSUPPORTED_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $UNSUPPORTED_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "415" ]; then
|
||
echo "✅ Test 6 PASSED: Unsupported media type rejected (HTTP 415)"
|
||
echo " X-Reason: $REASON"
|
||
elif [ "$STATUS" = "200" ]; then
|
||
echo "⚠️ Test 6 INFO: Unsupported media type accepted (no MIME restrictions configured)"
|
||
else
|
||
echo "❌ Test 6 FAILED: Unexpected status code: HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 7: Zero file size
|
||
echo ""
|
||
echo "=== Test 7: Zero File Size ==="
|
||
echo "Testing HEAD /upload with zero byte file..."
|
||
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "0")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: 0"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "400" ]; then
|
||
echo "✅ Test 7 PASSED: Zero byte file rejected (HTTP 400)"
|
||
echo " X-Reason: $REASON"
|
||
else
|
||
echo "❌ Test 7 FAILED: Expected HTTP 400, got HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 8: Existing blob (duplicate)
|
||
echo ""
|
||
echo "=== Test 8: Duplicate Blob Detection ==="
|
||
echo "Testing HEAD /upload with hash of existing blob..."
|
||
|
||
# Use the hash from our previous mirror test that should exist
|
||
EXISTING_SHA256="24308d48eb498b593e55a87b6300ccffdea8432babc0bb898b1eff21ebbb72de"
|
||
RESPONSE=$(make_head_request "$EXISTING_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers:"
|
||
echo " X-SHA-256: $EXISTING_SHA256 (should already exist from mirror test)"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "409" ]; then
|
||
echo "✅ Test 8 PASSED: Duplicate blob detected (HTTP 409 Conflict)"
|
||
echo " X-Reason: $REASON"
|
||
elif [ "$STATUS" = "200" ]; then
|
||
echo "⚠️ Test 8 INFO: Duplicate upload allowed (server allows overwrites)"
|
||
else
|
||
echo "❌ Test 8 FAILED: Unexpected status code: HTTP $STATUS"
|
||
fi
|
||
|
||
# Test 9: Authorization test (if server requires auth)
|
||
echo ""
|
||
echo "=== Test 9: Authorization Handling ==="
|
||
echo "Testing HEAD /upload authorization requirements..."
|
||
|
||
# Test without authorization first
|
||
RESPONSE=$(make_head_request "$TEST_SHA256" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH")
|
||
STATUS=$(get_status_code "$RESPONSE")
|
||
REASON=$(get_x_reason "$RESPONSE")
|
||
|
||
echo "Request Headers (no authorization):"
|
||
echo " X-SHA-256: $TEST_SHA256"
|
||
echo " X-Content-Type: $TEST_CONTENT_TYPE"
|
||
echo " X-Content-Length: $TEST_CONTENT_LENGTH"
|
||
echo " Authorization: (missing)"
|
||
echo ""
|
||
echo "Response:"
|
||
echo "$RESPONSE"
|
||
echo ""
|
||
|
||
if [ "$STATUS" = "401" ]; then
|
||
echo "✅ Test 9a PASSED: Authorization required (HTTP 401)"
|
||
echo " X-Reason: $REASON"
|
||
elif [ "$STATUS" = "200" ]; then
|
||
echo "ℹ️ Test 9a INFO: No authorization required (anonymous uploads allowed)"
|
||
else
|
||
echo "❌ Test 9a FAILED: Unexpected status code: HTTP $STATUS"
|
||
fi
|
||
|
||
echo ""
|
||
echo "=== Test Summary ==="
|
||
echo "BUD-06 Upload Requirements pre-flight validation test complete."
|
||
echo ""
|
||
echo "Key Test Scenarios:"
|
||
echo " ✓ Valid request validation"
|
||
echo " ✓ Missing/invalid X-SHA-256 header"
|
||
echo " ✓ Missing X-Content-Length header"
|
||
echo " ✓ File size limit enforcement"
|
||
echo " ✓ Media type validation (if configured)"
|
||
echo " ✓ Zero byte file rejection"
|
||
echo " ✓ Duplicate blob detection"
|
||
echo " ✓ Authorization handling"
|
||
echo ""
|
||
echo "Note: Some tests may show INFO/WARNING if server policies differ"
|
||
echo "from BUD-06 specification (e.g., no MIME restrictions, allows duplicates)."
|
||
echo ""
|
||
echo "=== End of BUD-06 Test Suite ===" |