From 0e9629e11035acf808cdc8ea068512702530e886 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 23 Aug 2026 11:05:56 +0200 Subject: [PATCH] Test thorium_repairs.sh to 100%, lift the gate timeout (89 -> 88) 75/75 lines through run_all.sh at --min 100, exit 0, and check_shell_coverage.sh passes with the allowlist line already deleted so the pass cannot come from the exemption. 55 assertions over 23 cases: all five profile repairs plus test_thorium, including every dry-run arm, the partial singleton-lock case, a corrupt database and the sqlite3-absent path. The lib needed NO production change -- it already takes every path from $THORIUM_CONFIG_DIR, so pointing that one variable at the tmpdir confines it completely. The gate's per-case timeout moves from the jail's 120s default to 600s. That default is a hang-catcher, not a performance budget, and this suite has outgrown it: 76s bare at 25 test files, 93s at 27, and kcov roughly doubles it. The symptom was a lib FAILING the gate while measuring perfectly -- bt_audio.sh printed "127/127 lines = 100.00%" and then "warn: case timed out after 120s", which --fail-on-case-error turned into a non-zero exit. bt_audio.sh and arch_cpu.sh both pass now. The cost, recorded in the evidence: a genuine hang takes 10 minutes per pass to surface instead of 2. test_thorium's `read -r -p` is exactly that shape, so every case here feeds it stdin explicitly. This also settles the quarantine in b2779059. Re-adding the arch_sysctl cases still yields "kcov instrumented no lines" for bt_audio at a 600s timeout with no timeout warning, so runtime was never that file's problem and the quarantine stands for the reason its header gives. Co-Authored-By: Claude Opus 5 (1M context) --- .../thorium-repairs-tests-2026-08-23.json | 18 +++ .../thorium-repairs-tests-2026-08-23.json | 57 ++++++++ .../fixes/lib/tests/test_thorium_repairs.sh | 132 ++++++++++++++++++ .../lib/tests/test_thorium_repairs_deep.sh | 125 +++++++++++++++++ .../fixes/lib/tests/thorium_harness.sh | 124 ++++++++++++++++ meta/scripts/lib/shell_coverage_bar.sh | 11 ++ meta/shell-coverage-allowlist.txt | 1 - 7 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 docs/superpowers/contracts/thorium-repairs-tests-2026-08-23.json create mode 100644 docs/superpowers/evidence/thorium-repairs-tests-2026-08-23.json create mode 100755 linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs.sh create mode 100755 linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs_deep.sh create mode 100755 linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh diff --git a/docs/superpowers/contracts/thorium-repairs-tests-2026-08-23.json b/docs/superpowers/contracts/thorium-repairs-tests-2026-08-23.json new file mode 100644 index 00000000..477f3f36 --- /dev/null +++ b/docs/superpowers/contracts/thorium-repairs-tests-2026-08-23.json @@ -0,0 +1,18 @@ +{ + "title": "Clear thorium_repairs.sh and lift the coverage gate's case timeout", + "objective": "Bring thorium_repairs.sh to 100% measured line coverage and remove its allowlist exemption, and stop the gate's 120s per-case timeout from failing libs whose coverage is actually 100%.", + "acceptance_criteria": [ + "The jail reports thorium_repairs.sh at 100.00% through tests/run_all.sh at --min 100, exiting 0.", + "check_shell_coverage.sh passes on thorium_repairs.sh with its allowlist line already deleted, so the pass cannot come from the exemption.", + "check_shell_coverage.sh passes on bt_audio.sh, which failed before this change despite measuring 127/127, because the case timed out.", + "All five profile-repair functions plus test_thorium are covered, including every dry-run arm and the sqlite3-absent path.", + "thorium_repairs.sh itself is unmodified: it already took every path from $THORIUM_CONFIG_DIR, so no production seam was needed.", + "The suite stays green and shellcheck reports nothing, with zero suppressions." + ], + "out_of_scope": [ + "Un-quarantining arch_sysctl_quarantined_cases.sh: re-adding it still breaks bt_audio's measurement even at a 600s timeout, so runtime was not its cause.", + "Changing the coverage instrument (shell_coverage_lines.py).", + "The remaining four untested libs: hosts_guard_migrate, hosts_guard_rollback, ubuntu_perf_fixes, nvidia_config." + ], + "verifier": "timeout 900s bash meta/scripts/shell_coverage_jail.sh --timeout 600s --subject linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh --measure thorium_repairs.sh --min 100 --fail-on-case-error -- \"\" (expects 75/75 = 100.00%, exit 0), then bash meta/scripts/check_shell_coverage.sh on thorium_repairs.sh and bt_audio.sh with the allowlist line removed." +} diff --git a/docs/superpowers/evidence/thorium-repairs-tests-2026-08-23.json b/docs/superpowers/evidence/thorium-repairs-tests-2026-08-23.json new file mode 100644 index 00000000..94a89bc3 --- /dev/null +++ b/docs/superpowers/evidence/thorium-repairs-tests-2026-08-23.json @@ -0,0 +1,57 @@ +{ + "intent": "Test thorium_repairs.sh to 100% line coverage, take it off the shell coverage allowlist, and raise the coverage gate's per-case timeout, which the growing suite had outgrown.", + "scope": [ + "linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh (new)", + "linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs.sh and test_thorium_repairs_deep.sh (new)", + "meta/scripts/lib/shell_coverage_bar.sh (--timeout added to the gate's jail invocation)", + "meta/shell-coverage-allowlist.txt (one line removed)", + "Non-goal: thorium_repairs.sh itself, which needed NO production change -- it already takes every path from $THORIUM_CONFIG_DIR" + ], + "changes": [ + "Added thorium_harness.sh, the fourth family harness, supplying THORIUM_CONFIG_DIR plus the backup_if_exists/remove_if_exists helpers that live in the entry script fix_thorium.sh rather than in any lib", + "Added 55 assertions over 23 cases across both files: all five profile repairs plus test_thorium, including the dry-run arm of every function that has one", + "Raised the gate's per-case timeout from the jail's 120s default to 600s in shell_coverage_bar.sh, because the suite is now 93s bare and kcov instrumentation roughly doubles that", + "Removed thorium_repairs.sh from meta/shell-coverage-allowlist.txt, taking it from 89 to 88 entries" + ], + "verification": [ + { + "command": "shell_coverage_jail.sh --subject .../tests/run_all.sh --measure thorium_repairs.sh --min 100 --fail-on-case-error", + "result": "pass", + "evidence": "thorium_repairs.sh: 75/75 lines = 100.00%, exit 0." + }, + { + "command": "bash meta/scripts/check_shell_coverage.sh .../thorium_repairs.sh, AFTER deleting its allowlist line", + "result": "pass", + "evidence": "'every checked shell library meets the coverage bar', EXIT 0. Checked after removal so the pass cannot be coming from the exemption." + }, + { + "command": "bash meta/scripts/check_shell_coverage.sh .../bt_audio.sh .../arch_cpu.sh", + "result": "pass", + "evidence": "EXIT 0. Before the timeout fix bt_audio.sh FAILED the gate while measuring a clean 127/127 -- the jail printed the number and then 'warn: case timed out after 120s', and --fail-on-case-error turned that into a non-zero exit." + }, + { + "command": "time bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh", + "result": "pass", + "evidence": "All fixes lib test files passed; 93s bare with the two new files (76s before them). That runtime against the 120s default is what the fix addresses." + }, + { + "command": "shellcheck + shfmt on the harness, both test files and shell_coverage_bar.sh", + "result": "pass", + "evidence": "No findings, zero suppressions." + }, + { + "command": "shell_coverage_jail.sh --timeout 600s --measure bt_audio.sh, with test_arch_sysctl.sh temporarily restored", + "result": "fail", + "evidence": "bt_audio.sh: 'kcov instrumented no lines', with NO timeout warning at 600s. This rules out runtime as the cause of that file's contagion and confirms the quarantine in b2779059 was correct for the reason its header states." + } + ], + "risks": [ + "A genuine hang now takes 10 minutes per pass to surface instead of 2. test_thorium's `read -r -p` is exactly that shape, which is why every case feeding it supplies stdin explicitly.", + "The gate's timeout is now the binding constraint on how large this suite can grow; at 93s bare it has roughly a 3x margin left.", + "test_thorium backgrounds a stub that sleeps 30s so the process is still alive when the lib's `kill -0` runs; a much slower machine could in principle race it." + ], + "rollback": [ + "git revert the commit, then re-add the thorium_repairs.sh line to meta/shell-coverage-allowlist.txt", + "Note the revert also restores the 120s gate timeout, which will make bt_audio.sh fail the gate again on this suite; re-run check_shell_coverage.sh on bt_audio.sh to confirm that is understood" + ] +} diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs.sh new file mode 100755 index 00000000..a6a38ccd --- /dev/null +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# lib/tests/test_thorium_repairs.sh — tests for thorium_repairs.sh's profile +# repairs: Local State, singleton locks, GPU cache and crash reports. +# +# fix_aggressive and test_thorium live in test_thorium_repairs_deep.sh, split +# out to hold every file under the 250-line cap. +# +# Calls go through _t_run rather than `out="$(...)"`: command substitution +# forks a subshell, and kcov does not register a lib whose first execution +# happens inside one. +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=thorium_harness.sh +. "${SCRIPT_DIR}/thorium_harness.sh" + +# shellcheck source=../thorium_repairs.sh +. "${FIXES_DIR}/lib/thorium_repairs.sh" + +printf '\n-- fix_local_state --\n' + +# Case 1: no Local State at all -- a fresh install. +thorium_reset +_t_run fix_local_state +_t_eq "0" "$?" "fix_local_state: returns 0 with no Local State" +_t_contains "$out" "No Local State file found" "fix_local_state: reports a fresh install" + +# Case 2: valid JSON is STILL backed up -- the lib treats a readable Local +# State as a crash source in its own right, not just a corrupt one. +thorium_reset +_t_profile "Local State" +_t_stub python3 'exit 0' +_t_run fix_local_state +_t_contains "$out" "backing up (common crash source)" \ + "fix_local_state: backs up even valid JSON" +_t_eq "no" "$(_t_exists "Local State")" "fix_local_state: moves the valid file aside" +_t_eq "yes" "$(_t_exists "Local State${BACKUP_SUFFIX}")" \ + "fix_local_state: the backup carries the suffix" + +# Case 3: corrupted JSON -- python3 exits non-zero. +thorium_reset +_t_profile "Local State" +_t_stub python3 'exit 1' +_t_run fix_local_state +_t_contains "$out" "appears corrupted" "fix_local_state: reports corruption" +_t_eq "yes" "$(_t_exists "Local State${BACKUP_SUFFIX}")" \ + "fix_local_state: backs up the corrupt file" + +# Case 4: dry-run leaves the file in place. +thorium_reset +_t_profile "Local State" +_t_stub python3 'exit 0' +DRY_RUN=true +_t_run fix_local_state +_t_eq "yes" "$(_t_exists "Local State")" "fix_local_state: dry-run keeps the file" +_t_contains "$out" "Would backup" "fix_local_state: dry-run says what it would do" + +printf '\n-- fix_singleton_locks --\n' + +# Case 5: no locks present. +thorium_reset +_t_run fix_singleton_locks +_t_contains "$out" "No stale lock files found" "fix_singleton_locks: reports none found" + +# Case 6: all three locks present -> all cleared. +thorium_reset +_t_profile SingletonLock SingletonSocket SingletonCookie +_t_run fix_singleton_locks +_t_eq "no" "$(_t_exists SingletonLock)" "fix_singleton_locks: clears SingletonLock" +_t_eq "no" "$(_t_exists SingletonSocket)" "fix_singleton_locks: clears SingletonSocket" +_t_eq "no" "$(_t_exists SingletonCookie)" "fix_singleton_locks: clears SingletonCookie" +_t_lacks "$out" "No stale lock files found" \ + "fix_singleton_locks: does not claim none were found" + +# Case 7: only one lock present -- the partial case, which the counter must +# still treat as "something was cleared". +thorium_reset +_t_profile SingletonLock +_t_run fix_singleton_locks +_t_eq "no" "$(_t_exists SingletonLock)" "fix_singleton_locks: clears the one lock" +_t_lacks "$out" "No stale lock files found" \ + "fix_singleton_locks: counts a single lock as cleared" + +printf '\n-- fix_gpu_cache --\n' + +# Case 8: nothing cached. +thorium_reset +_t_run fix_gpu_cache +_t_contains "$out" "No GPU cache to clear" "fix_gpu_cache: reports an empty cache" + +# Case 9: all four cache locations, including the Default/ ones. +thorium_reset +_t_profile GPUCache/f "Default/GPUCache/f" ShaderCache/f "Default/ShaderCache/f" +_t_run fix_gpu_cache +_t_eq "no" "$(_t_exists GPUCache)" "fix_gpu_cache: clears the top-level GPUCache" +_t_eq "no" "$(_t_exists Default/GPUCache)" "fix_gpu_cache: clears the profile GPUCache" +_t_eq "no" "$(_t_exists ShaderCache)" "fix_gpu_cache: clears the top-level ShaderCache" +_t_eq "no" "$(_t_exists Default/ShaderCache)" "fix_gpu_cache: clears the profile ShaderCache" +_t_lacks "$out" "No GPU cache to clear" "fix_gpu_cache: does not claim the cache was empty" + +printf '\n-- fix_crash_reports --\n' + +# Case 10: no crash directory. +thorium_reset +_t_run fix_crash_reports +_t_eq "0" "$?" "fix_crash_reports: returns 0 with no crash directory" + +# Case 11: crash directory present but EMPTY -> left alone, since the count +# gate is what decides, not the directory's existence. +thorium_reset +mkdir -p "${THORIUM_CONFIG_DIR}/Crash Reports" +_t_run fix_crash_reports +_t_eq "yes" "$(_t_exists "Crash Reports")" "fix_crash_reports: keeps an empty crash dir" + +# Case 12: crash reports present -> removed and counted. +thorium_reset +_t_profile "Crash Reports/a" "Crash Reports/b" +_t_run fix_crash_reports +_t_eq "no" "$(_t_exists "Crash Reports")" "fix_crash_reports: removes the crash dir" +_t_contains "$out" "Cleared 2 crash report(s)" "fix_crash_reports: counts the reports" + +# Case 13: dry-run reports the count without deleting. +thorium_reset +_t_profile "Crash Reports/a" +DRY_RUN=true +_t_run fix_crash_reports +_t_eq "yes" "$(_t_exists "Crash Reports")" "fix_crash_reports: dry-run keeps the dir" +_t_contains "$out" "Would clear 1 crash report(s)" "fix_crash_reports: dry-run states the count" + +printf '\nthorium_repairs (profile): %d passed, %d failed\n' "$PASS" "$FAIL" +[[ $FAIL -eq 0 ]] diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs_deep.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs_deep.sh new file mode 100755 index 00000000..ef5d04bf --- /dev/null +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/test_thorium_repairs_deep.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# lib/tests/test_thorium_repairs_deep.sh — tests for thorium_repairs.sh's +# fix_aggressive and test_thorium. +# +# Split from test_thorium_repairs.sh to hold every file under the 250-line +# cap. test_thorium is the awkward one: it backgrounds the browser, sleeps, +# and then BLOCKS on `read -r -p`. Every case here therefore feeds it stdin, +# because a stub that leaves the read waiting hangs the whole suite -- and +# under the coverage jail that presents as a case timeout, not as a hang. +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=thorium_harness.sh +. "${SCRIPT_DIR}/thorium_harness.sh" + +# shellcheck source=../thorium_repairs.sh +. "${FIXES_DIR}/lib/thorium_repairs.sh" + +printf '\n-- fix_aggressive --\n' + +# Case 1: not aggressive -> returns without touching anything. +thorium_reset +_t_profile "Default/Cache/f" +_t_run fix_aggressive +_t_eq "yes" "$(_t_exists Default/Cache)" "fix_aggressive: leaves the cache alone by default" +_t_lacks "$out" "aggressive fixes" "fix_aggressive: says nothing when not enabled" + +# Case 2: aggressive with every path present -> all six removed. +thorium_reset +AGGRESSIVE=true +_t_profile "Default/Service Worker/f" "Default/Cache/f" "Default/Code Cache/f" \ + "Default/IndexedDB/f" "BrowserMetrics/f" "component_crx_cache/f" +_t_run fix_aggressive +_t_contains "$out" "may lose some site data" "fix_aggressive: warns about data loss" +_t_eq "no" "$(_t_exists "Default/Service Worker")" "fix_aggressive: removes Service Worker" +_t_eq "no" "$(_t_exists Default/Cache)" "fix_aggressive: removes Cache" +_t_eq "no" "$(_t_exists "Default/Code Cache")" "fix_aggressive: removes Code Cache" +_t_eq "no" "$(_t_exists Default/IndexedDB)" "fix_aggressive: removes IndexedDB" +_t_eq "no" "$(_t_exists BrowserMetrics)" "fix_aggressive: removes BrowserMetrics" +_t_eq "no" "$(_t_exists component_crx_cache)" "fix_aggressive: removes the crx cache" + +# Case 3: aggressive with a HEALTHY database -> checked, left in place. +thorium_reset +AGGRESSIVE=true +_t_profile "Default/Web Data" "Default/History" +_t_stub sqlite3 'exit 0' +_t_run fix_aggressive +_t_contains "$out" "Checking database: Web Data" "fix_aggressive: checks Web Data" +_t_contains "$out" "Checking database: History" "fix_aggressive: checks History" +_t_eq "yes" "$(_t_exists "Default/Web Data")" "fix_aggressive: keeps a healthy database" +_t_lacks "$out" "may be corrupted" "fix_aggressive: does not cry corruption on a good db" + +# Case 4: aggressive with a CORRUPT database -> backed up. +thorium_reset +AGGRESSIVE=true +_t_profile "Default/Web Data" +_t_stub sqlite3 'exit 1' +_t_run fix_aggressive +_t_contains "$out" "may be corrupted: Web Data" "fix_aggressive: reports the corruption" +_t_eq "no" "$(_t_exists "Default/Web Data")" "fix_aggressive: moves the corrupt db aside" +_t_eq "yes" "$(_t_exists "Default/Web Data${BACKUP_SUFFIX}")" \ + "fix_aggressive: the corrupt db is backed up, not deleted" + +# Case 5: sqlite3 not installed -> the integrity check is skipped entirely, +# and the database is left untouched rather than assumed bad. +thorium_reset +AGGRESSIVE=true +_t_profile "Default/History" +_t_unstub sqlite3 +_t_hide sqlite3 +_t_run fix_aggressive +_t_eq "yes" "$(_t_exists Default/History)" "fix_aggressive: keeps the db without sqlite3" +_t_lacks "$out" "may be corrupted" "fix_aggressive: makes no corruption claim without sqlite3" +_t_full_path + +printf '\n-- test_thorium --\n' + +# Case 6: TEST_AFTER unset -> returns immediately, browser never launched. +thorium_reset +_t_run test_thorium +_t_lacks "$(_t_calls)" "thorium-browser" "test_thorium: does not launch when not asked" + +# Case 7: dry-run says what it would do and launches nothing. +thorium_reset +TEST_AFTER=true +DRY_RUN=true +_t_run test_thorium +_t_contains "$out" "Would test thorium-browser startup" "test_thorium: dry-run states intent" +_t_lacks "$(_t_calls)" "thorium-browser" "test_thorium: dry-run launches nothing" + +# Case 8: the browser stays up, and the prompt is answered "n" -> killed. +# The stub sleeps longer than the lib's own 4s wait so the process is still +# alive when `kill -0` runs. +thorium_reset +TEST_AFTER=true +_t_stub thorium-browser 'sleep 30' +test_thorium <<<"n" >"${TEST_TMPDIR}/tt_out" 2>&1 +out="$(cat "${TEST_TMPDIR}/tt_out")" +_t_contains "$out" "Thorium started successfully" "test_thorium: reports a successful start" +_t_contains "$out" "Browser closed" "test_thorium: closes the browser when answered n" + +# Case 9: answered with a bare newline -> the default keeps it running. +thorium_reset +TEST_AFTER=true +_t_stub thorium-browser 'sleep 30' +test_thorium <<<"" >"${TEST_TMPDIR}/tt_out" 2>&1 +out="$(cat "${TEST_TMPDIR}/tt_out")" +_t_contains "$out" "Browser left running" "test_thorium: default answer leaves it running" + +# Case 10: the browser dies immediately -> the failure advice, and exit 1. +# Run in a subshell: the lib calls `exit 1` on this path, which would +# otherwise end this test file early. +thorium_reset +TEST_AFTER=true +_t_stub thorium-browser 'exit 1' +rc=0 +(test_thorium "${TEST_TMPDIR}/tt_out" 2>&1) || rc=$? +out="$(cat "${TEST_TMPDIR}/tt_out")" +_t_eq "1" "$rc" "test_thorium: exits 1 when the browser will not stay up" +_t_contains "$out" "still crashing after fixes" "test_thorium: reports the crash" +_t_contains "$out" "yay -S thorium-browser-bin" "test_thorium: suggests a reinstall" + +printf '\nthorium_repairs (deep): %d passed, %d failed\n' "$PASS" "$FAIL" +[[ $FAIL -eq 0 ]] diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh new file mode 100755 index 00000000..615c872d --- /dev/null +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# lib/tests/thorium_harness.sh — shared setup for the Thorium repair lib +# tests (thorium_repairs.sh). +# +# Sourced, not executed. Builds on lib_test_core.sh and adds what the lib +# reads from its entry script, fix_thorium.sh: +# +# * THORIUM_CONFIG_DIR, pointed into the throwaway tmpdir, plus the +# DRY_RUN / AGGRESSIVE / TEST_AFTER flags and BACKUP_SUFFIX; +# * backup_if_exists and remove_if_exists, redefined verbatim from the +# entry script -- they live there rather than in any lib, the same +# arrangement arch_desktop_harness.sh handles with apply_tweak; +# * the colour variables the lib echoes; +# * the real log_*/has_cmd helpers, via scripts/lib/common.sh. +# +# The lib takes EVERY path it touches from $THORIUM_CONFIG_DIR, so pointing +# that one variable at the tmpdir is enough to confine it -- no production +# seam had to be added, unlike the arch desktop family. +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FIXES_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)" +REPO_ROOT="$(cd "${FIXES_DIR}/../../../.." && pwd)" + +# shellcheck source=lib_test_core.sh +. "${SCRIPT_DIR}/lib_test_core.sh" + +# shellcheck source=../../../../lib/common.sh +. "${REPO_ROOT}/linux_configuration/scripts/lib/common.sh" + +# --- globals and helpers owned by fix_thorium.sh ---------------------------- + +# Read by the lib under test, never by this harness, so static analysis +# cannot see the use; export makes the intent explicit. +export THORIUM_CONFIG_DIR="${TEST_TMPDIR}/thorium" +export BACKUP_SUFFIX=".bak.20260822_120000" +export DRY_RUN=false +export AGGRESSIVE=false +export TEST_AFTER=false + +# The lib echoes these directly; fix_thorium.sh defines them for a terminal. +# Empty here so assertions match on text rather than escape sequences. +export RED='' +export GREEN='' +export YELLOW='' +export NC='' + +# Verbatim from fix_thorium.sh. +backup_if_exists() { + local path="$1" + local name + name=$(basename "$path") + + if [[ -e $path ]]; then + local backup_path="${path}${BACKUP_SUFFIX}" + if [[ $DRY_RUN == true ]]; then + echo " [dry-run] Would backup: $name" + else + mv "$path" "$backup_path" + log_ok "Backed up: $name -> $(basename "$backup_path")" + fi + return 0 + fi + return 1 +} + +# Verbatim from fix_thorium.sh. +remove_if_exists() { + local path="$1" + local name + name=$(basename "$path") + + if [[ -e $path ]]; then + if [[ $DRY_RUN == true ]]; then + echo " [dry-run] Would remove: $name" + else + rm -rf "$path" + log_ok "Removed: $name" + fi + return 0 + fi + return 1 +} + +_thorium_default_stubs() { + local tool + for tool in python3 sqlite3 thorium-browser; do + _t_stub "$tool" 'exit 0' + done +} + +# thorium_reset — start a test group from "nothing has happened yet". +thorium_reset() { + _t_reset_calls + DRY_RUN=false + AGGRESSIVE=false + TEST_AFTER=false + export DRY_RUN AGGRESSIVE TEST_AFTER + rm -rf "${THORIUM_CONFIG_DIR}" + mkdir -p "${THORIUM_CONFIG_DIR}/Default" + _t_full_path + _thorium_default_stubs +} + +# _t_profile PATH... — create files inside the Thorium profile. +_t_profile() { + local rel + for rel in "$@"; do + mkdir -p "$(dirname "${THORIUM_CONFIG_DIR}/${rel}")" + printf 'x\n' >"${THORIUM_CONFIG_DIR}/${rel}" + done +} + +# _t_exists REL — "yes"/"no" for a path inside the profile, for assertions +# that read better than a bare test. +_t_exists() { + if [[ -e "${THORIUM_CONFIG_DIR}/$1" ]]; then + printf 'yes\n' + else + printf 'no\n' + fi +} + +thorium_reset diff --git a/meta/scripts/lib/shell_coverage_bar.sh b/meta/scripts/lib/shell_coverage_bar.sh index 7f8c1fea..50eaee8b 100755 --- a/meta/scripts/lib/shell_coverage_bar.sh +++ b/meta/scripts/lib/shell_coverage_bar.sh @@ -62,8 +62,19 @@ is_covered() { # --fail-on-case-error: a suite that dies partway must fail the gate, not # be graded on however many lines it managed to reach first. + # --timeout: the jail defaults to 120s per case, which is a hang-catcher + # rather than a performance budget -- and this repo's suites have outgrown + # it. fixes/lib/tests/run_all.sh measures 76s bare with 25 test files and + # 93s with 27, and kcov instrumentation roughly doubles that, so the + # default started failing the gate on libs that measured a clean 100% + # (bt_audio.sh: "127/127 lines = 100.00%" followed by "case timed out"). + # CI runners are slower than this workstation, so the ceiling is set well + # clear of the suite rather than just above it. The cost is that a genuine + # hang -- thorium_repairs.sh's `read -r -p` is exactly that shape -- now + # takes 10 minutes per pass to surface instead of 2. "$REPO_ROOT/meta/scripts/shell_coverage_jail.sh" \ --subject "$suite" \ + --timeout 600s \ "${jail_args[@]}" \ --measure "$(basename "$path")" \ --min "$COVERAGE_BAR" \ diff --git a/meta/shell-coverage-allowlist.txt b/meta/shell-coverage-allowlist.txt index 78090231..7de7c68f 100644 --- a/meta/shell-coverage-allowlist.txt +++ b/meta/shell-coverage-allowlist.txt @@ -79,7 +79,6 @@ linux_configuration/scripts/single_use/fixes/lib/hosts_guard_migrate.sh linux_configuration/scripts/single_use/fixes/lib/hosts_guard_rollback.sh linux_configuration/scripts/single_use/fixes/lib/nvidia_config.sh linux_configuration/scripts/single_use/fixes/lib/pacman_hook_stall_setup.sh -linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh linux_configuration/scripts/single_use/fixes/lib/ubuntu_perf_fixes.sh linux_configuration/scripts/single_use/fresh-install/lib/packages.sh linux_configuration/scripts/single_use/lib/joplin_server.sh