testsAndMisc/linux_configuration/scripts/lib/tests/test_mtk_partitions.sh
Krzysztof kuhy Rudnicki d42d8ff20d
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Shrink the shell-coverage allowlist 115 -> 106: cover scripts/lib
Gives linux_configuration/scripts/lib a real test suite, which takes all
nine of its libraries off meta/shell-coverage-allowlist.txt at once —
coverage is per-directory, so this is the highest-ratio first batch.

139 assertions across four suites, all offline: the mtk toolkit is driven
through its existing MTK_ROOT_FIXTURE seam, and adb is shimmed onto a
narrowed PATH. Nothing reads the wall clock, this host's udev rules, or a
real device, because the suite runs in shell-tests.yml and again on every
pre-push via ci-mirror — a host-dependent assertion would be a flake that
blocks unrelated pushes.

The gate only checks that tests/run_all.sh EXISTS, so an empty one would
mark all nine libraries covered while testing nothing. Each of the four
load-bearing rules was therefore mutation-tested and the suite required to
go red: classify_device's && -> ||, discover_partitions' init_boot/boot
ordering, mtk_select_device's refusal to guess between two phones, and
is_hour_in_range's 10#$ octal guard.

That last one initially SURVIVED. Dropping 10#$ makes bash abort with
"value too great for base", a non-zero exit indistinguishable from an
honest out-of-range result, so the status-only assertion passed either
way. It now asserts stderr is empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 23:52:09 +02:00

143 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Covers discover_partitions, mtk_ramdisk_carrier,
# mtk_check_layout_expectation, mtk_sane_ramdisk_size and mtk_check_venv.
#
# The load-bearing case is INIT_BOOT WINS OVER BOOT. A device launched on
# Android 13+ carries the ramdisk in init_boot even though boot also exists,
# so a loop that checked boot first would pick the wrong partition on exactly
# the hardware this toolkit targets — and would do it silently, because both
# names are present and both reads succeed.
#
# The second is that discover_partitions consults the FILESYSTEM, never the
# API level. mtk_check_layout_expectation may disagree and warn, but it must
# not change the answer.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=mtk_harness.sh
source "$HERE/mtk_harness.sh"
_t_sandbox
# shellcheck source=../mtk_common.sh
source "$HERE/../mtk_common.sh"
# --- discover_partitions ---------------------------------------------------
# A/B device with init_boot: the ramdisk lives in init_boot, not boot.
MTK_ROOT_FIXTURE="$(_t_fixture ab_initboot 'ro.boot.slot_suffix=_a' \
'boot_a
boot_b
init_boot_a
init_boot_b
vbmeta_a
vbmeta_b
userdata')"
export MTK_ROOT_FIXTURE
_t_rc 0 "discover_partitions succeeds when a ramdisk carrier exists" discover_partitions
discover_partitions
_t_is "A/B" "$MTK_AB_SCHEME" "an _a suffix in the listing means A/B"
_t_is "_a" "$MTK_SLOT_SUFFIX" "slot suffix comes from ro.boot.slot_suffix"
_t_is "init_boot_a" "$MTK_RAMDISK_PART" "init_boot wins over boot when both exist"
_t_is "vbmeta_a" "$MTK_VBMETA_PART" "vbmeta picks up the active slot suffix"
_t_is "init_boot" "$(mtk_ramdisk_carrier)" "carrier strips the slot suffix"
_t_is "0" "$MTK_SLOT_ASSUMED" "a reported slot suffix is not an assumption"
# A-only device with no init_boot: must fall through to boot.
MTK_ROOT_FIXTURE="$(_t_fixture aonly_boot '' \
'boot
recovery
vbmeta
userdata')"
discover_partitions
_t_is "A-only" "$MTK_AB_SCHEME" "no _a suffix means A-only"
_t_is "" "$MTK_SLOT_SUFFIX" "A-only has no slot suffix"
_t_is "boot" "$MTK_RAMDISK_PART" "falls through to boot when init_boot is absent"
_t_is "boot" "$(mtk_ramdisk_carrier)" "carrier of an unsuffixed boot is boot"
# A/B device whose slot_suffix is unreadable. The code falls back to _a
# because a dump has to start somewhere, but must FLAG that it guessed.
MTK_ROOT_FIXTURE="$(_t_fixture ab_no_suffix '' \
'boot_a
boot_b
vbmeta_a
vbmeta_b')"
discover_partitions
_t_is "_a" "$MTK_SLOT_SUFFIX" "A/B with no reported suffix falls back to _a"
_t_is "1" "$MTK_SLOT_ASSUMED" "the _a fallback is recorded as an assumption"
_t_is "boot_a" "$MTK_RAMDISK_PART" "assumed suffix still resolves a carrier"
# An empty listing is what an unauthorized or absent device produces. It must
# fail rather than reporting a plausible-looking empty layout.
MTK_ROOT_FIXTURE="$(_t_fixture no_partitions '' '')"
_t_rc 1 "discover_partitions fails on an empty by-name listing" discover_partitions
discover_partitions || true
_t_is "unknown" "$MTK_AB_SCHEME" "an empty listing yields an unknown scheme"
_t_is "" "$MTK_RAMDISK_PART" "an empty listing names no ramdisk partition"
# A listing with neither boot nor init_boot: non-empty, but no carrier.
MTK_ROOT_FIXTURE="$(_t_fixture no_carrier '' \
'system
vendor
userdata')"
_t_rc 1 "discover_partitions fails when no carrier is present" discover_partitions
# --- mtk_check_layout_expectation ------------------------------------------
# first_api_level >= 33 predicts init_boot. Agreement is quiet.
MTK_ROOT_FIXTURE="$(_t_fixture api34_initboot \
'ro.boot.slot_suffix=_a
ro.product.first_api_level=34' \
'boot_a
init_boot_a')"
discover_partitions
_t_rc 0 "api 34 + init_boot carrier agrees" mtk_check_layout_expectation
# Disagreement warns and returns 1 — but the device still wins.
MTK_ROOT_FIXTURE="$(_t_fixture api34_boot_only \
'ro.boot.slot_suffix=_a
ro.product.first_api_level=34' \
'boot_a
vbmeta_a')"
discover_partitions
_t_rc 1 "api 34 + boot carrier disagrees and says so" mtk_check_layout_expectation
_t_is "boot_a" "$MTK_RAMDISK_PART" "a disagreeing expectation does NOT change the answer"
warn_out="$(mtk_check_layout_expectation 2>&1 || true)"
_t_in "Trusting the device" "$warn_out" "the warning states the filesystem wins"
# Below 33 predicts boot.
MTK_ROOT_FIXTURE="$(_t_fixture api30_boot 'ro.product.first_api_level=30' 'boot')"
discover_partitions
_t_rc 0 "api 30 + boot carrier agrees" mtk_check_layout_expectation
# An unreadable or non-numeric api level is not an error — it is simply no
# cross-check. This must not be mistaken for a disagreement.
MTK_ROOT_FIXTURE="$(_t_fixture api_missing '' 'boot')"
discover_partitions
_t_rc 0 "an absent api level skips the cross-check" mtk_check_layout_expectation
# --- mtk_sane_ramdisk_size -------------------------------------------------
# Both an empty read and a whole-disk grab look like success to mtkclient's
# exit code, which is the entire reason this band exists.
_t_rc 1 "zero bytes is implausible" mtk_sane_ramdisk_size 0
_t_in "implausibly small" "$(mtk_sane_ramdisk_size 0 || true)" "small failure says which way"
_t_rc 1 "a truncated read is implausible" mtk_sane_ramdisk_size 1024
_t_rc 0 "8 MiB is a plausible ramdisk" mtk_sane_ramdisk_size $((8 * 1024 * 1024))
_t_rc 0 "the lower bound itself is accepted" mtk_sane_ramdisk_size $((1024 * 1024))
_t_rc 0 "the upper bound itself is accepted" mtk_sane_ramdisk_size $((128 * 1024 * 1024))
_t_rc 1 "a whole-disk grab is implausible" mtk_sane_ramdisk_size $((4 * 1024 * 1024 * 1024))
_t_in "implausibly large" "$(mtk_sane_ramdisk_size $((4 * 1024 * 1024 * 1024)) || true)" \
"large failure says which way"
# `stat` failing yields an empty string, not a number.
_t_rc 1 "a non-numeric size is rejected" mtk_sane_ramdisk_size "not-a-number"
_t_rc 1 "an empty size is rejected" mtk_sane_ramdisk_size ""
# --- mtk_check_venv --------------------------------------------------------
# MTK_ROOT_CACHE points at an empty tmpdir, so this takes the deterministic
# "missing" branch on any host, CI included.
_t_rc 1 "an absent venv is reported as missing" mtk_check_venv
_t_in "missing:" "$(mtk_check_venv || true)" "the missing branch names the interpreter path"
_t_done "test_mtk_partitions.sh"