Files
NeoTachyon/tests/component_auto_update.sh
T
Dushnilin 84cdf9d2f8 feat(updates): 1.3.10 - Автоматическое обновление компонентов (сразу при выходе и по расписанию)
- Backend: реализован запуск автоматического обновления компонентов в фоновом режиме (trigger_component_auto_update, component_auto_update_apply)
- Cron: поддержка окна обслуживания (schedule mode) с регистрацией задачи в crontab по заданному времени (HH:MM)
- UCI: новые опции component_auto_update_enabled, component_auto_update_mode, component_auto_update_time, component_auto_update_targets
- Web UI: элементы управления во вкладке настроек «Обновления» (чекбокс включения, переключатель режима, время и мультиселект разрешенных компонентов)
- Тесты: добавлен интеграционный тест component_auto_update.sh, обновлены cron-тесты updates_due.sh, все 118 тестов успешно пройдены в Docker
- Локализация: добавлены русские переводы для всех новых элементов интерфейса
2026-09-01 10:58:46 +03:00

160 lines
4.7 KiB
Bash

#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
UPDATES_UC="$TACHYON_LIB/components/updates.uc"
WORK_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
assert_eq() {
local expected="$1"
local actual="$2"
local label="$3"
[ "$actual" = "$expected" ] || fail "$label: expected '$expected', got '$actual'"
}
fake_lib="$WORK_DIR/lib"
cache_dir="$WORK_DIR/cache"
job_dir="$WORK_DIR/jobs"
timestamp_file="$WORK_DIR/component-update-check.timestamp"
mkdir -p \
"$fake_lib/core" \
"$fake_lib/config" \
"$fake_lib/components" \
"$fake_lib/service" \
"$fake_lib/providers/zapret" \
"$fake_lib/providers/zapret2" \
"$fake_lib/providers/byedpi" \
"$job_dir" \
"$cache_dir"
cat >"$fake_lib/core/uci.uc" <<'UCODE'
function get_all(_config, section) {
if (section == "settings") {
return {
component_update_check_enabled: getenv("TEST_COMPONENT_UPDATE_CHECK_ENABLED") || "1",
component_update_check_interval: getenv("TEST_COMPONENT_UPDATE_CHECK_INTERVAL") || "1d",
component_auto_update_enabled: getenv("TEST_COMPONENT_AUTO_UPDATE_ENABLED") || "0",
component_auto_update_mode: getenv("TEST_COMPONENT_AUTO_UPDATE_MODE") || "immediate",
component_auto_update_time: getenv("TEST_COMPONENT_AUTO_UPDATE_TIME") || "04:00",
component_auto_update_targets: getenv("TEST_COMPONENT_AUTO_UPDATE_TARGETS") ? split(getenv("TEST_COMPONENT_AUTO_UPDATE_TARGETS"), " ") : [ "all" ]
};
}
return {};
}
function section_objects(_config, _type) {
return [];
}
return {
get_all,
section_objects
};
UCODE
cat >"$fake_lib/config/connections.uc" <<'UCODE'
return {};
UCODE
cat >"$fake_lib/components/action.uc" <<'UCODE'
#!/usr/bin/env ucode
let component = ARGV[1] || "tachyon";
let action = ARGV[2] || "check_update";
if (action == "check_update") {
let result = {
success: true,
component,
action,
message: "Update is available",
current_version: "1.0.0",
latest_version: "1.1.0",
release_url: "https://example.com/release",
changed: 0,
status: "outdated"
};
print(sprintf("%J\n", result));
exit(0);
}
if (action == "update") {
let result = {
success: true,
component,
action,
message: "Updated successfully",
current_version: "1.1.0",
latest_version: "1.1.0",
changed: 1,
status: "latest"
};
print(sprintf("%J\n", result));
exit(0);
}
UCODE
cat >"$fake_lib/providers/zapret/runtime.uc" <<'UCODE'
#!/usr/bin/env ucode
exit(1);
UCODE
cp "$fake_lib/providers/zapret/runtime.uc" "$fake_lib/providers/zapret2/runtime.uc"
cp "$fake_lib/providers/zapret/runtime.uc" "$fake_lib/providers/byedpi/runtime.uc"
cat >"$fake_lib/service/state.uc" <<'UCODE'
#!/usr/bin/env ucode
exit(0);
UCODE
updates_ucode() {
TEST_COMPONENT_UPDATE_CHECK_ENABLED="${TEST_COMPONENT_UPDATE_CHECK_ENABLED:-1}" \
TEST_COMPONENT_UPDATE_CHECK_INTERVAL="${TEST_COMPONENT_UPDATE_CHECK_INTERVAL:-1d}" \
TEST_COMPONENT_AUTO_UPDATE_ENABLED="${TEST_COMPONENT_AUTO_UPDATE_ENABLED:-0}" \
TEST_COMPONENT_AUTO_UPDATE_MODE="${TEST_COMPONENT_AUTO_UPDATE_MODE:-immediate}" \
TEST_COMPONENT_AUTO_UPDATE_TIME="${TEST_COMPONENT_AUTO_UPDATE_TIME:-04:00}" \
TEST_COMPONENT_AUTO_UPDATE_TARGETS="${TEST_COMPONENT_AUTO_UPDATE_TARGETS:-all}" \
TACHYON_LIB="$fake_lib" \
TACHYON_BIN="/usr/bin/tachyon" \
TACHYON_SERVICE_INIT="/etc/init.d/tachyon" \
TACHYON_COMPONENT_UPDATE_CHECK_CACHE_DIR="$cache_dir" \
TACHYON_COMPONENT_UPDATE_CHECK_STATE_FILE="$timestamp_file" \
UPDATES_JOB_DIR="$job_dir" \
ucode -L "$fake_lib" -L "$TACHYON_LIB" "$UPDATES_UC" "$@"
}
# 1. Test immediate auto-update trigger on check if outdated
TEST_COMPONENT_AUTO_UPDATE_ENABLED=1 \
TEST_COMPONENT_AUTO_UPDATE_MODE=immediate \
updates_ucode component-updates-if-due
# Verify update check cache was populated
[ -f "$cache_dir/tachyon.json" ] || fail "component update check cache missing"
# Verify that auto-update spawned a background job in job_dir
sleep 1
job_files=( "$job_dir"/*.json )
[ -f "${job_files[0]}" ] || fail "auto-update should create background job state"
# 2. Test scheduled apply
rm -rf "$job_dir"/*
TEST_COMPONENT_AUTO_UPDATE_ENABLED=1 \
TEST_COMPONENT_AUTO_UPDATE_MODE=schedule \
TEST_COMPONENT_AUTO_UPDATE_TIME="04:00" \
updates_ucode component-auto-update-apply
sleep 1
job_files=( "$job_dir"/*.json )
[ -f "${job_files[0]}" ] || fail "scheduled auto-update should create background job state"
printf 'component auto update test passed\n'