93382d2de6
- machineid bind (/data/state/machine-id→/etc/machine-id) держит /data busy → снимаем bind перед umount; remount через systemctl start (не mount /data — нет fstab). - restart power/settings после install (повторный just run: иначе крутится старый бинарь, start=no-op) + restart power в начале power-safe-блока (чистый FSM Running). - §3 oneshot-чек: firstboot/machineid валидны в active|inactive (отработал ИЛИ корректно пропущен Condition'ом на повторном boot); реальный сбой = failed. - stage2.target тянет savetime.timer (WantedBy без enable не срабатывал). Блок power-safe зелёный: N=3 цикла /data цел, abort→ShutdownAborted, power-cut fsck-clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Alexander <akotenev2003@gmail.com>
306 lines
21 KiB
Bash
306 lines
21 KiB
Bash
#!/usr/bin/env bash
|
|
# Сквозной E2E Штурмана в Lima-VM (приёмка v0.1/v0.6 + шагающий скелет, спека §9.3/§9.4).
|
|
# Запуск: just e2e (двухфазно через reboot) или just run (однофазно, без reboot).
|
|
#
|
|
# Фазы (env E2E_PHASE):
|
|
# pre — сборка → install бинарей/юнитов → старт shturman.target → проверки §9.3 (1–8)
|
|
# → выставить персист-пробу (Settings.Set + запомнить machine-id); [по умолчанию]
|
|
# post — после reboot: персист настройки сохранился + machine-id стабилен (every-boot bind, §9.3.4).
|
|
#
|
|
# Системная шина устройства (§5.1). dev-mocks включён дефолт-фичей сборки (fake-ACC).
|
|
set -uo pipefail
|
|
|
|
REPO=/shturman
|
|
cd "$REPO" || { echo "нет $REPO"; exit 1; }
|
|
|
|
PHASE="${E2E_PHASE:-pre}"
|
|
IDLE_SECS="${E2E_IDLE_SECS:-20}" # окно простоя для eMMC-прокси (§7.5)
|
|
EMMC_MAX_SECTORS="${E2E_EMMC_MAX_SECTORS:-4096}" # порог T (🟡 калибруется; 4096 сект ≈ 2 МБ/окно)
|
|
FRAME=/run/shturman/frame.png
|
|
PROBE_KEY=ui.theme
|
|
PROBE_VAL=night
|
|
MID_BEFORE=/data/state/e2e-mid-before # снимок machine-id до reboot (персист в /data)
|
|
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$HOME/.cache/shturman/target}"
|
|
|
|
pass() { echo " ✓ $*"; }
|
|
fail() { echo "E2E FAIL: $*" >&2; exit 1; }
|
|
info() { echo; echo "== $* =="; }
|
|
|
|
# Имена на шине (зеркало crates/shturman-ipc/src/names.rs).
|
|
P_NAME=ru.shturman.Power; P_PATH=/ru/shturman/Power; P_IFACE=ru.shturman.Power1
|
|
P_MOCK=ru.shturman.dev.PowerMock1
|
|
S_NAME=ru.shturman.Settings; S_PATH=/ru/shturman/Settings; S_IFACE=ru.shturman.Settings1
|
|
|
|
settings_get() { busctl --system call "$S_NAME" "$S_PATH" "$S_IFACE" Get s "$1" 2>/dev/null; }
|
|
|
|
# =========================== POST-reboot фаза ===========================
|
|
if [ "$PHASE" = post ]; then
|
|
info "POST-reboot: персист настроек + machine-id стабилен (§9.3.4)"
|
|
# дождаться, пока сервисы поднимутся после автозагрузки target
|
|
for _ in $(seq 1 30); do systemctl is-active --quiet shturman-settings && break; sleep 1; done
|
|
|
|
findmnt /data >/dev/null || fail "/data не смонтирован после reboot"
|
|
pass "/data смонтирован после reboot"
|
|
|
|
# настройка пережила reboot
|
|
got=$(settings_get "$PROBE_KEY")
|
|
echo "$got" | grep -q "\"$PROBE_VAL\"" || fail "Settings.$PROBE_KEY != $PROBE_VAL после reboot (got: $got)"
|
|
pass "Settings.$PROBE_KEY = $PROBE_VAL пережил reboot"
|
|
|
|
# machine-id стабилен (every-boot bind из /data/state/machine-id)
|
|
sudo test -f "$MID_BEFORE" || fail "нет снимка $MID_BEFORE (фаза pre не отработала?)"
|
|
before=$(sudo cat "$MID_BEFORE"); now=$(cat /etc/machine-id)
|
|
[ -n "$now" ] || fail "/etc/machine-id пуст"
|
|
[ "$before" = "$now" ] || fail "machine-id изменился: было $before, стало $now"
|
|
src=$(sudo cat /data/state/machine-id)
|
|
[ "$now" = "$src" ] || fail "/etc/machine-id($now) != /data/state/machine-id($src) — bind не сработал"
|
|
pass "machine-id стабилен после reboot ($now), привязан из /data"
|
|
|
|
# journald volatile теперь естественно (drop-in присутствовал на boot)
|
|
test -d /run/log/journal && ! test -d /var/log/journal \
|
|
&& pass "journald volatile (/run/log/journal)" || echo " WARN: journald не строго volatile"
|
|
|
|
echo; echo "E2E POST OK ✅"
|
|
exit 0
|
|
fi
|
|
|
|
# ============================ PRE фаза ============================
|
|
info "сборка (release, VM-локальный target=$CARGO_TARGET_DIR)"
|
|
cargo build --release --workspace || fail "сборка"
|
|
for b in firstboot settings power shell splash; do
|
|
sudo install -m755 "$CARGO_TARGET_DIR/release/shturman-$b" /usr/local/bin/ || fail "install shturman-$b"
|
|
done
|
|
pass "бинари установлены в /usr/local/bin"
|
|
|
|
info "раскладка systemd-юнитов + dbus policy (из репо — подхватить правки)"
|
|
sudo install -m644 systemd/shturman.target systemd/data.mount \
|
|
systemd/shturman-stage0.target systemd/shturman-stage1.target systemd/shturman-stage2.target \
|
|
/etc/systemd/system/
|
|
sudo install -m644 systemd/shturman-firstboot.service systemd/shturman-machineid.service \
|
|
systemd/shturman-power.service systemd/shturman-settings.service \
|
|
systemd/shturman-shell.service systemd/shturman-splash.service \
|
|
systemd/shturman-stage2-warmup.service systemd/shturman-savetime.service \
|
|
/etc/systemd/system/
|
|
sudo install -d /etc/dbus-1/system.d
|
|
sudo install -m644 systemd/dbus/ru.shturman.conf /etc/dbus-1/system.d/
|
|
sudo install -d /etc/systemd/journald.conf.d /etc/systemd/oomd.conf.d
|
|
sudo install -m644 systemd/journald-shturman.conf /etc/systemd/journald.conf.d/shturman.conf
|
|
sudo install -m644 systemd/oomd-shturman.conf /etc/systemd/oomd.conf.d/shturman.conf
|
|
sudo install -m644 systemd/zram-generator.conf /etc/systemd/zram-generator.conf
|
|
sudo install -d /etc/tmpfiles.d
|
|
sudo install -m644 systemd/tmpfiles-shturman.conf /etc/tmpfiles.d/shturman.conf
|
|
sudo systemd-tmpfiles --create /etc/tmpfiles.d/shturman.conf || true
|
|
# watchdog (B05/A14) + save-time .timer (B07)
|
|
sudo install -d /etc/systemd/system.conf.d
|
|
sudo install -m644 systemd/watchdog-shturman.conf /etc/systemd/system.conf.d/shturman-watchdog.conf
|
|
sudo install -m644 systemd/shturman-savetime.timer /etc/systemd/system/
|
|
sudo systemctl daemon-reload
|
|
# применить конфиги детерминированно (на свежем boot drop-in’ы появились после старта демонов)
|
|
sudo systemctl reload dbus 2>/dev/null || true
|
|
sudo systemctl restart systemd-journald 2>/dev/null || true
|
|
sudo rm -rf /var/log/journal 2>/dev/null || true # устаревший persistent-журнал (до drop-in); volatile его не пересоздаст
|
|
sudo modprobe zram 2>/dev/null || true # zram-модуль (linux-modules-extra); может отсутствовать в vz-ядре
|
|
sudo systemctl start "systemd-zram-setup@zram0.service" 2>/dev/null || true
|
|
sudo systemctl restart systemd-oomd 2>/dev/null || sudo systemctl start systemd-oomd 2>/dev/null || true # подхватить oomd.conf.d
|
|
pass "юниты/политики разложены"
|
|
|
|
info "старт shturman.target (зонтик → Stage 0/1/2)"
|
|
sudo systemctl start shturman.target || fail "shturman.target не стартовал"
|
|
# Перезапустить демоны, чтобы подхватить свежесобранные бинари (на повторном just run — иначе крутится
|
|
# старый бинарь, start=no-op; на чистом vm-reset сервисы и так стартуют с новым). shell НЕ трогаем:
|
|
# иначе frame.png стал бы новее stage2.ready и сломал бы ассерт «warmup после кадра» (порядок фаз).
|
|
sudo systemctl restart shturman-power.service shturman-settings.service
|
|
for _ in $(seq 1 15); do systemctl is-active --quiet shturman-shell && break; sleep 1; done
|
|
|
|
# ---- 1. /data до сервисов + реальные power-safe опции (§9.3.1) ----
|
|
info "1. /data смонтирован, реальные non-default опции + volatile-слой"
|
|
findmnt /data >/dev/null || fail "/data не смонтирован"
|
|
opts=$(findmnt -no OPTIONS /data)
|
|
echo "$opts" | grep -q errors=remount-ro || fail "нет errors=remount-ro (opts: $opts)"
|
|
pass "/data: $opts"
|
|
# volatile-слой (tmpfs) присутствует — кадр/журнал/транзиент пишутся сюда, не на flash (A11).
|
|
# Полный RO-rootfs + overlay(upper на tmpfs) — на HW/v4 (A/B boot-select нет в VM, §7.1); тут — дисциплина + tmpfs.
|
|
findmnt -t tmpfs /run >/dev/null || fail "/run не tmpfs (нет volatile-слоя)"
|
|
pass "volatile-слой: /run = tmpfs"
|
|
|
|
# ---- 2. first-boot маркер + идемпотентность (§9.3.2) ----
|
|
info "2. first-boot маркер + machine-id"
|
|
sudo test -f /data/.shturman-provisioned || fail "нет маркера .shturman-provisioned"
|
|
sudo test -f /data/state/machine-id || fail "нет /data/state/machine-id"
|
|
sudo systemctl start shturman-firstboot.service # повторно — Condition гейтит → no-op
|
|
pass "first-boot маркер на месте, повторный запуск no-op"
|
|
|
|
# ---- 3. per-unit critical set active (degraded не маскирует, §9.3.1) ----
|
|
info "3. per-unit critical set"
|
|
for u in shturman-power shturman-settings shturman-shell; do
|
|
systemctl is-active --quiet "$u" || fail "$u не active ($(systemctl is-active "$u" 2>&1))"
|
|
pass "$u: active"
|
|
done
|
|
for u in shturman-firstboot shturman-machineid; do
|
|
state=$(systemctl is-active "$u" 2>&1)
|
|
# oneshot валиден в active (отработал, RemainAfterExit) ИЛИ inactive (корректно пропущен Condition'ом
|
|
# на повторном boot: firstboot — marker есть; reflects clean+re-run). Реальный сбой = failed/activating.
|
|
case "$state" in
|
|
active | inactive) pass "$u: $state (oneshot)" ;;
|
|
*) fail "$u не active/inactive (сбой): $state" ;;
|
|
esac
|
|
done
|
|
|
|
# ---- 4. имена на системной шине (own) + сервис отвечает (§9.3.3) ----
|
|
info "4. имена на шине + отклик"
|
|
busctl --system list | grep -q "$P_NAME" || fail "нет $P_NAME на шине"
|
|
busctl --system list | grep -q "$S_NAME" || fail "нет $S_NAME на шине"
|
|
busctl --system call "$P_NAME" "$P_PATH" "$P_IFACE" GetPowerState | grep -q running \
|
|
|| fail "Power.GetPowerState != running"
|
|
pass "$P_NAME / $S_NAME владеют именами; GetPowerState=running"
|
|
|
|
# ---- 5. fake-ACC: SetAcc -> AccChanged (§9.3.5) ----
|
|
info "5. fake-ACC SetAcc -> AccChanged"
|
|
mon=$(mktemp)
|
|
# sudo нужен busctl для eavesdrop системной шины; редирект в $mon — намеренно user-owned mktemp (SC2024 ок).
|
|
# shellcheck disable=SC2024
|
|
sudo busctl --system monitor "$P_NAME" >"$mon" 2>&1 &
|
|
MON=$!
|
|
sleep 1
|
|
busctl --system call "$P_NAME" "$P_PATH" "$P_MOCK" SetAcc b false || { sudo kill "$MON" 2>/dev/null; fail "вызов SetAcc"; }
|
|
sleep 1
|
|
sudo kill "$MON" 2>/dev/null; wait "$MON" 2>/dev/null
|
|
grep -q AccChanged "$mon" || { echo "--- monitor ---"; cat "$mon"; fail "AccChanged не наблюдаем"; }
|
|
rm -f "$mon"
|
|
busctl --system call "$P_NAME" "$P_PATH" "$P_MOCK" SetAcc b true >/dev/null 2>&1 || true # вернуть acc=on
|
|
pass "AccChanged наблюдаем после SetAcc"
|
|
|
|
# ---- 7. первый Slint-кадр: PNG не пустой (§9.3.6) ----
|
|
info "7. первый Slint-кадр (software-render PNG)"
|
|
sudo test -f "$FRAME" || fail "нет кадра $FRAME (shell.service не отрендерил?)"
|
|
sz=$(sudo stat -c%s "$FRAME"); [ "$sz" -gt 10000 ] || fail "кадр подозрительно мал ($sz Б)"
|
|
sudo head -c8 "$FRAME" | od -An -tx1 | tr -d ' \n' | grep -qi "89504e47" || fail "$FRAME не PNG"
|
|
pass "кадр $FRAME: $sz Б, валидный PNG"
|
|
|
|
# ---- Stage 0/1/2 разделены (v0.2 boot-конвейер) ----
|
|
info "Stage 0/1/2: фазы разделены + splash до кадра + warmup после"
|
|
for t in shturman-stage0 shturman-stage1 shturman-stage2; do
|
|
systemctl is-active --quiet "$t.target" || fail "$t.target не достигнут ($(systemctl is-active "$t.target" 2>&1))"
|
|
pass "$t.target reached"
|
|
done
|
|
sudo test -f /run/shturman/splash.png || fail "нет splash.png (Stage 0)"
|
|
sudo head -c8 /run/shturman/splash.png | od -An -tx1 | tr -d ' \n' | grep -qi 89504e47 || fail "splash.png не PNG"
|
|
fr=$(sudo stat -c %Y "$FRAME"); sp=$(sudo stat -c %Y /run/shturman/splash.png)
|
|
[ "$sp" -le "$fr" ] || fail "splash.png ($sp) позже frame.png ($fr) — Stage 0 не раньше Stage 1"
|
|
sudo test -f /run/shturman/stage2.ready || fail "нет stage2.ready (Stage 2 warmup не отработал)"
|
|
w2=$(sudo stat -c %Y /run/shturman/stage2.ready)
|
|
[ "$w2" -ge "$fr" ] || fail "stage2.ready ($w2) раньше кадра ($fr) — Stage 2 не деферред"
|
|
pass "порядок фаз: splash($sp) ≤ frame($fr) ≤ stage2($w2)"
|
|
# boot-тайминг (функц., НЕ гейт; вердикт — RK3588, performance §2)
|
|
echo " $(systemd-analyze time 2>/dev/null | head -1 || echo 'systemd-analyze н/д')"
|
|
|
|
# ---- power-safe (v0.3): FSM ShutdownImminent + N циклов зажигания + abort + power-cut ----
|
|
info "power-safe: ShutdownImminent + N=3 цикла зажигания + abort + power-cut"
|
|
# Чистый FSM Running для циклов (свежий бинарь + сброс любого «залипшего» состояния от §5 fake-ACC).
|
|
sudo systemctl restart shturman-power.service
|
|
for _ in $(seq 1 10); do systemctl is-active --quiet shturman-power && break; sleep 1; done
|
|
sleep 1 # дать power re-acquire ru.shturman.Power на шине
|
|
P_CALL() { busctl --system call "$P_NAME" "$P_PATH" "$P_MOCK" "$@"; }
|
|
busctl --system call "$S_NAME" "$S_PATH" "$S_IFACE" Set sv ui.theme s night >/dev/null
|
|
echo 0 | sudo tee /data/state/power-cycles >/dev/null
|
|
|
|
observe_imminent() { # SetAcc(false) → ждём ShutdownImminent на шине
|
|
local mon; mon=$(mktemp)
|
|
# shellcheck disable=SC2024
|
|
sudo busctl --system monitor "$P_NAME" >"$mon" 2>&1 & local M=$!
|
|
sleep 0.7; P_CALL SetAcc b false >/dev/null; sleep 0.7
|
|
sudo kill "$M" 2>/dev/null; wait "$M" 2>/dev/null
|
|
grep -q ShutdownImminent "$mon" || { echo "--- mon ---"; cat "$mon"; rm -f "$mon"; return 1; }
|
|
rm -f "$mon"
|
|
}
|
|
|
|
for i in 1 2 3; do
|
|
observe_imminent || fail "цикл $i: ShutdownImminent не наблюдаем"
|
|
n=$(($(sudo cat /data/state/power-cycles) + 1))
|
|
sudo systemctl stop shturman-stage1.target # стоп сервисов (освобождает /data)
|
|
sudo umount /etc/machine-id 2>/dev/null || true # снять machineid-bind, иначе /data busy
|
|
sync; sudo umount /data || fail "цикл $i: umount /data (PONR)"
|
|
findmnt /data >/dev/null && fail "цикл $i: /data не размонтирован (PONR не достигнут)"
|
|
sudo systemctl start shturman.target # re-mount data.mount + сервисы (machineid re-bind)
|
|
for _ in $(seq 1 15); do systemctl is-active --quiet shturman-settings && break; sleep 1; done
|
|
findmnt /data >/dev/null || fail "цикл $i: /data не вернулся после remount"
|
|
echo "$n" | sudo tee /data/state/power-cycles >/dev/null
|
|
pass "цикл зажигания $i: stop→umount(PONR)→remount→restart, /data вернулся"
|
|
done
|
|
got=$(busctl --system call "$S_NAME" "$S_PATH" "$S_IFACE" Get s ui.theme 2>/dev/null)
|
|
echo "$got" | grep -q '"night"' || fail "ui.theme потерян после циклов"
|
|
[ "$(sudo cat /data/state/power-cycles)" = 3 ] || fail "счётчик циклов != 3"
|
|
pass "N=3 цикла: /data + счётчик целы (нет потери)"
|
|
|
|
# abort до PONR
|
|
mon=$(mktemp)
|
|
# shellcheck disable=SC2024
|
|
sudo busctl --system monitor "$P_NAME" >"$mon" 2>&1 & M=$!
|
|
sleep 0.7; P_CALL SetAcc b false >/dev/null; sleep 0.3; P_CALL SetAcc b true >/dev/null; sleep 0.7
|
|
sudo kill "$M" 2>/dev/null; wait "$M" 2>/dev/null
|
|
grep -q ShutdownAborted "$mon" || { cat "$mon"; rm -f "$mon"; fail "ShutdownAborted не наблюдаем"; }
|
|
rm -f "$mon"
|
|
findmnt /data >/dev/null || fail "/data не смонтирован после abort"
|
|
busctl --system call "$P_NAME" "$P_PATH" "$P_IFACE" GetPowerState | grep -q running || fail "не running после abort"
|
|
pass "abort до PONR: ShutdownAborted + /data RW + running"
|
|
|
|
# power-cut-сим: SIGKILL во время shutdown → /data консистентен
|
|
P_CALL SetAcc b false >/dev/null; sleep 0.3
|
|
sudo systemctl kill -s KILL shturman-power.service shturman-settings.service 2>/dev/null || true
|
|
sudo systemctl stop shturman-stage1.target 2>/dev/null || true
|
|
sudo umount /etc/machine-id 2>/dev/null || true
|
|
sudo umount /data 2>/dev/null || sudo umount -l /data 2>/dev/null || true
|
|
findmnt /data >/dev/null && fail "power-cut: /data не размонтирован (fsck был бы на смонтированном)"
|
|
sudo fsck.ext4 -n /var/lib/shturman/data.img >/dev/null 2>&1 || fail "fsck /data не clean после power-cut"
|
|
sudo systemctl start shturman.target # re-mount + restart
|
|
for _ in $(seq 1 15); do systemctl is-active --quiet shturman-settings && break; sleep 1; done
|
|
sudo grep -q night /data/settings/settings.json || fail "last durable value потерян после power-cut"
|
|
pass "power-cut-сим: /data консистентен (fsck clean, night present)"
|
|
|
|
# watchdog/save-time конфиг
|
|
test -f /etc/systemd/system.conf.d/shturman-watchdog.conf || fail "нет watchdog-конфига"
|
|
systemctl is-active --quiet shturman-savetime.timer && pass "savetime.timer активен" || echo " WARN: savetime.timer не активен"
|
|
pass "watchdog-конфиг на месте"
|
|
|
|
# ---- 8. base-бюджеты: journald / zram / fake-hwclock / eMMC-прокси (§9.3.7) ----
|
|
info "8. base-бюджеты (функц.)"
|
|
# journald volatile: активный журнал в /run/log/journal, persistent /var/log/journal отсутствует (A10)
|
|
test -d /run/log/journal || fail "journald не volatile (нет /run/log/journal)"
|
|
test -d /var/log/journal && fail "journald пишет в persistent /var/log/journal (нарушение A10)"
|
|
pass "journald volatile (/run/log/journal, без /var/log/journal)"
|
|
# ровно одно zram-устройство (A09); модуль zram может отсутствовать в vz-ядре — честная VM↔HW-граница
|
|
zn=$(zramctl --noheadings 2>/dev/null | wc -l | tr -d ' ')
|
|
if [ "$zn" = 1 ]; then pass "zram: ровно одно устройство ($(zramctl --noheadings --output NAME 2>/dev/null))"
|
|
elif [ "$zn" = 0 ]; then echo " WARN: zram-устройств нет (модуль zram отсутствует в vz-ядре — HW-only, §13)"
|
|
else fail "zram: ожидалось одно устройство, найдено $zn"; fi
|
|
# fake-hwclock пишет в /data, не в /etc (A11). Override — FILE из /etc/default/fake-hwclock
|
|
# (сервис в Lima masked: Lima сам синхронит время — на HW юнит размаскирован, EnvironmentFile тот же).
|
|
sudo sh -c '. /etc/default/fake-hwclock 2>/dev/null; FILE="${FILE:-/data/state/fake-hwclock.data}" fake-hwclock save' || true
|
|
sudo test -f /data/state/fake-hwclock.data || fail "fake-hwclock не записал в /data/state/fake-hwclock.data"
|
|
sudo test -f /etc/fake-hwclock.data && fail "fake-hwclock пишет в /etc (нарушение A11)"
|
|
pass "fake-hwclock → /data/state/fake-hwclock.data (не в /etc)"
|
|
# systemd-oomd: запущен + наша политика загружена (A09). PSI/cgroup2 нужны — в vz есть; иначе honest WARN.
|
|
if [ "$(systemctl is-active systemd-oomd 2>/dev/null)" = active ] && test -f /etc/systemd/oomd.conf.d/shturman.conf; then
|
|
pass "systemd-oomd active, политика oomd.conf.d/shturman.conf загружена"
|
|
else echo " WARN: systemd-oomd не active (нет PSI/пакета — проверь провижининг)"; fi
|
|
# eMMC-прокси: дельта записанных секторов loop-/data за окно простоя
|
|
src=$(findmnt -no SOURCE /data); dev=$(basename "$src")
|
|
if [ ! -e "/sys/block/$dev" ]; then dev=$(losetup -j /var/lib/shturman/data.img -O NAME --noheadings 2>/dev/null | tr -d ' ' | xargs -r basename); fi
|
|
read_w() { awk -v d="$dev" '$3==d {print $10}' /proc/diskstats; }
|
|
s0=$(read_w); echo " окно простоя ${IDLE_SECS}s (loop-dev=$dev)…"; sleep "$IDLE_SECS"; s1=$(read_w)
|
|
delta=$(( ${s1:-0} - ${s0:-0} ))
|
|
echo " eMMC-прокси: записано $delta секторов за ${IDLE_SECS}s (порог $EMMC_MAX_SECTORS, ~калибровка)"
|
|
[ "$delta" -le "$EMMC_MAX_SECTORS" ] || fail "eMMC: дельта $delta > порога $EMMC_MAX_SECTORS секторов"
|
|
pass "eMMC-прокси в пороге"
|
|
|
|
# ---- персист-проба для POST-фазы ----
|
|
info "персист-проба (для проверки после reboot)"
|
|
busctl --system call "$S_NAME" "$S_PATH" "$S_IFACE" Set sv "$PROBE_KEY" s "$PROBE_VAL" || fail "Settings.Set"
|
|
got=$(settings_get "$PROBE_KEY"); echo "$got" | grep -q "\"$PROBE_VAL\"" || fail "Set не применился (got: $got)"
|
|
sudo cp /etc/machine-id "$MID_BEFORE" # снимок до reboot
|
|
pass "Settings.$PROBE_KEY=$PROBE_VAL выставлен; machine-id снят в $MID_BEFORE"
|
|
|
|
echo; echo "E2E PRE OK ✅ (для полной приёмки — reboot + фаза post: just e2e)"
|