334 lines
11 KiB
Bash
334 lines
11 KiB
Bash
#!/bin/bash
|
|
# Test script for PISCAL Docker image
|
|
# Verifies build, executable presence, and basic functionality
|
|
|
|
set -e # Exit on any error
|
|
|
|
IMAGE_NAME="piscal-server"
|
|
IMAGE_TAG="test"
|
|
TEST_CONTAINER="piscal-test-$$"
|
|
TEST_DIR=$(mktemp -d)
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Cleanup function
|
|
cleanup() {
|
|
echo -e "\n${YELLOW}Cleaning up...${NC}"
|
|
docker rm -f "$TEST_CONTAINER" 2>/dev/null || true
|
|
rm -rf "$TEST_DIR" 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# Test counter
|
|
TESTS_PASSED=0
|
|
TESTS_FAILED=0
|
|
|
|
# Test function
|
|
run_test() {
|
|
local test_name="$1"
|
|
echo -e "\n${YELLOW}Testing: $test_name${NC}"
|
|
if eval "$2"; then
|
|
echo -e "${GREEN}✓ PASS: $test_name${NC}"
|
|
((TESTS_PASSED++))
|
|
return 0
|
|
else
|
|
echo -e "${RED}✗ FAIL: $test_name${NC}"
|
|
((TESTS_FAILED++))
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
echo "=========================================="
|
|
echo "PISCAL Docker Image Test Suite"
|
|
echo "=========================================="
|
|
|
|
# Test 1: Build verification
|
|
run_test "Docker image builds successfully" "
|
|
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} . > /dev/null 2>&1
|
|
"
|
|
|
|
# Test 2: Executable check
|
|
run_test "PISCAL executable exists at /srv/piscal" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -f /srv/piscal
|
|
"
|
|
|
|
run_test "PISCAL executable is executable" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -x /srv/piscal
|
|
"
|
|
|
|
run_test "PISCAL executable can be executed (version check)" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} /srv/piscal --help > /dev/null 2>&1 || \
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} /srv/piscal 2>&1 | head -1 > /dev/null
|
|
"
|
|
|
|
# Test 3: Manager scripts check
|
|
run_test "piscal_manager.sh exists and is executable" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -x /srv/piscal_manager.sh
|
|
"
|
|
|
|
run_test "piscal_launcher.sh exists and is executable" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -x /srv/piscal_launcher.sh
|
|
"
|
|
|
|
run_test "piscal_launcher.cfg exists" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -f /srv/piscal_launcher.cfg
|
|
"
|
|
|
|
run_test "subdir_year.sh exists and is executable" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -x /srv/subdir_year.sh
|
|
"
|
|
|
|
# Test 4: SSH configuration
|
|
run_test "SSH server is installed" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} which sshd > /dev/null
|
|
"
|
|
|
|
run_test "launcher user exists" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} id launcher > /dev/null
|
|
"
|
|
|
|
run_test "launcher user is in sudo group" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} groups launcher | grep -q sudo
|
|
"
|
|
|
|
run_test "/run/sshd directory exists" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} test -d /run/sshd
|
|
"
|
|
|
|
# Test 5: Functional test with piscal_manager.sh - test all status states
|
|
run_test "piscal_manager.sh: Status 'not started' for new directory" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} bash -c '
|
|
mkdir -p /srv/test_status/input
|
|
cd /srv
|
|
status=\$(bash piscal_manager.sh -d test_status 2>&1)
|
|
echo \"\$status\" | grep -q \"not started\"
|
|
'
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Error handling - missing directory" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} bash -c '
|
|
cd /srv
|
|
status=\$(bash piscal_manager.sh -d nonexistent_dir 2>&1)
|
|
echo \"\$status\" | grep -q \"not found\"
|
|
'
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Error handling - missing input directory" "
|
|
docker run --rm ${IMAGE_NAME}:${IMAGE_TAG} bash -c '
|
|
mkdir -p /srv/test_noinput
|
|
cd /srv
|
|
status=\$(bash piscal_manager.sh -d test_noinput 2>&1)
|
|
echo \"\$status\" | grep -q \"input directory.*not found\"
|
|
'
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Launch job returns 'started' status" "
|
|
# Create test directory structure
|
|
mkdir -p \"${TEST_DIR}/input\"
|
|
cp \"${SCRIPT_DIR}/sample_data/LeafInput-valid.csv\" \"${TEST_DIR}/input/\"
|
|
|
|
# Start container with test data mounted
|
|
docker run -d --name \"${TEST_CONTAINER}\" \
|
|
-v \"${TEST_DIR}:/test\" \
|
|
${IMAGE_NAME}:${IMAGE_TAG} \
|
|
tail -f /dev/null > /dev/null 2>&1
|
|
|
|
# Wait for container to be ready
|
|
sleep 2
|
|
|
|
# Create working directory structure inside container (relative to /srv)
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
mkdir -p /srv/test_work/input
|
|
cp /test/input/*.csv /srv/test_work/input/ 2>/dev/null || true
|
|
'
|
|
|
|
# Launch job using piscal_manager.sh
|
|
result=\$(docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_work -p C3_photosynthesis_leafweb -s -t 2>&1
|
|
')
|
|
|
|
# Check for 'started' status
|
|
echo \"\$result\" | grep -q \"started\"
|
|
|
|
# Clean up test container
|
|
docker rm -f \"${TEST_CONTAINER}\" > /dev/null 2>&1 || true
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Status 'running' while job is active" "
|
|
# Create test directory structure
|
|
mkdir -p \"${TEST_DIR}/input\"
|
|
cp \"${SCRIPT_DIR}/sample_data/LeafInput-valid.csv\" \"${TEST_DIR}/input/\"
|
|
|
|
# Start container with test data mounted
|
|
docker run -d --name \"${TEST_CONTAINER}\" \
|
|
-v \"${TEST_DIR}:/test\" \
|
|
${IMAGE_NAME}:${IMAGE_TAG} \
|
|
tail -f /dev/null > /dev/null 2>&1
|
|
|
|
# Wait for container to be ready
|
|
sleep 2
|
|
|
|
# Create working directory structure inside container (relative to /srv)
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
mkdir -p /srv/test_running/input
|
|
cp /test/input/*.csv /srv/test_running/input/ 2>/dev/null || true
|
|
'
|
|
|
|
# Launch job in background
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_running -p C3_photosynthesis_leafweb -s -t > /dev/null 2>&1
|
|
' || true
|
|
|
|
# Wait a moment for job to start
|
|
sleep 1
|
|
|
|
# Check status (should be 'running' or 'complete' depending on speed)
|
|
status=\$(docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_running 2>&1 | head -1
|
|
')
|
|
|
|
# Status should be either 'running' or 'complete'
|
|
echo \"\$status\" | grep -qE \"^(running|complete)\$\"
|
|
|
|
# Clean up test container
|
|
docker rm -f \"${TEST_CONTAINER}\" > /dev/null 2>&1 || true
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Cannot launch if already running" "
|
|
# Create test directory structure
|
|
mkdir -p \"${TEST_DIR}/input\"
|
|
cp \"${SCRIPT_DIR}/sample_data/LeafInput-valid.csv\" \"${TEST_DIR}/input/\"
|
|
|
|
# Start container with test data mounted
|
|
docker run -d --name \"${TEST_CONTAINER}\" \
|
|
-v \"${TEST_DIR}:/test\" \
|
|
${IMAGE_NAME}:${IMAGE_TAG} \
|
|
tail -f /dev/null > /dev/null 2>&1
|
|
|
|
# Wait for container to be ready
|
|
sleep 2
|
|
|
|
# Create working directory structure inside container (relative to /srv)
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
mkdir -p /srv/test_already/input
|
|
cp /test/input/*.csv /srv/test_already/input/ 2>/dev/null || true
|
|
'
|
|
|
|
# Create a fake running process by creating PID file with current shell PID
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
echo \$\$ > /srv/test_already/piscal.pid
|
|
'
|
|
|
|
# Try to launch - should fail with 'still running'
|
|
result=\$(docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_already -p C3_photosynthesis_leafweb -s -t 2>&1
|
|
' || echo \"still running\")
|
|
|
|
# Check for 'still running' status
|
|
echo \"\$result\" | grep -q \"still running\"
|
|
|
|
# Clean up test container
|
|
docker rm -f \"${TEST_CONTAINER}\" > /dev/null 2>&1 || true
|
|
"
|
|
|
|
run_test "piscal_manager.sh: Status 'complete' with output verification" "
|
|
# Create test directory structure
|
|
mkdir -p \"${TEST_DIR}/input\"
|
|
cp \"${SCRIPT_DIR}/sample_data/LeafInput-valid.csv\" \"${TEST_DIR}/input/\"
|
|
|
|
# Start container with test data mounted
|
|
docker run -d --name \"${TEST_CONTAINER}\" \
|
|
-v \"${TEST_DIR}:/test\" \
|
|
${IMAGE_NAME}:${IMAGE_TAG} \
|
|
tail -f /dev/null > /dev/null 2>&1
|
|
|
|
# Wait for container to be ready
|
|
sleep 2
|
|
|
|
# Create working directory structure inside container (relative to /srv)
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
mkdir -p /srv/test_complete/input
|
|
cp /test/input/*.csv /srv/test_complete/input/ 2>/dev/null || true
|
|
'
|
|
|
|
# Launch job using piscal_manager.sh
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_complete -p C3_photosynthesis_leafweb -s -t > /dev/null 2>&1
|
|
' || true
|
|
|
|
# Wait for job to complete (with timeout) - use a script inside container
|
|
docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
max_wait=120
|
|
wait_time=0
|
|
status=\"\"
|
|
while [ \$wait_time -lt \$max_wait ]; do
|
|
cd /srv
|
|
status=\$(bash piscal_manager.sh -d test_complete 2>&1 | head -1)
|
|
if echo \"\$status\" | grep -q \"complete\"; then
|
|
break
|
|
fi
|
|
if echo \"\$status\" | grep -q \"not started\"; then
|
|
sleep 2
|
|
wait_time=\$((wait_time + 2))
|
|
continue
|
|
fi
|
|
if echo \"\$status\" | grep -q \"running\"; then
|
|
sleep 5
|
|
wait_time=\$((wait_time + 5))
|
|
continue
|
|
fi
|
|
break
|
|
done
|
|
# Verify status is complete
|
|
echo \"\$status\" | grep -q \"complete\"
|
|
'
|
|
|
|
# Get full status output to verify output structure
|
|
full_output=\$(docker exec \"${TEST_CONTAINER}\" bash -c '
|
|
cd /srv
|
|
bash piscal_manager.sh -d test_complete 2>&1
|
|
')
|
|
|
|
# Verify output contains the expected markers
|
|
echo \"\$full_output\" | grep -q \"#touser\"
|
|
echo \"\$full_output\" | grep -q \"#clninput\"
|
|
echo \"\$full_output\" | grep -q \"#nottouser\"
|
|
|
|
# Verify output directories exist
|
|
docker exec \"${TEST_CONTAINER}\" test -d /srv/test_complete/output/fitresult/touser
|
|
docker exec \"${TEST_CONTAINER}\" test -d /srv/test_complete/output/clninput
|
|
docker exec \"${TEST_CONTAINER}\" test -d /srv/test_complete/output/fitresult/nottouser
|
|
|
|
# Verify output directories contain files (at least one file should exist)
|
|
touser_files=\$(docker exec \"${TEST_CONTAINER}\" bash -c 'find /srv/test_complete/output/fitresult/touser -type f 2>/dev/null | wc -l')
|
|
[ \"\$touser_files\" -gt 0 ]
|
|
|
|
# Clean up test container
|
|
docker rm -f \"${TEST_CONTAINER}\" > /dev/null 2>&1 || true
|
|
"
|
|
|
|
# Summary
|
|
echo ""
|
|
echo "=========================================="
|
|
echo "Test Summary"
|
|
echo "=========================================="
|
|
echo -e "${GREEN}Passed: ${TESTS_PASSED}${NC}"
|
|
if [ $TESTS_FAILED -gt 0 ]; then
|
|
echo -e "${RED}Failed: ${TESTS_FAILED}${NC}"
|
|
exit 1
|
|
else
|
|
echo -e "${GREEN}Failed: ${TESTS_FAILED}${NC}"
|
|
echo -e "\n${GREEN}All tests passed!${NC}"
|
|
exit 0
|
|
fi
|