#!/usr/bin/env bash # Тесты пакетного установщика proxy-client/install.sh во временном HOME. set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TEST_TMP_ROOT="$(mktemp -d /tmp/proxy-client-install-test.XXXXXX)" trap 'rm -rf "$TEST_TMP_ROOT"' EXIT fail() { echo "FAIL: $*" >&2 exit 1 } ok() { echo "ok - $*" } assert_link_points_to() { local link_path="$1" expected_path="$2" [ -L "$link_path" ] || fail "нет ссылки $link_path" [ "$(readlink -f "$link_path")" = "$expected_path" ] \ || fail "$link_path указывает не на $expected_path" } assert_not_exists() { [ ! -e "$1" ] && [ ! -L "$1" ] || fail "путь не должен существовать: $1" } assert_package_links() { local package_dir="$1" home_dir="$2" link for link in .local/bin/proxy-client .config/proxy-client/shell.bash \ .config/proxy-client/examples; do assert_link_points_to "$home_dir/$link" "$package_dir/$link" done } # Копия пакета в пути с пробелами и машинными файлами, которые установщик # не должен трогать. Печатает путь к пакету; HOME создаётся рядом. new_fixture() { local fixture package_dir fixture="$(mktemp -d "$TEST_TMP_ROOT/fixture.XXXXXX")" package_dir="$fixture/source with spaces/proxy-client" mkdir -p "$package_dir" "$fixture/home" cp -a "$REPO_ROOT/proxy-client/." "$package_dir/" printf 'MACHINE_CONFIG_SENTINEL\n' > "$package_dir/.config/proxy-client/config" printf 'PRIVATE_PROFILE_SENTINEL\n' > "$package_dir/.config/proxy-client/default.url" printf '%s\n' "$fixture" } run_install() { local fixture="$1" shift (cd "$TEST_TMP_ROOT" && HOME="$fixture/home" \ "$fixture/source with spaces/proxy-client/install.sh" "$@") } home_snapshot() { find "$1" -printf '%p %y %l %s %T@\n' | sort } test_fresh_install() { local fixture home_dir package_dir output fixture="$(new_fixture)" home_dir="$fixture/home" package_dir="$fixture/source with spaces/proxy-client" run_install "$fixture" >/dev/null assert_package_links "$package_dir" "$home_dir" [ -x "$home_dir/.local/bin/proxy-client" ] || fail "CLI не исполняемый" assert_not_exists "$home_dir/.config/proxy-client/config" assert_not_exists "$home_dir/.config/proxy-client/default.url" output="$( env -i HOME="$home_dir" PATH=/usr/bin:/bin TERM=dumb bash -ic ' command -v proxy-client && declare -F proxy_on ' 2>/dev/null )" [ "$output" = "$home_dir/.local/bin/proxy-client"$'\n'proxy_on ] \ || fail "новый Bash не нашёл proxy-client и proxy_on: $output" ok "свежая установка: три ссылки и рабочий блок в ~/.bashrc" } test_repeat_changes_nothing() { local fixture home_dir before fixture="$(new_fixture)" home_dir="$fixture/home" run_install "$fixture" >/dev/null before="$(home_snapshot "$home_dir")" run_install "$fixture" >/dev/null [ "$(home_snapshot "$home_dir")" = "$before" ] \ || fail "повторный запуск изменил HOME" ok "повторный запуск ничего не меняет" } test_conflicts_block_whole_install() { local fixture home_dir output fixture="$(new_fixture)" home_dir="$fixture/home" mkdir -p "$home_dir/.local/bin" "$home_dir/.config/proxy-client" printf 'KEEP_CLI\n' > "$home_dir/.local/bin/proxy-client" ln -s "$fixture/missing" "$home_dir/.config/proxy-client/examples" if output="$(run_install "$fixture" 2>&1)"; then fail "установка прошла поверх чужих файлов" fi printf '%s' "$output" | grep -Fq "$home_dir/.local/bin/proxy-client" \ || fail "не назван конфликт CLI" printf '%s' "$output" | grep -Fq "$home_dir/.config/proxy-client/examples" \ || fail "не названа битая ссылка" grep -Fqx KEEP_CLI "$home_dir/.local/bin/proxy-client" \ || fail "чужой CLI изменён" [ "$(readlink "$home_dir/.config/proxy-client/examples")" = "$fixture/missing" ] \ || fail "битая ссылка изменена" assert_not_exists "$home_dir/.config/proxy-client/shell.bash" assert_not_exists "$home_dir/.bashrc" ok "все конфликты названы сразу, частичной установки нет" } test_keeps_machine_files() { local fixture home_dir fixture="$(new_fixture)" home_dir="$fixture/home" mkdir -p "$home_dir/.config/proxy-client" printf 'HOME_CONFIG\n' > "$home_dir/.config/proxy-client/config" printf 'HOME_PROFILE\n' > "$home_dir/.config/proxy-client/default.url" run_install "$fixture" --no-shell-setup >/dev/null [ ! -L "$home_dir/.config/proxy-client/config" ] || fail "config стал ссылкой" [ ! -L "$home_dir/.config/proxy-client/default.url" ] \ || fail "default.url стал ссылкой" grep -Fqx HOME_CONFIG "$home_dir/.config/proxy-client/config" \ || fail "машинный config изменён" grep -Fqx HOME_PROFILE "$home_dir/.config/proxy-client/default.url" \ || fail "default.url изменён" ok "машинные config и default.url не трогаются" } test_no_shell_setup() { local fixture home_dir output fixture="$(new_fixture)" home_dir="$fixture/home" output="$(run_install "$fixture" --no-shell-setup)" assert_not_exists "$home_dir/.bashrc" printf '%s' "$output" | grep -Fq 'proxy-client/shell.bash' \ || fail "нет подсказки для текущей сессии" ok "--no-shell-setup не трогает ~/.bashrc" } test_linked_parent_directories() { local fixture home_dir package_dir fixture="$(new_fixture)" home_dir="$fixture/home" package_dir="$fixture/source with spaces/proxy-client" mkdir -p "$fixture/external-local" "$fixture/external-config" ln -s "$fixture/external-local" "$home_dir/.local" ln -s "$fixture/external-config" "$home_dir/.config" run_install "$fixture" --no-shell-setup >/dev/null assert_package_links "$package_dir" "$home_dir" [ -L "$fixture/external-local/bin/proxy-client" ] \ || fail "ссылка не попала в каталог, на который указывает ~/.local" ok "каталоги ~/.local и ~/.config могут быть ссылками" } test_fresh_install test_repeat_changes_nothing test_conflicts_block_whole_install test_keeps_machine_files test_no_shell_setup test_linked_parent_directories echo "PASS: тесты установщика proxy-client"