#!/bin/bash set -euo pipefail # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" TEST_DIR="${SCRIPT_DIR}/test_tmp" TEST_TOKEN="test-token-$(date +%s)" CONTAINER_NAME="sos-test-$(date +%s)" IMAGE="gitea.jde.nz/public/simple-object-server:latest" TEST_PORT="" SOS_TEST_HOST="" CLEANUP_NEEDED=false # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # Logging functions log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; } die() { log_error "$@"; exit 1; } # Cleanup on exit cleanup() { [[ "$CLEANUP_NEEDED" != true ]] && return log_info "Cleaning up test environment..." docker stop "${CONTAINER_NAME}" &>/dev/null || true docker rm "${CONTAINER_NAME}" &>/dev/null || true rm -rf "${TEST_DIR}" log_info "Cleanup complete" } trap cleanup EXIT # Check dependencies check_dependencies() { log_info "Checking dependencies..." for cmd in docker jq curl; do command -v $cmd &>/dev/null || die "$cmd is required but not installed" done docker info &>/dev/null || die "Docker daemon is not running" log_info "All dependencies satisfied" } # Setup test environment setup_test_environment() { log_info "Setting up test environment..." CLEANUP_NEEDED=true # Create directories rm -rf "${TEST_DIR}" mkdir -p "${TEST_DIR}"/{test_files,config} # Generate hashed token for authentication log_info "Generating authentication token..." local hashed_token=$(docker run --rm "$IMAGE" /sos/hash_token "${TEST_TOKEN}" 2>/dev/null | grep '^\$2[aby]\$' | head -1) [[ -z "$hashed_token" ]] && die "Failed to generate hashed token" # Create config echo "{\"write_tokens\": [\"${hashed_token}\"]}" > "${TEST_DIR}/config/sos_config.json" # Create test files echo "This is test file 1" > "${TEST_DIR}/test_files/test1.txt" echo "This is test file 2 with more content" > "${TEST_DIR}/test_files/test2.txt" dd if=/dev/urandom of="${TEST_DIR}/test_files/binary_test.bin" bs=1024 count=10 &>/dev/null cp "${SCRIPT_DIR}/sos" "${TEST_DIR}/test_files/sos_binary" log_info "Test environment ready" } # Start and configure test server start_test_server() { log_info "Starting SOS test server..." # Pull latest image docker pull "$IMAGE" &>/dev/null || log_warning "Using cached image" # Start container with dynamic port local container_id=$(docker run -d --name "${CONTAINER_NAME}" -p 80 "$IMAGE" 2>&1) [[ $? -ne 0 ]] && die "Failed to start container: ${container_id}" log_info "Container started: ${container_id:0:12}" # Get assigned port TEST_PORT=$(docker port "${CONTAINER_NAME}" 80 | cut -d: -f2) [[ -z "$TEST_PORT" ]] && die "Failed to get container port" log_info "Container port: ${TEST_PORT}" # Copy config and restart (for Docker-in-Docker compatibility) docker cp "${TEST_DIR}/config/sos_config.json" "${CONTAINER_NAME}:/data/sos_config.json" || die "Failed to copy config" docker exec "${CONTAINER_NAME}" mkdir -p /data/storage 2>/dev/null || true docker restart "${CONTAINER_NAME}" &>/dev/null || die "Failed to restart container" # ARM64 systems may need more time to restart sleep 5 # Wait for restart # Update port if changed after restart local new_port=$(docker port "${CONTAINER_NAME}" 80 | cut -d: -f2) [[ -z "$new_port" ]] && die "Lost port mapping after restart" [[ "$new_port" != "$TEST_PORT" ]] && TEST_PORT="$new_port" && log_info "Port updated: ${TEST_PORT}" # Get network details for connectivity local container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${CONTAINER_NAME}") local host_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' "${CONTAINER_NAME}") # Wait for server readiness and determine connection method wait_for_server "$container_ip" "$host_ip" } # Wait for server and determine connection method wait_for_server() { local container_ip="${1:-}" local host_ip="${2:-}" log_info "Waiting for server readiness..." for attempt in {1..60}; do # Try all connection methods local container_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://${container_ip}:80/" 2>/dev/null || echo "000") local host_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://${host_ip}:${TEST_PORT}/" 2>/dev/null || echo "000") local local_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://localhost:${TEST_PORT}/" 2>/dev/null || echo "000") # Debug first attempts if [[ $attempt -le 3 ]]; then log_info "Health check #${attempt}: container=${container_code}, host=${host_code}, localhost=${local_code}" fi # Check which method works if [[ "$container_code" =~ ^(200|204|404)$ ]]; then export SOS_TEST_HOST="${container_ip}:80" log_info "Server ready! Using container IP: ${SOS_TEST_HOST}" return 0 elif [[ "$host_code" =~ ^(200|204|404)$ ]]; then export SOS_TEST_HOST="${host_ip}:${TEST_PORT}" log_info "Server ready! Using host IP: ${SOS_TEST_HOST}" return 0 elif [[ "$local_code" =~ ^(200|204|404)$ ]]; then export SOS_TEST_HOST="localhost:${TEST_PORT}" log_info "Server ready! Using localhost: ${SOS_TEST_HOST}" return 0 fi # Progress indicator [[ $((attempt % 10)) -eq 0 ]] && log_info "Still waiting... (${attempt}/60)" sleep 1 done die "Server failed to become ready after 60 seconds" } # Execute SOS upload command run_sos_upload() { local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" export SOS_WRITE_TOKEN="${TEST_TOKEN}" export SOS_TEST_MODE=1 "${SCRIPT_DIR}/sos" upload "$host" "$@" } # Test functions test_upload() { local file="$1" local label="$2" shift 2 log_info "Testing upload: ${file##*/} with label ${label}" local output=$(run_sos_upload "$file" "$label" "$@" 2>&1 | tee "${TEST_DIR}/upload_output.txt") if echo "$output" | grep -q "Download URL:"; then log_info "Upload successful" return 0 else log_error "Upload failed" # Show error details for debugging ARM64 issues echo "Error output:" >&2 echo "$output" | grep -E "(FATAL:|ERROR:|Failed|curl)" | head -5 >&2 return 1 fi } test_retrieval() { local identifier="$1" local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" log_info "Testing retrieval: ${identifier}" local response=$(curl -s "http://${host}/${identifier}") [[ -z "$response" ]] && log_error "Retrieval failed" && return 1 # For hash identifiers, also test metadata endpoint if [[ "$identifier" =~ ^[a-f0-9]{64}$ ]]; then curl -s "http://${host}/meta/${identifier}" | jq -e '.metadata' &>/dev/null || { log_error "Metadata retrieval failed" return 1 } fi log_info "Retrieval successful" return 0 } test_deduplication() { log_info "Testing deduplication..." # Create duplicate file cp "${TEST_DIR}/test_files/test1.txt" "${TEST_DIR}/test_files/test1_dup.txt" # Upload original and duplicate run_sos_upload "${TEST_DIR}/test_files/test1.txt" "dup:original" &>/dev/null local output=$(run_sos_upload "${TEST_DIR}/test_files/test1_dup.txt" "dup:copy" 2>&1) if echo "$output" | grep -q "File already exists, skipping upload"; then log_info "Deduplication working" return 0 else log_error "Deduplication failed" return 1 fi } test_metadata_update() { log_info "Testing metadata update..." run_sos_upload "${TEST_DIR}/test_files/test2.txt" "meta:v1" &>/dev/null local output=$(run_sos_upload "${TEST_DIR}/test_files/test2.txt" "meta:v2" "meta:updated" 2>&1) if echo "$output" | grep -q "File already exists"; then log_info "Metadata update working" return 0 else log_error "Metadata update failed" return 1 fi } test_api_endpoints() { log_info "Testing API endpoints..." local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" # Test hash endpoint local hash=$(curl -s "http://${host}/hash/test:file1" | jq -r '.hash') [[ -z "$hash" || "$hash" == "null" ]] && log_error "Hash endpoint failed" && return 1 # Test exists endpoint local exists=$(curl -s "http://${host}/exists/${hash}" | jq -r '.exists') [[ "$exists" != "true" ]] && log_error "Exists endpoint failed" && return 1 log_info "API endpoints working" return 0 } test_invalid_auth() { log_info "Testing invalid authentication..." echo "auth test" > "${TEST_DIR}/test_files/auth_test.txt" export SOS_WRITE_TOKEN="invalid-token" export SOS_TEST_MODE=1 local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" # Run upload with invalid token and properly capture exit code set +e "${SCRIPT_DIR}/sos" upload "$host" "${TEST_DIR}/test_files/auth_test.txt" "auth:test" >"${TEST_DIR}/auth_output.txt" 2>&1 local exit_code=$? set -e local output=$(cat "${TEST_DIR}/auth_output.txt") # The sos script should fail with non-zero exit code and show error message if [[ $exit_code -ne 0 ]] && echo "$output" | grep -qE "(FATAL:|Invalid write token|HTTP 403|HTTP 401)"; then log_info "Invalid auth correctly rejected (exit code: $exit_code)" return 0 else log_error "Invalid auth not rejected properly (exit code: $exit_code)" echo "Output:" && echo "$output" | head -5 return 1 fi } test_metadata_single() { log_info "Testing single metadata field..." echo "metadata test single" > "${TEST_DIR}/test_files/meta_single.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/meta_single.txt" "meta:single" --metadata "customField=testValue" 2>&1) # Check if upload succeeded if ! echo "$output" | grep -q "Download URL:"; then log_error "Upload with metadata failed" echo "$output" | head -5 return 1 fi # Verify metadata was included local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" local hash=$(curl -s "http://${host}/hash/meta:single" | jq -r '.hash') local meta=$(curl -s "http://${host}/meta/${hash}" | jq -r '.metadata.customField') if [[ "$meta" == "testValue" ]]; then log_info "Single metadata field working" return 0 else log_error "Metadata not found or incorrect (got: $meta)" return 1 fi } test_metadata_multiple() { log_info "Testing multiple metadata fields..." echo "metadata test multiple" > "${TEST_DIR}/test_files/meta_multiple.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/meta_multiple.txt" "meta:multiple" \ --metadata "field1=value1" \ --metadata "field2=value2" \ --metadata "templateXXHash64=abc123def456" 2>&1) # Check if upload succeeded if ! echo "$output" | grep -q "Download URL:"; then log_error "Upload with multiple metadata failed" echo "$output" | head -5 return 1 fi # Verify all metadata fields were included local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" local hash=$(curl -s "http://${host}/hash/meta:multiple" | jq -r '.hash') local metadata=$(curl -s "http://${host}/meta/${hash}") local field1=$(echo "$metadata" | jq -r '.metadata.field1') local field2=$(echo "$metadata" | jq -r '.metadata.field2') local xxhash=$(echo "$metadata" | jq -r '.metadata.templateXXHash64') if [[ "$field1" == "value1" && "$field2" == "value2" && "$xxhash" == "abc123def456" ]]; then log_info "Multiple metadata fields working" return 0 else log_error "Metadata fields incorrect" echo "field1=$field1, field2=$field2, templateXXHash64=$xxhash" return 1 fi } test_metadata_special_chars() { log_info "Testing metadata with special characters..." echo "metadata test special" > "${TEST_DIR}/test_files/meta_special.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/meta_special.txt" "meta:special" \ --metadata "description=This is a test with spaces" \ --metadata "formula=a=b+c" \ --metadata "path=/usr/local/bin" \ --metadata "quote=He said \"hello\"" 2>&1) # Check if upload succeeded if ! echo "$output" | grep -q "Download URL:"; then log_error "Upload with special chars metadata failed" echo "$output" | head -5 return 1 fi # Verify metadata with special characters local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" local hash=$(curl -s "http://${host}/hash/meta:special" | jq -r '.hash') local metadata=$(curl -s "http://${host}/meta/${hash}") local desc=$(echo "$metadata" | jq -r '.metadata.description') local formula=$(echo "$metadata" | jq -r '.metadata.formula') local path=$(echo "$metadata" | jq -r '.metadata.path') local quote=$(echo "$metadata" | jq -r '.metadata.quote') if [[ "$desc" == "This is a test with spaces" && \ "$formula" == "a=b+c" && \ "$path" == "/usr/local/bin" && \ "$quote" == 'He said "hello"' ]]; then log_info "Metadata with special characters working" return 0 else log_error "Special character metadata incorrect" echo "description='$desc'" echo "formula='$formula'" echo "path='$path'" echo "quote='$quote'" return 1 fi } test_metadata_mixed_labels() { log_info "Testing metadata mixed with multiple labels..." echo "metadata test mixed" > "${TEST_DIR}/test_files/meta_mixed.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/meta_mixed.txt" \ "meta:mixed1" \ --metadata "author=test-user" \ "meta:mixed2" \ --metadata "version=1.2.3" \ "meta:mixed3" 2>&1) # Check if upload succeeded if ! echo "$output" | grep -q "Download URL:"; then log_error "Upload with mixed labels and metadata failed" echo "$output" | head -5 return 1 fi # Verify metadata and labels local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" local hash=$(curl -s "http://${host}/hash/meta:mixed1" | jq -r '.hash') local metadata=$(curl -s "http://${host}/meta/${hash}") local author=$(echo "$metadata" | jq -r '.metadata.author') local version=$(echo "$metadata" | jq -r '.metadata.version') local labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') # Check all three labels exist local has_mixed1=$(echo "$metadata" | jq -r '.metadata.labeltags | map(select(. == "meta:mixed1")) | length') local has_mixed2=$(echo "$metadata" | jq -r '.metadata.labeltags | map(select(. == "meta:mixed2")) | length') local has_mixed3=$(echo "$metadata" | jq -r '.metadata.labeltags | map(select(. == "meta:mixed3")) | length') if [[ "$author" == "test-user" && "$version" == "1.2.3" && \ "$has_mixed1" == "1" && "$has_mixed2" == "1" && "$has_mixed3" == "1" ]]; then log_info "Mixed labels and metadata working" return 0 else log_error "Mixed metadata/labels incorrect" echo "author=$author, version=$version" echo "Labels: mixed1=$has_mixed1, mixed2=$has_mixed2, mixed3=$has_mixed3" return 1 fi } test_metadata_empty_value() { log_info "Testing metadata with empty value..." echo "metadata test empty" > "${TEST_DIR}/test_files/meta_empty.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/meta_empty.txt" "meta:empty" \ --metadata "emptyField=" \ --metadata "normalField=hasValue" 2>&1) # Check if upload succeeded if ! echo "$output" | grep -q "Download URL:"; then log_error "Upload with empty metadata value failed" echo "$output" | head -5 return 1 fi # Verify metadata local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" local hash=$(curl -s "http://${host}/hash/meta:empty" | jq -r '.hash') local metadata=$(curl -s "http://${host}/meta/${hash}") local empty=$(echo "$metadata" | jq -r '.metadata.emptyField') local normal=$(echo "$metadata" | jq -r '.metadata.normalField') if [[ "$empty" == "" && "$normal" == "hasValue" ]]; then log_info "Empty metadata value handled correctly" return 0 else log_error "Empty metadata value not handled correctly" echo "emptyField='$empty', normalField='$normal'" return 1 fi } test_metadata_invalid_format() { log_info "Testing invalid metadata format rejection..." echo "metadata test invalid" > "${TEST_DIR}/test_files/meta_invalid.txt" # Test invalid format (no equals sign) - directly call sos to capture exit code export SOS_WRITE_TOKEN="${TEST_TOKEN}" export SOS_TEST_MODE=1 local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" set +e "${SCRIPT_DIR}/sos" upload "$host" "${TEST_DIR}/test_files/meta_invalid.txt" "meta:invalid" --metadata "noequals" >"${TEST_DIR}/invalid_meta_output.txt" 2>&1 local exit_code=$? set -e local output=$(cat "${TEST_DIR}/invalid_meta_output.txt") if [[ $exit_code -ne 0 ]] && echo "$output" | grep -q "Metadata must be in \"key=value\" format"; then log_info "Invalid metadata format correctly rejected (exit code: $exit_code)" return 0 else log_error "Invalid metadata format not rejected properly" echo "Exit code: $exit_code" echo "$output" | head -5 return 1 fi } test_metadata_no_labels() { log_info "Testing metadata without any labels (should fail)..." echo "metadata no labels" > "${TEST_DIR}/test_files/meta_no_labels.txt" # Test with only metadata, no labels - should fail export SOS_WRITE_TOKEN="${TEST_TOKEN}" export SOS_TEST_MODE=1 local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" set +e "${SCRIPT_DIR}/sos" upload "$host" "${TEST_DIR}/test_files/meta_no_labels.txt" \ --metadata "field1=value1" \ --metadata "field2=value2" >"${TEST_DIR}/no_labels_output.txt" 2>&1 local exit_code=$? set -e local output=$(cat "${TEST_DIR}/no_labels_output.txt") if [[ $exit_code -ne 0 ]] && echo "$output" | grep -q "At least one label:tag is required"; then log_info "Metadata without labels correctly rejected (exit code: $exit_code)" return 0 else log_error "Metadata without labels not rejected properly" echo "Exit code: $exit_code" echo "$output" | head -5 return 1 fi } test_metadata_ordering_comprehensive() { log_info "Testing comprehensive metadata and label ordering combinations..." local all_passed=true local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" # Test 1: Metadata before all labels echo "order test 1" > "${TEST_DIR}/test_files/order1.txt" local output=$(run_sos_upload "${TEST_DIR}/test_files/order1.txt" \ --metadata "position=before" \ --metadata "test=1" \ "order:test1a" \ "order:test1b" 2>&1) if echo "$output" | grep -q "Download URL:"; then local hash=$(curl -s "http://${host}/hash/order:test1a" | jq -r '.hash') local metadata=$(curl -s "http://${host}/meta/${hash}") local position=$(echo "$metadata" | jq -r '.metadata.position') local test=$(echo "$metadata" | jq -r '.metadata.test') local labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$position" == "before" && "$test" == "1" && "$labels" == "2" ]]; then log_info " ✓ Metadata before all labels: PASSED" else log_error " ✗ Metadata before all labels: FAILED" echo " Got: position=$position, test=$test, labels=$labels" all_passed=false fi else log_error " ✗ Metadata before all labels: Upload failed" all_passed=false fi # Test 2: Metadata after all labels echo "order test 2" > "${TEST_DIR}/test_files/order2.txt" output=$(run_sos_upload "${TEST_DIR}/test_files/order2.txt" \ "order:test2a" \ "order:test2b" \ --metadata "position=after" \ --metadata "test=2" 2>&1) if echo "$output" | grep -q "Download URL:"; then hash=$(curl -s "http://${host}/hash/order:test2a" | jq -r '.hash') metadata=$(curl -s "http://${host}/meta/${hash}") position=$(echo "$metadata" | jq -r '.metadata.position') test=$(echo "$metadata" | jq -r '.metadata.test') labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$position" == "after" && "$test" == "2" && "$labels" == "2" ]]; then log_info " ✓ Metadata after all labels: PASSED" else log_error " ✗ Metadata after all labels: FAILED" echo " Got: position=$position, test=$test, labels=$labels" all_passed=false fi else log_error " ✗ Metadata after all labels: Upload failed" all_passed=false fi # Test 3: Alternating pattern - label, metadata, label, metadata echo "order test 3" > "${TEST_DIR}/test_files/order3.txt" output=$(run_sos_upload "${TEST_DIR}/test_files/order3.txt" \ "order:test3a" \ --metadata "first=1" \ "order:test3b" \ --metadata "second=2" 2>&1) if echo "$output" | grep -q "Download URL:"; then hash=$(curl -s "http://${host}/hash/order:test3a" | jq -r '.hash') metadata=$(curl -s "http://${host}/meta/${hash}") first=$(echo "$metadata" | jq -r '.metadata.first') second=$(echo "$metadata" | jq -r '.metadata.second') labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$first" == "1" && "$second" == "2" && "$labels" == "2" ]]; then log_info " ✓ Alternating label-metadata pattern: PASSED" else log_error " ✗ Alternating label-metadata pattern: FAILED" echo " Got: first=$first, second=$second, labels=$labels" all_passed=false fi else log_error " ✗ Alternating label-metadata pattern: Upload failed" all_passed=false fi # Test 4: Alternating pattern - metadata, label, metadata, label echo "order test 4" > "${TEST_DIR}/test_files/order4.txt" output=$(run_sos_upload "${TEST_DIR}/test_files/order4.txt" \ --metadata "alpha=a" \ "order:test4a" \ --metadata "beta=b" \ "order:test4b" 2>&1) if echo "$output" | grep -q "Download URL:"; then hash=$(curl -s "http://${host}/hash/order:test4a" | jq -r '.hash') metadata=$(curl -s "http://${host}/meta/${hash}") alpha=$(echo "$metadata" | jq -r '.metadata.alpha') beta=$(echo "$metadata" | jq -r '.metadata.beta') labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$alpha" == "a" && "$beta" == "b" && "$labels" == "2" ]]; then log_info " ✓ Alternating metadata-label pattern: PASSED" else log_error " ✗ Alternating metadata-label pattern: FAILED" echo " Got: alpha=$alpha, beta=$beta, labels=$labels" all_passed=false fi else log_error " ✗ Alternating metadata-label pattern: Upload failed" all_passed=false fi # Test 5: Complex mixed pattern echo "order test 5" > "${TEST_DIR}/test_files/order5.txt" output=$(run_sos_upload "${TEST_DIR}/test_files/order5.txt" \ --metadata "start=yes" \ "order:test5a" \ "order:test5b" \ --metadata "middle=true" \ "order:test5c" \ --metadata "end=done" \ --metadata "extra=value" 2>&1) if echo "$output" | grep -q "Download URL:"; then hash=$(curl -s "http://${host}/hash/order:test5a" | jq -r '.hash') metadata=$(curl -s "http://${host}/meta/${hash}") start=$(echo "$metadata" | jq -r '.metadata.start') middle=$(echo "$metadata" | jq -r '.metadata.middle') end=$(echo "$metadata" | jq -r '.metadata.end') extra=$(echo "$metadata" | jq -r '.metadata.extra') labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$start" == "yes" && "$middle" == "true" && "$end" == "done" && \ "$extra" == "value" && "$labels" == "3" ]]; then log_info " ✓ Complex mixed pattern: PASSED" else log_error " ✗ Complex mixed pattern: FAILED" echo " Got: start=$start, middle=$middle, end=$end, extra=$extra, labels=$labels" all_passed=false fi else log_error " ✗ Complex mixed pattern: Upload failed" all_passed=false fi # Test 6: Multiple consecutive metadata flags at different positions echo "order test 6" > "${TEST_DIR}/test_files/order6.txt" output=$(run_sos_upload "${TEST_DIR}/test_files/order6.txt" \ --metadata "group1a=1" \ --metadata "group1b=2" \ "order:test6a" \ --metadata "group2a=3" \ --metadata "group2b=4" \ "order:test6b" \ --metadata "group3a=5" \ --metadata "group3b=6" 2>&1) if echo "$output" | grep -q "Download URL:"; then hash=$(curl -s "http://${host}/hash/order:test6a" | jq -r '.hash') metadata=$(curl -s "http://${host}/meta/${hash}") g1a=$(echo "$metadata" | jq -r '.metadata.group1a') g1b=$(echo "$metadata" | jq -r '.metadata.group1b') g2a=$(echo "$metadata" | jq -r '.metadata.group2a') g2b=$(echo "$metadata" | jq -r '.metadata.group2b') g3a=$(echo "$metadata" | jq -r '.metadata.group3a') g3b=$(echo "$metadata" | jq -r '.metadata.group3b') labels=$(echo "$metadata" | jq -r '.metadata.labeltags | length') if [[ "$g1a" == "1" && "$g1b" == "2" && "$g2a" == "3" && \ "$g2b" == "4" && "$g3a" == "5" && "$g3b" == "6" && "$labels" == "2" ]]; then log_info " ✓ Multiple consecutive metadata groups: PASSED" else log_error " ✗ Multiple consecutive metadata groups: FAILED" echo " Got: g1a=$g1a, g1b=$g1b, g2a=$g2a, g2b=$g2b, g3a=$g3a, g3b=$g3b, labels=$labels" all_passed=false fi else log_error " ✗ Multiple consecutive metadata groups: Upload failed" all_passed=false fi if [[ "$all_passed" == true ]]; then log_info "All ordering tests passed!" return 0 else log_error "Some ordering tests failed" return 1 fi } # Run all tests run_tests() { local tests=( "test_upload ${TEST_DIR}/test_files/test1.txt test:file1" "test_upload ${TEST_DIR}/test_files/test2.txt test:file2 version:1.0 env:test" "test_upload ${TEST_DIR}/test_files/binary_test.bin binary:test" "test_upload ${TEST_DIR}/test_files/sos_binary sos:test sos:latest" "test_retrieval test:file1" "test_deduplication" "test_metadata_update" "test_api_endpoints" "test_invalid_auth" "test_metadata_single" "test_metadata_multiple" "test_metadata_special_chars" "test_metadata_mixed_labels" "test_metadata_empty_value" "test_metadata_invalid_format" "test_metadata_no_labels" "test_metadata_ordering_comprehensive" ) local total=${#tests[@]} local passed=0 log_info "Running ${total} tests..." echo "" set +e # Don't exit on test failures for test in "${tests[@]}"; do eval "$test" && ((passed++)) || true echo "" # Small delay between tests for ARM64 stability sleep 0.5 done set -e # Summary echo "==================================" if [[ $passed -eq $total ]]; then echo -e "${GREEN}All tests passed!${NC} (${passed}/${total})" return 0 else echo -e "${RED}Some tests failed!${NC} (${passed}/${total})" return 1 fi } # Main execution main() { echo "SOS Test Suite" echo "==============" echo "" check_dependencies setup_test_environment start_test_server echo "" local result=0 run_tests || result=$? echo "" log_info "Test suite completed" [[ $result -ne 0 ]] && log_warning "Server logs:" && docker logs "${CONTAINER_NAME}" 2>&1 | tail -10 exit $result } main "$@"