#!/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 - generate unique hashes for each test run TIMESTAMP=$(date +%s) TEST_SHA256=$(echo "test_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1) TEST_CONTENT_TYPE="image/png" TEST_CONTENT_LENGTH="71418" # Generate additional unique hashes for tests that need fresh hashes TEST_SHA256_FRESH=$(echo "fresh_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1) TEST_SHA256_AUTH=$(echo "auth_bud06_${TIMESTAMP}_$(uname -n)" | sha256sum | cut -d' ' -f1) # 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_FRESH" "$TEST_CONTENT_TYPE" "$TEST_CONTENT_LENGTH") STATUS=$(get_status_code "$RESPONSE") echo "Request Headers:" echo " X-SHA-256: $TEST_SHA256_FRESH" 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_FRESH" "$UNSUPPORTED_TYPE" "$TEST_CONTENT_LENGTH") STATUS=$(get_status_code "$RESPONSE") REASON=$(get_x_reason "$RESPONSE") echo "Request Headers:" echo " X-SHA-256: $TEST_SHA256_FRESH" 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_AUTH" "$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_AUTH" 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 ==="