- Зачем: - приложение должно явно работать через прокси и сохранять настройку после обновлений. - Что: - добавлены отдельный ярлык ChatGPT Proxy и запускатель на основе proxy-client. - исключено смешение прямого и проксированного режимов существующего процесса. - установка, документация и автоматические проверки дополнены новым Stow-пакетом. - Проверка: - bash tests/test_chatgpt_proxy_launcher.sh. - bash tests/test_proxy_launchers.sh. - bash tests/test_install.sh.
194 lines
7.8 KiB
Bash
Executable File
194 lines
7.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
LAUNCHER="$REPO_ROOT/chatgpt/.local/bin/start-chatgpt-proxy"
|
|
DESKTOP_FILE="$REPO_ROOT/chatgpt/.local/share/applications/chatgpt-proxy.desktop"
|
|
SHELL_MODULE="$REPO_ROOT/proxy-client/.config/proxy-client/shell.bash"
|
|
TEST_ROOT="$(mktemp -d /tmp/chatgpt-proxy-launcher-test.XXXXXX)"
|
|
trap 'rm -rf "$TEST_ROOT"' EXIT
|
|
|
|
pass_count=0
|
|
|
|
fail() {
|
|
echo "FAIL: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
ok() {
|
|
pass_count=$((pass_count + 1))
|
|
echo "ok - $*"
|
|
}
|
|
|
|
assert_contains() {
|
|
local file="$1" expected="$2" message="$3"
|
|
grep -Fq -- "$expected" "$file" || fail "$message"
|
|
}
|
|
|
|
assert_not_exists() {
|
|
local path="$1" message="$2"
|
|
[ ! -e "$path" ] || fail "$message"
|
|
}
|
|
|
|
setup_fixture() {
|
|
local fixture="$1"
|
|
mkdir -p "$fixture/bin" "$fixture/home" "$fixture/proc" "$fixture/results"
|
|
|
|
cat > "$fixture/bin/pgrep" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
if [ "${FAKE_PGREP_STATUS:-1}" = 0 ]; then
|
|
printf '%s\n' "${FAKE_PGREP_PIDS:-4242}"
|
|
fi
|
|
exit "${FAKE_PGREP_STATUS:-1}"
|
|
EOF
|
|
|
|
cat > "$fixture/bin/notify-send" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf '<%s>\n' "$@" >> "$RESULTS_DIR/notifications"
|
|
EOF
|
|
|
|
cat > "$fixture/bin/proxy-client" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf 'called\n' >> "$RESULTS_DIR/proxy-calls"
|
|
if [ "${FAKE_PROXY_FAIL:-0}" = 1 ]; then
|
|
echo 'тестовый прокси недоступен' >&2
|
|
exit 1
|
|
fi
|
|
[ "${1:-}" = env ] || exit 99
|
|
cat <<'ENV'
|
|
HTTP_PROXY=http://proxy.test:1234
|
|
HTTPS_PROXY=http://proxy.test:1234
|
|
ALL_PROXY=socks5://proxy.test:1234
|
|
NO_PROXY=proxy.test,localhost,127.0.0.1,::1,[::1],.example.test
|
|
http_proxy=http://proxy.test:1234
|
|
https_proxy=http://proxy.test:1234
|
|
all_proxy=socks5://proxy.test:1234
|
|
no_proxy=proxy.test,localhost,127.0.0.1,::1,[::1],.example.test
|
|
ENV
|
|
EOF
|
|
|
|
cat > "$fixture/bin/chatgpt" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf '<%s>\n' "$@" > "$RESULTS_DIR/chatgpt-args"
|
|
printf 'HTTP_PROXY=%s\nALL_PROXY=%s\nNO_PROXY=%s\n' \
|
|
"$HTTP_PROXY" "$ALL_PROXY" "$NO_PROXY" > "$RESULTS_DIR/chatgpt-env"
|
|
EOF
|
|
|
|
chmod +x "$fixture/bin/pgrep" "$fixture/bin/notify-send" \
|
|
"$fixture/bin/proxy-client" "$fixture/bin/chatgpt"
|
|
}
|
|
|
|
write_process() {
|
|
local fixture="$1" pid="$2"
|
|
shift 2
|
|
mkdir -p "$fixture/proc/$pid"
|
|
printf '%s\0' "$@" > "$fixture/proc/$pid/cmdline"
|
|
}
|
|
|
|
run_launcher() {
|
|
local fixture="$1"
|
|
shift
|
|
HOME="$fixture/home" \
|
|
PATH="$fixture/bin:/usr/bin:/bin" \
|
|
RESULTS_DIR="$fixture/results" \
|
|
PROXY_CLIENT_BIN="$fixture/bin/proxy-client" \
|
|
PROXY_CLIENT_SHELL="$SHELL_MODULE" \
|
|
CHATGPT_BIN="$fixture/bin/chatgpt" \
|
|
PROC_ROOT="$fixture/proc" \
|
|
"$LAUNCHER" "$@"
|
|
}
|
|
|
|
# Успешный запуск передаёт и окружение, и явные параметры Chromium.
|
|
fixture="$TEST_ROOT/success"
|
|
setup_fixture "$fixture"
|
|
FAKE_PGREP_STATUS=1 run_launcher "$fixture" 'chatgpt://example/path'
|
|
assert_contains "$fixture/results/chatgpt-args" \
|
|
'<--proxy-server=http://proxy.test:1234>' \
|
|
'не передан сервер Chromium'
|
|
assert_contains "$fixture/results/chatgpt-args" \
|
|
'<--proxy-bypass-list=proxy.test;localhost;127.0.0.1;::1;[::1];*.example.test>' \
|
|
'неверно преобразован список обхода Chromium'
|
|
assert_contains "$fixture/results/chatgpt-args" '<chatgpt://example/path>' \
|
|
'пользовательский аргумент потерян'
|
|
assert_contains "$fixture/results/chatgpt-env" \
|
|
'ALL_PROXY=socks5://proxy.test:1234' \
|
|
'proxy-окружение не унаследовано'
|
|
assert_not_exists "$fixture/results/notifications" \
|
|
'успешный запуск показал ошибку'
|
|
ok 'успешный запуск применяет proxy-client к Chromium и окружению'
|
|
|
|
# Уже работающий через тот же прокси экземпляр получает повторный запрос:
|
|
# Electron поднимает его существующее окно вместо ошибки «уже запущен».
|
|
fixture="$TEST_ROOT/running-proxied"
|
|
setup_fixture "$fixture"
|
|
write_process "$fixture" 4242 \
|
|
'/usr/lib/chatgpt/ChatGPT --proxy-server=http://proxy.test:1234 --proxy-bypass-list=proxy.test;localhost;127.0.0.1;::1;[::1];*.example.test'
|
|
FAKE_PGREP_STATUS=0 run_launcher "$fixture" 'chatgpt://existing'
|
|
assert_contains "$fixture/results/chatgpt-args" '<chatgpt://existing>' \
|
|
'повторный запрос не передан прокси-экземпляру'
|
|
assert_not_exists "$fixture/results/notifications" \
|
|
'работающий прокси-экземпляр ошибочно объявлен конфликтом'
|
|
ok 'повторный прокси-запуск открывает существующий экземпляр'
|
|
|
|
# Прямой экземпляр блокируется с точной инструкцией: встроенный Restart
|
|
# сохранит прямой режим, поэтому приложение нужно завершить через системный лоток.
|
|
fixture="$TEST_ROOT/running-direct"
|
|
setup_fixture "$fixture"
|
|
write_process "$fixture" 4242 /usr/lib/chatgpt/ChatGPT
|
|
set +e
|
|
FAKE_PGREP_STATUS=0 run_launcher "$fixture" >/dev/null 2>&1
|
|
status=$?
|
|
set -e
|
|
[ "$status" -eq 1 ] || fail "ожидался код 1 при прямом ChatGPT, получен $status"
|
|
assert_not_exists "$fixture/results/chatgpt-args" \
|
|
'прямой ChatGPT получил повторный запуск'
|
|
assert_contains "$fixture/results/notifications" 'без прокси' \
|
|
'уведомление не различает прямой экземпляр'
|
|
assert_contains "$fixture/results/notifications" 'системном лотке' \
|
|
'нет инструкции для полного завершения прямого экземпляра'
|
|
ok 'прямой экземпляр блокируется с точной инструкцией'
|
|
|
|
# Недоступный прокси не приводит к прямому запуску.
|
|
fixture="$TEST_ROOT/unavailable"
|
|
setup_fixture "$fixture"
|
|
set +e
|
|
FAKE_PGREP_STATUS=1 FAKE_PROXY_FAIL=1 run_launcher "$fixture" >/dev/null 2>&1
|
|
status=$?
|
|
set -e
|
|
[ "$status" -eq 1 ] || fail "ожидался код 1 при ошибке прокси, получен $status"
|
|
assert_not_exists "$fixture/results/chatgpt-args" \
|
|
'ChatGPT запущен напрямую после ошибки прокси'
|
|
assert_contains "$fixture/results/notifications" 'proxy-client status' \
|
|
'нет диагностической подсказки при ошибке прокси'
|
|
ok 'ошибка прокси запрещает прямой запуск'
|
|
|
|
# Ярлык остаётся отдельным и не перехватывает штатные обработчики ChatGPT.
|
|
assert_contains "$DESKTOP_FILE" 'Name=ChatGPT Proxy' \
|
|
'неверное имя ярлыка'
|
|
assert_contains "$DESKTOP_FILE" 'Exec=start-chatgpt-proxy %U' \
|
|
'ярлык не вызывает управляемый запускатель'
|
|
if grep -q '^MimeType=' "$DESKTOP_FILE"; then
|
|
fail 'прокси-ярлык не должен перехватывать штатные MIME-обработчики'
|
|
fi
|
|
[ "$(basename "$DESKTOP_FILE")" = chatgpt-proxy.desktop ] \
|
|
|| fail 'прокси-ярлык подменяет системный chatgpt.desktop'
|
|
ok 'ChatGPT Proxy остаётся отдельным пользовательским ярлыком'
|
|
|
|
if command -v desktop-file-validate >/dev/null 2>&1; then
|
|
desktop-file-validate "$DESKTOP_FILE" >/dev/null \
|
|
|| fail 'desktop-file-validate нашёл ошибку'
|
|
ok 'desktop-файл корректен'
|
|
else
|
|
echo 'skip - desktop-file-validate не установлен'
|
|
fi
|
|
|
|
if command -v shellcheck >/dev/null 2>&1; then
|
|
shellcheck -s bash "$LAUNCHER" "$0" \
|
|
|| fail 'shellcheck нашёл проблемы'
|
|
ok 'shellcheck чист'
|
|
else
|
|
echo 'skip - shellcheck не установлен'
|
|
fi
|
|
|
|
echo "PASS: $pass_count проверок пройдено"
|