diff --git a/.github/scripts/test-install-script.sh b/.github/scripts/test-install-script.sh new file mode 100755 index 000000000..9294f8f35 --- /dev/null +++ b/.github/scripts/test-install-script.sh @@ -0,0 +1,412 @@ +#!/usr/bin/env bash +# Test script for installTorrServerLinux.sh +# This script runs inside Docker containers to test the installation script + +set -e + +# Colors for output +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Test configuration +readonly SCRIPT_NAME="installTorrServerLinux.sh" +readonly INSTALL_DIR="/opt/torrserver" +readonly GLIBC_LIMITED_VERSION="135" +readonly MIN_GLIBC_VERSION="2.32" +readonly MAX_RETRIES="${MAX_RETRIES:-3}" +readonly RETRY_DELAY="${RETRY_DELAY:-2}" + +# Helper functions +log_info() { + echo -e "${GREEN}✓${NC} $1" +} + +log_error() { + echo -e "${RED}✗${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +log_test() { + echo "Test $1: $2" +} + +# Check if OS requires glibc-limited version +is_glibc_limited_os() { + local os="$1" + local glibc_limited_oses="$2" + echo "$glibc_limited_oses" | grep -qE "(^|\|)$os(\||$)" +} + +# Get glibc version message for OS +get_glibc_message() { + local os="$1" + case "$os" in + debian-11) + echo "Note: Debian 11 has glibc 2.31, installing version $GLIBC_LIMITED_VERSION (version 136+ requires glibc >= $MIN_GLIBC_VERSION)" + ;; + almalinux-8) + echo "Note: AlmaLinux 8 has glibc 2.28, installing version $GLIBC_LIMITED_VERSION (version 136+ requires glibc >= $MIN_GLIBC_VERSION)" + ;; + rocky-8) + echo "Note: Rocky 8 has glibc 2.28, installing version $GLIBC_LIMITED_VERSION (version 136+ requires glibc >= $MIN_GLIBC_VERSION)" + ;; + amazonlinux-2) + echo "Note: Amazon Linux 2 has glibc 2.26, installing version $GLIBC_LIMITED_VERSION (version 136+ requires glibc >= $MIN_GLIBC_VERSION)" + ;; + esac +} + +# Install RPM packages (dnf/yum) +install_rpm_packages() { + local pkg_manager="$1" + shift + local packages=("$@") + + "$pkg_manager" makecache -q || true + # Always remove curl-minimal first to avoid conflicts + "$pkg_manager" remove -y -q curl-minimal 2>/dev/null || true + + # Check if curl package is installed (not just curl-minimal) + if rpm -qa curl >/dev/null 2>&1; then + # curl package is already installed, just install other packages + "$pkg_manager" install -y -q "${packages[@]}" || true + else + # curl package not installed, install curl with --allowerasing + "$pkg_manager" install -y -q --allowerasing curl "${packages[@]}" || true + fi +} + +# Install dependencies based on OS +install_dependencies() { + if command -v apt-get >/dev/null 2>&1; then + retry_command "apt-get update" "apt-get update -qq" 3 1 || true + retry_command "apt-get install" "apt-get install -y -qq curl iputils-ping dnsutils" 3 1 || true + elif command -v dnf >/dev/null 2>&1; then + retry_command "dnf install" "install_rpm_packages dnf iputils bind-utils" 3 1 || true + elif command -v yum >/dev/null 2>&1; then + retry_command "yum install" "install_rpm_packages yum iputils bind-utils" 3 1 || true + fi +} + +# Verify curl installation +verify_curl_installation() { + if command -v rpm >/dev/null 2>&1; then + if ! rpm -qa curl >/dev/null 2>&1; then + log_error "curl package is not installed after dependency installation" + exit 1 + fi + # Verify curl-minimal is not present (it should have been removed) + if rpm -qa curl-minimal >/dev/null 2>&1; then + log_warning "curl-minimal is still installed, removing it..." + rpm -e --nodeps curl-minimal 2>/dev/null || true + fi + elif command -v dpkg >/dev/null 2>&1; then + if ! dpkg -s curl >/dev/null 2>&1; then + log_error "curl package is not installed after dependency installation" + exit 1 + fi + fi +} + +# Retry a command with exponential backoff +retry_command() { + local test_name="$1" + local test_command="$2" + local max_attempts="${3:-$MAX_RETRIES}" + local delay="${4:-$RETRY_DELAY}" + local attempt=1 + local last_error=0 + + # Print command before first attempt + if [[ $attempt -eq 1 ]]; then + echo "Executing: $test_command" + fi + + while [[ $attempt -le $max_attempts ]]; do + if [[ $attempt -gt 1 ]]; then + echo "Retry attempt $attempt/$max_attempts: $test_command" + fi + if eval "$test_command"; then + if [[ $attempt -gt 1 ]]; then + log_info "$test_name (succeeded on attempt $attempt)" + fi + return 0 + else + last_error=$? + if [[ $attempt -lt $max_attempts ]]; then + log_warning "$test_name failed (attempt $attempt/$max_attempts), retrying in ${delay}s..." + sleep "$delay" + delay=$((delay * 2)) + fi + attempt=$((attempt + 1)) + fi + done + + log_error "$test_name (failed after $max_attempts attempts)" + return $last_error +} + +# Run a test command and handle errors +run_test() { + local test_name="$1" + local test_command="$2" + local skip_on_error="${3:-false}" + local use_retry="${4:-true}" + + if [[ "$use_retry" == "true" ]]; then + if retry_command "$test_name" "$test_command"; then + log_info "$test_name" + return 0 + else + if [[ "$skip_on_error" == "true" ]]; then + log_warning "$test_name (skipped after retries)" + return 0 + else + log_error "$test_name" + return 1 + fi + fi + else + if eval "$test_command"; then + log_info "$test_name" + return 0 + else + if [[ "$skip_on_error" == "true" ]]; then + log_warning "$test_name (skipped)" + return 0 + else + log_error "$test_name" + return 1 + fi + fi + fi +} + +# Main test execution +main() { + local matrix_os="${MATRIX_OS:-}" + local test_user="${TEST_USER:-default}" + local glibc_limited_oses="${GLIBC_LIMITED_OSES:-}" + + # Determine root flag + local root_flag='' + if [[ "$test_user" == 'root' ]]; then + root_flag='--root' + fi + + # Check if OS requires glibc-limited version + local is_glibc_limited=false + if is_glibc_limited_os "$matrix_os" "$glibc_limited_oses"; then + is_glibc_limited=true + fi + + echo "========================================" + echo "Testing $SCRIPT_NAME" + echo "OS: $matrix_os" + echo "User: $test_user" + echo "Retry settings: max=$MAX_RETRIES, initial_delay=${RETRY_DELAY}s" + echo "========================================" + echo "" + + # Test 1: Check script syntax + echo "::group::Test 1: Check script syntax" + log_test "1" "Checking script syntax..." + echo "Executing: bash -n $SCRIPT_NAME" + if bash -n "$SCRIPT_NAME"; then + log_info "Script syntax is valid" + else + log_error "Script syntax check failed" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 2: Show help + echo "::group::Test 2: Test help command" + log_test "2" "Testing help command..." + echo "Executing: ./$SCRIPT_NAME --help" + if ./"$SCRIPT_NAME" --help > /dev/null; then + log_info "Help command works" + else + log_error "Help command failed" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 3: Install in silent mode + echo "::group::Test 3: Install TorrServer" + log_test "3" "Installing TorrServer (silent mode)..." + if [[ "$is_glibc_limited" == "true" ]]; then + local glibc_msg + glibc_msg=$(get_glibc_message "$matrix_os") + if [[ -n "$glibc_msg" ]]; then + echo "$glibc_msg" + fi + if retry_command "Installation" "./$SCRIPT_NAME --install $GLIBC_LIMITED_VERSION --silent $root_flag"; then + log_info "Installation completed" + else + log_error "Installation failed after retries" + echo "::endgroup::" + exit 1 + fi + else + if retry_command "Installation" "./$SCRIPT_NAME --install --silent $root_flag"; then + log_info "Installation completed" + else + log_error "Installation failed after retries" + echo "::endgroup::" + exit 1 + fi + fi + echo "::endgroup::" + echo "" + + # Test 4: Check installation + echo "::group::Test 4: Verify installation" + log_test "4" "Checking installation..." + echo "Executing: ls $INSTALL_DIR/TorrServer-linux-*" + if ls "$INSTALL_DIR"/TorrServer-linux-* >/dev/null 2>&1; then + log_info "Binary file exists" + else + log_error "Binary file not found" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 5: Check version + echo "::group::Test 5: Check version" + log_test "5" "Checking for updates..." + if [[ "$is_glibc_limited" == "true" ]]; then + echo "Note: Skipping version check (latest version requires glibc >= $MIN_GLIBC_VERSION)" + log_info "Version check skipped (expected)" + else + if retry_command "Version check" "./$SCRIPT_NAME --check --silent $root_flag"; then + log_info "Version check completed" + else + log_error "Version check failed after retries" + echo "::endgroup::" + exit 1 + fi + fi + echo "::endgroup::" + echo "" + + # Test 6: Update (if available) + echo "::group::Test 6: Test update command" + log_test "6" "Testing update command..." + if [[ "$is_glibc_limited" == "true" ]]; then + echo "Note: Skipping update test (latest version requires glibc >= $MIN_GLIBC_VERSION)" + log_info "Update check skipped (expected)" + else + if retry_command "Update check" "./$SCRIPT_NAME --update --silent $root_flag"; then + log_info "Update check completed" + else + log_error "Update check failed after retries" + echo "::endgroup::" + exit 1 + fi + fi + echo "::endgroup::" + echo "" + + # Test 7: Reconfigure + echo "::group::Test 7: Test reconfigure command" + log_test "7" "Testing reconfigure command..." + if retry_command "Reconfigure" "./$SCRIPT_NAME --reconfigure --silent $root_flag"; then + log_info "Reconfigure completed" + else + log_error "Reconfigure failed after retries" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 8: Change user (if not already root) + if [[ "$test_user" == 'default' ]]; then + echo "::group::Test 8: Test change-user to root" + log_test "8" "Testing change-user to root..." + if retry_command "User change to root" "./$SCRIPT_NAME --change-user root --silent"; then + log_info "User change to root completed" + else + log_error "User change to root failed after retries" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 8b: Change user back to default (only for Ubuntu to test full flow) + if [[ "$matrix_os" == 'ubuntu-22.04' ]] || [[ "$matrix_os" == 'ubuntu-24.04' ]]; then + echo "::group::Test 8b: Test change-user back to default" + log_test "8b" "Testing change-user back to default..." + if retry_command "User change back to default" "./$SCRIPT_NAME --change-user torrserver --silent"; then + log_info "User change back to default completed" + else + log_error "User change back to default failed after retries" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + fi + fi + + # Test 9: Cleanup - Uninstall + echo "::group::Test 9: Uninstall TorrServer" + log_test "9" "Uninstalling TorrServer..." + if retry_command "Uninstallation" "./$SCRIPT_NAME --remove --silent"; then + log_info "Uninstallation completed" + else + log_error "Uninstallation failed after retries" + echo "::endgroup::" + exit 1 + fi + echo "::endgroup::" + echo "" + + # Test 10: Verify cleanup + echo "::group::Test 10: Verify cleanup" + log_test "10" "Verifying cleanup..." + echo "Executing: Checking if $INSTALL_DIR is empty or doesn't exist" + if [[ ! -d "$INSTALL_DIR" ]] || [[ -z "$(ls -A "$INSTALL_DIR" 2>/dev/null)" ]]; then + log_info "Cleanup verified" + else + log_warning "Installation directory still exists (may be expected)" + fi + echo "::endgroup::" + echo "" + + echo "========================================" + echo "All tests passed! ✓" + echo "========================================" +} + +# Setup and run tests +setup() { + echo "::group::Setup: Install dependencies" + # Install dependencies + install_dependencies + + # Verify curl installation + verify_curl_installation + + # Make script executable + chmod +x "$SCRIPT_NAME" + echo "::endgroup::" + echo "" +} + +# Run setup and main +setup +main diff --git a/.github/workflows/test-install-script.yml b/.github/workflows/test-install-script.yml new file mode 100644 index 000000000..4ae94b252 --- /dev/null +++ b/.github/workflows/test-install-script.yml @@ -0,0 +1,122 @@ +name: Test Install Script + +on: + push: + branches: + - master + paths: + - "installTorrServerLinux.sh" + - ".github/workflows/test-install-script.yml" + - ".github/scripts/test-install-script.sh" + pull_request: + branches: + - master + paths: + - "installTorrServerLinux.sh" + - ".github/workflows/test-install-script.yml" + - ".github/scripts/test-install-script.sh" + workflow_dispatch: + +# OSes that require version 135 due to glibc < 2.32 +# Version 136+ requires glibc >= 2.32 +env: + GLIBC_LIMITED_OSES: "debian-11|almalinux-8|rocky-8|amazonlinux-2" + MAX_RETRIES: "3" + RETRY_DELAY: "60" + +jobs: + test-script-syntax: + name: Test Script Syntax + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Test script syntax + run: | + chmod +x installTorrServerLinux.sh + bash -n installTorrServerLinux.sh + echo "✓ Script syntax is valid" + + - name: Test help command + run: | + ./installTorrServerLinux.sh --help > /dev/null + ./installTorrServerLinux.sh help > /dev/null + echo "✓ Help command works" + + test-install-script: + name: Test on ${{ matrix.os }} (${{ matrix.test-user }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: + - ubuntu-22.04 + - ubuntu-24.04 + - debian-11 + - debian-12 + - debian-13 + - fedora-latest + - almalinux-8 + - almalinux-9 + - almalinux-10 + - rocky-8 + - rocky-9 + - rocky-10 + - amazonlinux-2 + test-user: [root, default] + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Get Docker image for OS + id: get-image + run: | + # Map OS to Docker image + case "${{ matrix.os }}" in + ubuntu-22.04) IMAGE="ubuntu:22.04" ;; + ubuntu-24.04) IMAGE="ubuntu:24.04" ;; + debian-11) IMAGE="debian:11" ;; + debian-12) IMAGE="debian:12" ;; + debian-13) IMAGE="debian:13" ;; + fedora-latest) IMAGE="fedora:latest" ;; + almalinux-8) IMAGE="almalinux:8" ;; + almalinux-9) IMAGE="almalinux:9" ;; + almalinux-10) IMAGE="almalinux:10" ;; + rocky-8) IMAGE="rockylinux/rockylinux:8" ;; + rocky-9) IMAGE="rockylinux/rockylinux:9" ;; + rocky-10) IMAGE="rockylinux/rockylinux:10" ;; + amazonlinux-2) IMAGE="amazonlinux:2" ;; + *) + echo "Warning: Unknown OS ${{ matrix.os }}, using ubuntu:22.04 as default" + IMAGE="ubuntu:22.04" + ;; + esac + echo "image=$IMAGE" >> $GITHUB_OUTPUT + echo "Using Docker image: $IMAGE for OS: ${{ matrix.os }}" + + - name: Run tests in container + run: | + docker run --rm \ + -v "$PWD:/workspace" \ + -w /workspace \ + --privileged \ + -e MATRIX_OS="${{ matrix.os }}" \ + -e TEST_USER="${{ matrix.test-user }}" \ + -e GLIBC_LIMITED_OSES="${{ env.GLIBC_LIMITED_OSES }}" \ + -e MAX_RETRIES="${{ env.MAX_RETRIES }}" \ + -e RETRY_DELAY="${{ env.RETRY_DELAY }}" \ + "${{ steps.get-image.outputs.image }}" \ + bash -c " + set -e + + # Make test script executable + chmod +x .github/scripts/test-install-script.sh + + # Run the test script + .github/scripts/test-install-script.sh + " diff --git a/installTorrServerLinux.sh b/installTorrServerLinux.sh index 9240e9d6c..1d906a658 100755 --- a/installTorrServerLinux.sh +++ b/installTorrServerLinux.sh @@ -1232,12 +1232,6 @@ configureService() { else # Auth setting exists, ask if user wants to change it if [[ $SILENT_MODE -eq 0 ]]; then - local current_auth_status - if [[ $isAuth -eq 1 ]]; then - current_auth_status="enabled" - else - current_auth_status="disabled" - fi if promptYesNo "$(msg enable_auth)" "$([[ $isAuth -eq 1 ]] && echo 'y' || echo 'n')"; then isAuth=1 else