diff --git a/test.sh b/test.sh index 0f894be..86cd984 100755 --- a/test.sh +++ b/test.sh @@ -1,583 +1,318 @@ #!/bin/bash - set -euo pipefail -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +# 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)" -TEST_PORT="" # Will be set dynamically after container starts +IMAGE="gitea.jde.nz/public/simple-object-server:latest" +TEST_PORT="" +SOS_TEST_HOST="" CLEANUP_NEEDED=false -# Colors for output +# Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' -NC='\033[0m' # No Color +NC='\033[0m' -function log_info() { - echo -e "${GREEN}[INFO]${NC} $1" +# 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" } - -function log_error() { - echo -e "${RED}[ERROR]${NC} $1" >&2 -} - -function log_warning() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -function cleanup() { - if [ "$CLEANUP_NEEDED" = true ]; then - log_info "Cleaning up test environment..." - - # Stop and remove container - if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then - docker stop "${CONTAINER_NAME}" >/dev/null 2>&1 || true - docker rm "${CONTAINER_NAME}" >/dev/null 2>&1 || true - log_info "Removed test container" - fi - - # Clean up test directory - if [ -d "${TEST_DIR}" ]; then - rm -rf "${TEST_DIR}" - log_info "Removed test directory" - fi - fi -} - trap cleanup EXIT -function die() { - log_error "$@" - exit 1 -} - -function check_dependencies() { +# Check dependencies +check_dependencies() { log_info "Checking dependencies..." - - # Check for Docker - if ! command -v docker &> /dev/null; then - die "Docker is required but not installed" - fi - - # Check for jq - if ! command -v jq &> /dev/null; then - die "jq is required but not installed" - fi - - # Check for curl - if ! command -v curl &> /dev/null; then - die "curl is required but not installed" - fi - - # Check Docker daemon is running - if ! docker info >/dev/null 2>&1; then - die "Docker daemon is not running" - fi - + 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" } -function setup_test_environment() { +# Setup test environment +setup_test_environment() { log_info "Setting up test environment..." CLEANUP_NEEDED=true - # Create test directory structure + # Create directories rm -rf "${TEST_DIR}" - mkdir -p "${TEST_DIR}/test_files" - mkdir -p "${TEST_DIR}/config" + mkdir -p "${TEST_DIR}"/{test_files,config} - # Generate hashed token + # Generate hashed token for authentication log_info "Generating authentication token..." - HASHED_TOKEN=$(docker run --rm gitea.jde.nz/public/simple-object-server:latest /sos/hash_token "${TEST_TOKEN}" 2>/dev/null | grep '^\$2[aby]\$' | head -1) + 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" - if [ -z "${HASHED_TOKEN}" ]; then - die "Failed to generate hashed token" - fi - - # Create test configuration in config directory - cat > "${TEST_DIR}/config/sos_config.json" < "${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 2>/dev/null - - # Create the sos binary for testing + 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 "Created test files" + log_info "Test environment ready" } -function start_test_server() { +# Start and configure test server +start_test_server() { log_info "Starting SOS test server..." - # Pull the latest image - log_info "Pulling latest simple-object-server image..." - docker pull gitea.jde.nz/public/simple-object-server:latest - if [ $? -ne 0 ]; then - log_warning "Failed to pull latest image, using cached version if available" - fi + # Pull latest image + docker pull "$IMAGE" &>/dev/null || log_warning "Using cached image" - # Ensure the config file exists and is readable - if [ ! -f "${TEST_DIR}/config/sos_config.json" ]; then - die "Config file ${TEST_DIR}/config/sos_config.json does not exist" - fi + # 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}" - # Start the container without specifying host port (Docker will assign one) - # No volume mounts - will use docker cp/exec for file operations - local container_id=$(docker run -d \ - --name "${CONTAINER_NAME}" \ - -p 80 \ - gitea.jde.nz/public/simple-object-server:latest 2>&1) + log_info "Container started: ${container_id:0:12}" - if [ $? -ne 0 ]; then - log_error "Failed to start container: ${container_id}" - die "Failed to start test server" - fi - - log_info "Container started with ID: ${container_id:0:12}" - - # Get the dynamically assigned port + # Get assigned port TEST_PORT=$(docker port "${CONTAINER_NAME}" 80 | cut -d: -f2) - if [ -z "${TEST_PORT}" ]; then - log_error "Failed to get container port" - die "Failed to get container port mapping" - fi - log_info "Container mapped to port: ${TEST_PORT}" + [[ -z "$TEST_PORT" ]] && die "Failed to get container port" + log_info "Container port: ${TEST_PORT}" - # Copy the config file into the container using docker cp - log_info "Copying config file into container..." - docker cp "${TEST_DIR}/config/sos_config.json" "${CONTAINER_NAME}:/data/sos_config.json" - if [ $? -ne 0 ]; then - log_error "Failed to copy config file into container" - docker logs "${CONTAINER_NAME}" 2>&1 - die "Failed to copy config file" - fi + # 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" - # Ensure storage directory exists in container - docker exec "${CONTAINER_NAME}" mkdir -p /data/storage - if [ $? -ne 0 ]; then - log_warning "Could not create storage directory (may already exist)" - fi + sleep 3 # Wait for restart - # Restart the container to pick up the config file - log_info "Restarting container to load config..." - docker restart "${CONTAINER_NAME}" >/dev/null 2>&1 - if [ $? -ne 0 ]; then - log_error "Failed to restart container" - die "Failed to restart container" - fi - - # Give container more time to initialize after restart - sleep 5 - - # Verify port mapping after restart (it might change) + # Update port if changed after restart local new_port=$(docker port "${CONTAINER_NAME}" 80 | cut -d: -f2) - if [ -z "${new_port}" ]; then - log_error "Lost port mapping after restart" - docker logs "${CONTAINER_NAME}" 2>&1 | tail -20 - die "Container port mapping lost after restart" - fi - if [ "${new_port}" != "${TEST_PORT}" ]; then - log_info "Port changed after restart: ${TEST_PORT} -> ${new_port}" - TEST_PORT="${new_port}" - fi + [[ -z "$new_port" ]] && die "Lost port mapping after restart" + [[ "$new_port" != "$TEST_PORT" ]] && TEST_PORT="$new_port" && log_info "Port updated: ${TEST_PORT}" - # Get container IP address for Docker-in-Docker environments - CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${CONTAINER_NAME}") - if [ -z "${CONTAINER_IP}" ]; then - log_warning "Could not get container IP, will use localhost" - CONTAINER_IP="localhost" - else - log_info "Container IP address: ${CONTAINER_IP}" - fi + # 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}") - # Try to get the Docker host IP (gateway) for Docker-in-Docker - HOST_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' "${CONTAINER_NAME}") - if [ -n "${HOST_IP}" ]; then - log_info "Docker host IP (gateway): ${HOST_IP}" - fi - - # Check if container is still running - if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then - log_error "Container stopped unexpectedly. Logs:" - docker logs "${CONTAINER_NAME}" 2>&1 - - # Additional debugging for CI environment - log_error "Debug: Checking /data directory in container:" - docker exec "${CONTAINER_NAME}" ls -la /data/ 2>&1 || true - log_error "Debug: Config file in container:" - docker exec "${CONTAINER_NAME}" cat /data/sos_config.json 2>&1 || true - - die "Container failed to stay running" - fi - - # Wait for server to be ready - log_info "Waiting for server to be ready..." - local max_attempts=60 - local attempt=0 - - while [ $attempt -lt $max_attempts ]; do - # Try multiple connection methods for different environments - local http_code="000" - local container_code="000" - local host_code="000" - local local_code="000" - - # Try direct container IP on port 80 (might work in some Docker setups) - if [ "${CONTAINER_IP}" != "localhost" ]; then - container_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://${CONTAINER_IP}:80/" 2>/dev/null || echo "000") - if [ "$container_code" != "000" ] && [ "$container_code" != "" ]; then - http_code="$container_code" - fi - fi - - # Try host IP with mapped port (Docker-in-Docker) - if [ -n "${HOST_IP}" ]; then - host_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://${HOST_IP}:${TEST_PORT}/" 2>/dev/null || echo "000") - if [ "$host_code" != "000" ] && [ "$host_code" != "" ]; then - http_code="$host_code" - fi - fi - - # Try localhost with mapped port (local Docker) - local_code=$(curl -s --max-time 2 -o /dev/null -w "%{http_code}" "http://localhost:${TEST_PORT}/" 2>/dev/null || echo "000") - if [ "$local_code" != "000" ] && [ "$local_code" != "" ]; then - http_code="$local_code" - fi - - # Debug: Show HTTP codes from all attempts on first few tries - if [ $attempt -lt 3 ]; then - log_info "Health check attempt $((attempt + 1)):" - log_info " Container IP (${CONTAINER_IP}:80): ${container_code}" - log_info " Host IP (${HOST_IP}:${TEST_PORT}): ${host_code}" - log_info " Localhost (localhost:${TEST_PORT}): ${local_code}" - # Check if container is actually running - if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then - log_info "Container is running, checking logs..." - docker logs "${CONTAINER_NAME}" 2>&1 | tail -5 - else - log_error "Container is not running!" - fi - fi - - # Check if any method succeeded - if [ "$container_code" = "200" ] || [ "$container_code" = "204" ] || [ "$container_code" = "404" ]; then - export SOS_TEST_HOST="${CONTAINER_IP}:80" - log_info "Server is ready! Using container IP: ${SOS_TEST_HOST}" - return 0 - elif [ "$host_code" = "200" ] || [ "$host_code" = "204" ] || [ "$host_code" = "404" ]; then - export SOS_TEST_HOST="${HOST_IP}:${TEST_PORT}" - log_info "Server is ready! Using host IP: ${SOS_TEST_HOST}" - return 0 - elif [ "$local_code" = "200" ] || [ "$local_code" = "204" ] || [ "$local_code" = "404" ]; then - export SOS_TEST_HOST="localhost:${TEST_PORT}" - log_info "Server is ready! Using localhost: ${SOS_TEST_HOST}" - return 0 - fi - - # Check container is still running every 5 attempts - if [ $((attempt % 5)) -eq 0 ]; then - if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then - log_error "Container stopped while waiting. Logs:" - docker logs "${CONTAINER_NAME}" 2>&1 | tail -20 - die "Container stopped unexpectedly" - fi - # Show progress every 5 seconds - if [ $attempt -gt 0 ]; then - log_info "Still waiting for server... (${attempt}/${max_attempts})" - fi - fi - - sleep 1 - attempt=$((attempt + 1)) - done - - log_error "Server did not become ready. Container logs:" - docker logs "${CONTAINER_NAME}" 2>&1 | tail -20 - die "Server failed to start after ${max_attempts} seconds" + # Wait for server readiness and determine connection method + wait_for_server "$container_ip" "$host_ip" } -function test_upload() { +# 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 - local extra_labels="$@" - log_info "Testing upload: ${file} with label ${label}" + log_info "Testing upload: ${file##*/} with label ${label}" - export SOS_WRITE_TOKEN="${TEST_TOKEN}" - # Override to use HTTP for local testing - export SOS_TEST_MODE=1 - # Use the determined host (either container IP or localhost) - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - # For container IP, we use IP:80 directly, for localhost we use localhost:port - if [[ "${test_host}" == *":"* ]]; then - # Has port, use as is - "${SCRIPT_DIR}/sos" upload "${test_host}" "${file}" "${label}" ${extra_labels} 2>&1 | tee "${TEST_DIR}/upload_output.txt" - else - # No port, shouldn't happen but handle it - "${SCRIPT_DIR}/sos" upload "${test_host}:80" "${file}" "${label}" ${extra_labels} 2>&1 | tee "${TEST_DIR}/upload_output.txt" - fi - - if [ ${PIPESTATUS[0]} -ne 0 ]; then - log_error "Upload failed for ${file}" - return 1 - fi - - # Verify upload was successful - if grep -q "Download URL:" "${TEST_DIR}/upload_output.txt"; then - log_info "Upload successful for ${file}" + if run_sos_upload "$file" "$label" "$@" 2>&1 | tee "${TEST_DIR}/upload_output.txt" | grep -q "Download URL:"; then + log_info "Upload successful" return 0 else - log_error "Upload verification failed for ${file}" + log_error "Upload failed" return 1 fi } -function test_retrieval() { +test_retrieval() { local identifier="$1" - local expected_content="$2" + local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - log_info "Testing retrieval by ${identifier}" + log_info "Testing retrieval: ${identifier}" - # Try to retrieve the file using the determined host - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - local response=$(curl -s "http://${test_host}/${identifier}") + local response=$(curl -s "http://${host}/${identifier}") + [[ -z "$response" ]] && log_error "Retrieval failed" && return 1 - if [ -z "${response}" ]; then - log_error "Failed to retrieve by ${identifier}" - return 1 - fi - - # For hash retrieval, test the actual hash endpoint - if [[ "${identifier}" =~ ^[a-f0-9]{64}$ ]]; then - local meta_response=$(curl -s "http://${test_host}/meta/${identifier}") - if echo "${meta_response}" | jq -e '.metadata' >/dev/null 2>&1; then - log_info "Successfully retrieved metadata for hash ${identifier}" - else - log_error "Failed to retrieve metadata for hash ${identifier}" + # 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 + } fi - log_info "Retrieval successful for ${identifier}" + log_info "Retrieval successful" return 0 } -function test_duplicate_upload() { - log_info "Testing duplicate file upload (deduplication)..." +test_deduplication() { + log_info "Testing deduplication..." - # Create a duplicate file with different name + # Create duplicate file cp "${TEST_DIR}/test_files/test1.txt" "${TEST_DIR}/test_files/test1_dup.txt" - export SOS_WRITE_TOKEN="${TEST_TOKEN}" - export SOS_TEST_MODE=1 + # 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) - # Use the determined host - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - - # Upload original - "${SCRIPT_DIR}/sos" upload "${test_host}" "${TEST_DIR}/test_files/test1.txt" "dup:original" >/dev/null 2>&1 - - # Upload duplicate (should detect existing file) - local output=$("${SCRIPT_DIR}/sos" upload "${test_host}" "${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 correctly" + if echo "$output" | grep -q "File already exists, skipping upload"; then + log_info "Deduplication working" return 0 else - log_error "Deduplication test failed" + log_error "Deduplication failed" return 1 fi } -function test_metadata_update() { +test_metadata_update() { log_info "Testing metadata update..." - export SOS_WRITE_TOKEN="${TEST_TOKEN}" - export SOS_TEST_MODE=1 + 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) - # Use the determined host - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - - # Upload a file - "${SCRIPT_DIR}/sos" upload "${test_host}" "${TEST_DIR}/test_files/test2.txt" "meta:v1" >/dev/null 2>&1 - - # Upload same file with different metadata - local output=$("${SCRIPT_DIR}/sos" upload "${test_host}" "${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 successful" + if echo "$output" | grep -q "File already exists"; then + log_info "Metadata update working" return 0 else - log_error "Metadata update test failed" + log_error "Metadata update failed" return 1 fi } -function test_exists_endpoint() { - log_info "Testing exists endpoint..." +test_api_endpoints() { + log_info "Testing API endpoints..." + local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - # Use the determined host - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - - # Get hash of an uploaded file - local hash=$(curl -s "http://${test_host}/hash/test:file1" | jq -r '.hash') - - if [ -z "${hash}" ] || [ "${hash}" = "null" ]; then - log_error "Failed to get hash for exists test" - return 1 - fi + # 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://${test_host}/exists/${hash}" | jq -r '.exists') + local exists=$(curl -s "http://${host}/exists/${hash}" | jq -r '.exists') + [[ "$exists" != "true" ]] && log_error "Exists endpoint failed" && return 1 - if [ "${exists}" = "true" ]; then - log_info "Exists endpoint working correctly" - return 0 - else - log_error "Exists endpoint test failed" - return 1 - fi + log_info "API endpoints working" + return 0 } -function test_invalid_auth() { +test_invalid_auth() { log_info "Testing invalid authentication..." - # Create a unique test file for this test - echo "auth test content" > "${TEST_DIR}/test_files/auth_test.txt" - + echo "auth test" > "${TEST_DIR}/test_files/auth_test.txt" export SOS_WRITE_TOKEN="invalid-token" export SOS_TEST_MODE=1 - # Use the determined host - local test_host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" + local host="${SOS_TEST_HOST:-localhost:${TEST_PORT}}" - # Run upload with invalid token and capture output + exit code - set +e # Temporarily disable exit on error - "${SCRIPT_DIR}/sos" upload "${test_host}" "${TEST_DIR}/test_files/auth_test.txt" "auth:test" 2>&1 | tee "${TEST_DIR}/auth_test_output.txt" - local exit_code=${PIPESTATUS[0]} - set -e # Re-enable exit on error + # 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_test_output.txt") + local output=$(cat "${TEST_DIR}/auth_output.txt") - # Check if it failed with non-zero exit code and error message - if [ ${exit_code} -ne 0 ] && (echo "${output}" | grep -q "Failed to upload" || echo "${output}" | grep -q "Invalid write token"); then - log_info "Invalid auth correctly rejected" + # 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 test failed - upload should have been rejected (exit code: ${exit_code})" - echo "Output was: ${output}" + log_error "Invalid auth not rejected properly (exit code: $exit_code)" + echo "Output:" && echo "$output" | head -5 return 1 fi } -function run_tests() { - local total_tests=0 - local passed_tests=0 +# 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" + ) - # Disable exit on error for test functions - set +e + local total=${#tests[@]} + local passed=0 - log_info "Starting test suite..." + log_info "Running ${total} tests..." echo "" - # Test 1: Basic upload - ((total_tests++)) - test_upload "${TEST_DIR}/test_files/test1.txt" "test:file1" - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 2: Upload with multiple labels - ((total_tests++)) - test_upload "${TEST_DIR}/test_files/test2.txt" "test:file2" "version:1.0" "env:test" - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 3: Binary file upload - ((total_tests++)) - test_upload "${TEST_DIR}/test_files/binary_test.bin" "binary:test" - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 4: Upload sos binary itself - ((total_tests++)) - test_upload "${TEST_DIR}/test_files/sos_binary" "sos:test" "sos:latest" - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 5: Retrieval by label - ((total_tests++)) - test_retrieval "test:file1" "This is test file 1" - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 6: Deduplication - ((total_tests++)) - test_duplicate_upload - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 7: Metadata update - ((total_tests++)) - test_metadata_update - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 8: Exists endpoint - ((total_tests++)) - test_exists_endpoint - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Test 9: Invalid authentication - ((total_tests++)) - test_invalid_auth - if [ $? -eq 0 ]; then - ((passed_tests++)) - fi - echo "" - - # Re-enable exit on error + set +e # Don't exit on test failures + for test in "${tests[@]}"; do + eval "$test" && ((passed++)) || true + echo "" + done set -e # Summary echo "==================================" - if [ ${passed_tests} -eq ${total_tests} ]; then - echo -e "${GREEN}All tests passed!${NC} (${passed_tests}/${total_tests})" + 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_tests}/${total_tests})" + echo -e "${RED}Some tests failed!${NC} (${passed}/${total})" return 1 fi } -function main() { +# Main execution +main() { echo "SOS Test Suite" echo "==============" echo "" @@ -587,19 +322,15 @@ function main() { start_test_server echo "" - run_tests - local test_result=$? + local result=0 + run_tests || result=$? echo "" log_info "Test suite completed" - # Show container logs if tests failed - if [ ${test_result} -ne 0 ]; then - log_warning "Showing server logs for debugging:" - docker logs "${CONTAINER_NAME}" 2>&1 | tail -20 - fi + [[ $result -ne 0 ]] && log_warning "Server logs:" && docker logs "${CONTAINER_NAME}" 2>&1 | tail -10 - exit ${test_result} + exit $result } main "$@" \ No newline at end of file