Files
NeoTachyon/tests/package_postinst_running_job.sh
Dushnilin e7ed3839ed fix(package): не удалять состояние выполняющегося задания в postinst
Самообновление Tachyon — это компонентное задание, которое устанавливает
пакет, чей postinst и вызывает remove_component_update_cache(). Очистка
стирала каталог component-actions целиком, включая файл состояния того
самого задания, которое ещё выполнялось. LuCI опрашивал задание, не
находил его, не получал ни message, ни stderr и показывал фолбэк
"Failed to execute" поверх успешно прошедшего обновления.

Теперь очистка пропускает задания, помеченные running. Устаревшие
результаты и кэш проверок обновлений убираются как раньше. Зависшее
задание не залипнет: детект по PID и started_at помечает такие stale.

Пути каталогов состояния стали переопределяемыми через окружение, чтобы
тест мог прогнать luci-postinst, не трогая /var/run.
2026-08-10 05:47:42 +03:00

70 lines
3.1 KiB
Bash

#!/usr/bin/env bash
set -eo pipefail
# A Tachyon self-update is itself a component job: the job installs the package
# whose postinst runs remove_component_update_cache(). That cleanup used to wipe
# the whole component-actions directory, deleting the state file of the very job
# that was still running. LuCI then polled a job that no longer existed, got
# neither a message nor stderr, and rendered its "Failed to execute" fallback
# over an update that had actually succeeded.
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
PACKAGE_UC="$TACHYON_LIB/service/package.uc"
WORK_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
STATE_DIR="$WORK_DIR/run/tachyon"
ACTION_DIR="$STATE_DIR/component-actions"
CHECK_DIR="$STATE_DIR/component-update-checks"
mkdir -p "$ACTION_DIR" "$CHECK_DIR"
RUNNING_JOB="$ACTION_DIR/1786306166-287510904.json"
FINISHED_JOB="$ACTION_DIR/1786306100-111111111.json"
STALE_CHECK="$CHECK_DIR/tachyon.json"
TIMESTAMP="$STATE_DIR/component-update-check.timestamp"
printf '%s\n' '{ "success": true, "running": true, "kind": "component", "component": "tachyon", "action": "install", "message": "Component action is running", "started_at": 1786306166 }' >"$RUNNING_JOB"
printf '%s\n' '{ "success": true, "running": false, "kind": "component", "component": "sing_box", "action": "check_update", "message": "Latest version is installed" }' >"$FINISHED_JOB"
printf '%s\n' '{ "component": "tachyon", "status": "latest" }' >"$STALE_CHECK"
printf '%s\n' '1786306166' >"$TIMESTAMP"
TACHYON_PACKAGE_TEST_MODE=1 \
TACHYON_RUNTIME_STATE_DIR="$STATE_DIR" \
TACHYON_UI_COMPONENT_ACTION_DIR="$ACTION_DIR" \
TACHYON_COMPONENT_UPDATE_CHECK_CACHE_DIR="$CHECK_DIR" \
TACHYON_COMPONENT_UPDATE_CHECK_STATE_FILE="$TIMESTAMP" \
TACHYON_COMPONENT_ACTION_LOCK="$STATE_DIR/component-action.lock" \
TACHYON_CONFIG_NAME=tachyon-package-job-test \
ucode -L "$TACHYON_LIB" "$PACKAGE_UC" luci-postinst >/dev/null 2>&1 ||
fail "luci-postinst must succeed in test mode"
# The whole point: the in-flight job survives so its worker can write the result.
[ -f "$RUNNING_JOB" ] ||
fail "postinst deleted the state file of a running component job; the UI then reports 'Failed to execute' over a successful update"
# Finished results are genuinely stale and must still be cleared.
[ ! -f "$FINISHED_JOB" ] ||
fail "postinst must still remove finished component job results"
[ ! -f "$STALE_CHECK" ] ||
fail "postinst must still clear the component update check cache"
[ ! -f "$TIMESTAMP" ] ||
fail "postinst must still clear the component update check timestamp"
# Structural: no unconditional wipe of the job directory may come back.
sweep="$(sed -n '/^function remove_component_update_cache/,/^}/p' "$PACKAGE_UC" | sed 's://.*::')"
[ -n "$sweep" ] || fail "service/package.uc must define remove_component_update_cache"
grep -Fq 'component_job_is_running' <<<"$sweep" ||
fail "remove_component_update_cache must skip jobs that are still running"
printf 'package postinst running-job checks passed\n'