Test arch_perf_report.sh to 98.33% and fix its dead journal-size check

Fifth of the 16 untested fixes/lib libs and the first of the arch-performance
group, which gets its own harness here. 38 assertions across two files. The
lib STAYS on the allowlist at 59/60 = 98.33%, measured twice.

The second dead branch this campaign has found, fixed here. Lines 36 and 65
matched on:

    ([0-9]+\.?[0-9]*)\ (G|M)

a REQUIRED space before the unit. journalctl actually prints "Archived and
active journals take up 305.5M in the file system." with no separator --
verified against the real binary on this machine. So check_journal_size could
never report a large journal and apply_safe_fixes could never vacuum one:
both were unreachable. The space is now optional, and tests cover the spaced
and unspaced forms so neither can rot.

NOTE: this makes a previously-dead DESTRUCTIVE action live. With
--apply-safe-fixes and a journal over a gigabyte, the entry script will now
really run `journalctl --vacuum-size=300M`. That is the flag's documented
purpose and it stays behind the flag, but it has never actually executed
before today.

Line 20, the one uncovered line, is `} >>"$REPORT_FILE"` -- the closing brace
of a redirected group. A minimal probe writes both inner lines to the file
while bash attributes no statement to the brace, and the report assertions
independently prove the group runs, since they read the text it writes. Same
defect (a) class as bt_audio's `} |`.

That form now caps four libs: bt_audio.sh, arch_perf_report.sh, and
arch_perf_probes.sh and nvidia_config.sh which are still untested. So the
continuation_lines() fix is worth landing after all -- as its own commit,
next, so a denominator change can be reverted without taking these tests
with it.

_t_hide and _t_full_path move from bt_harness.sh into lib_test_core.sh: they
are generic PATH plumbing and the arch harness needs them for the
"nvidia-smi is not installed" branch. All twelve existing suites re-run green
after the move.

One trap worth recording: apply_safe_fixes appends to the ACTIONS array, so
it must be called directly rather than inside "$(...)" -- a command
substitution runs it in a subshell where the appends die with it, and the
assertions read an empty array.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-08-22 18:06:57 +02:00
parent a5b6663c02
commit ffcf99f102
8 changed files with 450 additions and 50 deletions

View File

@ -0,0 +1,18 @@
{
"title": "Test arch_perf_report.sh, open the arch-performance family, and fix the dead journal-size check",
"objective": "Cover the fifth of the sixteen untested fixes/lib libs and stand up the harness the arch-performance group will share. Writing the tests exposed a second dead branch -- the journal size regex demanded a space before the unit that journalctl never prints -- so this lands that fix alongside the coverage. The lib stops at 98.33%: its last line is a redirected closing brace no test can reach.",
"acceptance_criteria": [
"arch_perf_report.sh measures 98.33% (59/60) through lib/tests/run_all.sh, twice, with line 20 the only uncovered line both times.",
"The old journal regex is shown NOT to match journalctl's real output before the fix, and the fixed one shown to match both the spaced and unspaced forms.",
"Line 20 is shown to be a closing brace of a redirected group that executes, not a missing test.",
"meta/shell-coverage-allowlist.txt is UNCHANGED -- arch_perf_report.sh does not meet the 100% bar.",
"The four bluetooth suites and the eight pacman_hook_stall suites still pass after _t_hide and _t_full_path move into lib_test_core.sh.",
"Every file stays under the repo's 250-line cap, and pre-commit passes with no suppression added."
],
"out_of_scope": [
"Clearing arch_perf_report.sh, bt_audio.sh or bt_adapter.sh from the allowlist. All three are capped by defect (a) in docs/kcov-under-report.md.",
"Changing continuation_lines() in meta/scripts/lib/shell_coverage_lines.py. That is the next commit, kept separate so a denominator change can be reverted without losing these tests.",
"The remaining eleven untested fixes/lib libs."
],
"verifier": "bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh (expects all files passing, 17 + 21 for the two arch_perf_report files), plus bash meta/scripts/shell_coverage_jail.sh --subject linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh --measure arch_perf_report.sh --min 1 --fail-on-case-error -- \"\" (expects 59/60 = 98.33%, uncovered 20), plus bash meta/scripts/check_shell_coverage.sh on the cleared libs (expects exit 0)."
}

View File

@ -0,0 +1,55 @@
{
"intent": "Test linux_configuration/scripts/single_use/fixes/lib/arch_perf_report.sh, fifth of the 16 untested fixes/lib libs and the first of the arch-performance group, and fix a second production bug the tests exposed: the journal size check could never fire. The lib reaches 98.33% and STAYS on the allowlist, capped by one closing-brace line.",
"scope": [
"linux_configuration/scripts/single_use/fixes/lib/arch_perf_report.sh (two regexes: the journal size match)",
"linux_configuration/scripts/single_use/fixes/lib/tests/arch_perf_harness.sh (new family harness)",
"linux_configuration/scripts/single_use/fixes/lib/tests/test_arch_perf_report.sh (new, 17 assertions)",
"linux_configuration/scripts/single_use/fixes/lib/tests/test_arch_perf_report_fixes.sh (new, 21 assertions)",
"linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh and bt_harness.sh (_t_hide/_t_full_path moved into the core)",
"meta/shell-coverage-allowlist.txt is deliberately UNCHANGED: arch_perf_report.sh does not meet the 100% bar"
],
"changes": [
"Fixed the journal size regexes in arch_perf_report.sh, lines 36 and 65. Both required a SPACE before the unit -- ([0-9]+\\.?[0-9]*)\\ (G|M) -- but journalctl prints 'Archived and active journals take up 305.5M in the file system.' with no separator, verified on this machine. check_journal_size could therefore never report a large journal, and apply_safe_fixes could never vacuum one: both were dead code. The space is now optional (\\ ?), and tests cover the spaced and unspaced forms.",
"Added arch_perf_harness.sh: sources lib_test_core.sh and the real scripts/lib/common.sh, points REPORT_FILE into the throwaway tmpdir, and redefines add_finding, add_action and run_and_log verbatim from diagnose_arch_performance.sh, which owns them rather than any lib.",
"Added test_arch_perf_report.sh covering check_gpu_state (nvidia-smi absent, an idle GPU pinned in P0, a busy P0 GPU that must NOT be flagged, an idle GPU in a low-power state, and nvidia-smi returning nothing) and check_journal_size (gigabyte, megabyte, space-separated, and journalctl failing).",
"Added test_arch_perf_report_fixes.sh covering apply_safe_fixes (disabled by the flag, nothing to do, enabling a disabled fstrim.timer, disabling a conflicting tlp.service, and vacuuming a multi-gigabyte journal) and print_summary (clean run, findings listed and counted, actions section).",
"Moved _t_hide and _t_full_path from bt_harness.sh into lib_test_core.sh. They are generic PATH plumbing, not bluetooth-specific, and the arch harness needs them for the 'nvidia-smi is not installed' branch.",
"apply_safe_fixes is called directly rather than inside a command substitution: it appends to the ACTIONS array, and a substitution runs it in a subshell where those appends die with it, leaving the assertions reading an empty array."
],
"verification": [
{
"command": "bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh",
"result": "pass",
"evidence": "arch_perf_report (probes): 17 passed; arch_perf_report (fixes/summary): 21 passed; both 0 failed. All fixes lib test files passed, so the four bluetooth libs and the eight pacman_hook_stall suites stay green after _t_hide moved into the core."
},
{
"command": "bash meta/scripts/shell_coverage_jail.sh --subject linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh --measure arch_perf_report.sh --min 1 --fail-on-case-error -- \"\"",
"result": "pass",
"evidence": "arch_perf_report.sh: 59/60 lines = 98.33%, uncovered: 20. Run twice with the identical line set."
},
{
"command": "bash -c 'line=\"...take up 4.2G in the file system.\"; [[ $line =~ ([0-9]+\\.?[0-9]*)\\ (G|M) ]]'",
"result": "pass",
"evidence": "Reproduced the bug before fixing: NO MATCH against the old regex, so no journal size could ever be flagged. With the optional space the same line matches and yields 4.2G. journalctl on this host prints '305.5M' with no space, confirming the real format the old regex excluded."
},
{
"command": "Read uncovered line 20 and probe it minimally",
"result": "pass",
"evidence": "Line 20 is '} >>\"$REPORT_FILE\"', the closing brace of a redirected group. A minimal probe ({ echo a; echo b; } >>file inside a function) writes both lines to the file while bash attributes no statement to the closing brace. The report assertions independently prove the group runs, since they read the very text it writes. Same defect (a) class as bt_audio's '} |' lines."
},
{
"command": "grep -lE '^[[:space:]]*\\}[[:space:]]*>' over all 22 fixes/lib libs",
"result": "pass",
"evidence": "The redirected-closing-brace form appears in arch_perf_report.sh, arch_perf_probes.sh and nvidia_config.sh. Together with bt_audio.sh's '} |' that is four libs capped by one detector gap, which is why the continuation_lines() fix is now worth landing as its own commit."
}
],
"risks": [
"The journal regex fix makes a previously-dead DESTRUCTIVE action live. apply_safe_fixes will now actually run 'journalctl --vacuum-size=300M' when the entry script is invoked with --apply-safe-fixes and the journal exceeds a gigabyte, deleting roughly 3.9G of logs on a 4.2G journal. That is the documented intent of the flag, and the vacuum still only runs behind it, but it has never actually executed before this commit.",
"arch_perf_report.sh stays on the allowlist at 98.33%, capped by line 20. Clearing it needs continuation_lines() in meta/scripts/lib/shell_coverage_lines.py to exclude a closing brace followed by a redirection or pipe, which lands separately so a regression can be reverted without losing these tests.",
"The GPU tests stub nvidia-smi rather than reading the real card, so they assert on the lib's parsing of a known nvidia-smi contract, not on this host's actual GPU state."
],
"rollback": [
"git revert the commit; it adds a harness and two test files, moves two helpers between harness files, and changes two regexes in one lib. No allowlist entry is touched.",
"After rollback, run bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh and confirm the remaining suites pass; the coverage gate is unaffected since arch_perf_report.sh stays exempt either way."
]
}

View File

@ -33,7 +33,10 @@ check_journal_size() {
journal_line=$(journalctl --disk-usage 2>/dev/null || true)
echo "Journal usage: ${journal_line:-unknown}" >>"$REPORT_FILE"
if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ (G|M) ]]; then
# The space before the unit is OPTIONAL: journalctl prints "305.5M in
# the file system", with no separator, so requiring one made this check
# dead code that could never report a large journal.
if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ ?(G|M) ]]; then
local value unit
value="${BASH_REMATCH[1]}"
unit="${BASH_REMATCH[2]}"
@ -62,7 +65,8 @@ apply_safe_fixes() {
local journal_line
journal_line=$(journalctl --disk-usage 2>/dev/null || true)
if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ G ]]; then
# Optional space, as in check_journal_size above.
if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ ?G ]]; then
journalctl --vacuum-size=300M
add_action "Vacuumed systemd journal to 300M."
fi

View File

@ -0,0 +1,96 @@
#!/usr/bin/env bash
# lib/tests/arch_perf_harness.sh — shared setup for the arch performance lib
# tests (arch_perf_report.sh, arch_perf_probes.sh).
#
# Sourced, not executed. Builds on lib_test_core.sh and adds the pieces these
# libs read from their entry script, diagnose_arch_performance.sh:
#
# * REPORT_FILE, FINDINGS, ACTIONS and the APPLY_SAFE_FIXES flag;
# * add_finding, add_action and run_and_log, redefined verbatim from the
# entry script -- they live there rather than in any lib, the same
# arrangement pacman_hook_stall_harness.sh handles with log_size;
# * the real log_*/has_cmd helpers, via scripts/lib/common.sh.
#
# REPORT_FILE points into the throwaway tmpdir, so the probes' report writes
# never leave the sandbox.
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 diagnose_arch_performance.sh --------------
# These four are read by the libs under test, never by this harness, so
# static analysis cannot see the use; export makes the intent explicit.
export REPORT_FILE="${TEST_TMPDIR}/report.log"
export APPLY_SAFE_FIXES="false"
export INSTALL_TOOLS="false"
declare -a FINDINGS=()
declare -a ACTIONS=()
# Verbatim from diagnose_arch_performance.sh.
add_finding() {
FINDINGS+=("$1")
log_warn "$1"
}
add_action() {
ACTIONS+=("$1")
log_info "$1"
}
run_and_log() {
local header="$1"
shift
{
echo
echo "=== $header ==="
"$@" 2>&1 || true
} >>"$REPORT_FILE"
}
# --- external tool stubs ----------------------------------------------------
_arch_default_stubs() {
local tool
for tool in nvidia-smi lspci journalctl systemctl sysctl lsblk sensors \
free uptime ps top swapon findmnt pacman systemd-analyze; do
_t_stub "$tool" 'exit 0'
done
}
# arch_reset — start a test group from "nothing has happened yet".
arch_reset() {
_t_reset_calls
FINDINGS=()
ACTIONS=()
APPLY_SAFE_FIXES="false"
INSTALL_TOOLS="false"
export APPLY_SAFE_FIXES INSTALL_TOOLS
: >"$REPORT_FILE"
_t_full_path
_arch_default_stubs
}
# _t_report — the report file's contents this round.
_t_report() {
cat "$REPORT_FILE" 2>/dev/null || true
}
# _t_findings / _t_actions — the recorded findings and actions, one per line.
_t_findings() {
printf '%s\n' "${FINDINGS[@]:-}"
}
_t_actions() {
printf '%s\n' "${ACTIONS[@]:-}"
}
arch_reset

View File

@ -99,54 +99,6 @@ SUDO_BODY
_t_stub sudo "$sudo_body"
}
# _t_hide TOOL... — make TOOL genuinely unfindable, so has_cmd/command -v
# report it absent.
#
# A prepended stub dir cannot do this: every tool these libs probe for
# (usbreset, pactl, wpctl) really exists on an Arch desktop, so PATH has to
# stop resolving it. Dropping PATH to $FAKE_BIN alone is NOT the answer
# either -- that also hides grep, head, awk and sort, which these libs use
# on the very branch under test, turning a "not installed" case into a
# cascade of "command not found".
#
# Instead a shim dir is built containing a symlink to every real executable
# on PATH EXCEPT the hidden ones, and PATH is pointed at it.
_t_hide() {
local hide_dir="${TEST_TMPDIR}/hidden_path"
rm -rf "$hide_dir"
mkdir -p "$hide_dir"
local -A hidden=()
local tool
for tool in "$@"; do
hidden["$tool"]=1
done
local dir entry name
local IFS=':'
for dir in ${LIB_TEST_ORIG_PATH}; do
[[ -d "$dir" ]] || continue
for entry in "$dir"/*; do
name="${entry##*/}"
[[ -n "${hidden[$name]:-}" ]] && continue
[[ -x "$entry" && ! -d "$entry" ]] || continue
[[ -e "${hide_dir}/${name}" ]] && continue
ln -s "$entry" "${hide_dir}/${name}" 2>/dev/null || true
done
done
PATH="${FAKE_BIN}:${hide_dir}"
hash -r
}
# _t_full_path — restore the prepended-stub PATH set up by lib_test_core.sh.
_t_full_path() {
PATH="${FAKE_BIN}:${LIB_TEST_ORIG_PATH}"
hash -r
}
export LIB_TEST_ORIG_PATH="${PATH#"${FAKE_BIN}:"}"
# bt_reset — start a test group from "nothing has happened yet".
bt_reset() {
_t_reset_calls

View File

@ -134,6 +134,54 @@ _t_unstub() {
hash -r
}
# _t_hide TOOL... — make TOOL genuinely unfindable, so has_cmd/command -v
# report it absent.
#
# A prepended stub dir cannot do this: every tool these libs probe for
# (usbreset, pactl, wpctl) really exists on an Arch desktop, so PATH has to
# stop resolving it. Dropping PATH to $FAKE_BIN alone is NOT the answer
# either -- that also hides grep, head, awk and sort, which these libs use
# on the very branch under test, turning a "not installed" case into a
# cascade of "command not found".
#
# Instead a shim dir is built containing a symlink to every real executable
# on PATH EXCEPT the hidden ones, and PATH is pointed at it.
_t_hide() {
local hide_dir="${TEST_TMPDIR}/hidden_path"
rm -rf "$hide_dir"
mkdir -p "$hide_dir"
local -A hidden=()
local tool
for tool in "$@"; do
hidden["$tool"]=1
done
local dir entry name
local IFS=':'
for dir in ${LIB_TEST_ORIG_PATH}; do
[[ -d "$dir" ]] || continue
for entry in "$dir"/*; do
name="${entry##*/}"
[[ -n "${hidden[$name]:-}" ]] && continue
[[ -x "$entry" && ! -d "$entry" ]] || continue
[[ -e "${hide_dir}/${name}" ]] && continue
ln -s "$entry" "${hide_dir}/${name}" 2>/dev/null || true
done
done
PATH="${FAKE_BIN}:${hide_dir}"
hash -r
}
# _t_full_path — restore the prepended-stub PATH set up by lib_test_core.sh.
_t_full_path() {
PATH="${FAKE_BIN}:${LIB_TEST_ORIG_PATH}"
hash -r
}
export LIB_TEST_ORIG_PATH="${PATH#"${FAKE_BIN}:"}"
# _t_calls — print everything the stubs recorded this round.
_t_calls() {
cat "${DEV}/calls" 2>/dev/null || true

View File

@ -0,0 +1,116 @@
#!/usr/bin/env bash
# Tests for lib/arch_perf_report.sh: check_gpu_state, check_journal_size,
# apply_safe_fixes and print_summary.
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=arch_perf_harness.sh
. "${SCRIPT_DIR}/arch_perf_harness.sh"
# shellcheck source=../arch_perf_report.sh
. "${FIXES_DIR}/lib/arch_perf_report.sh"
# --- check_gpu_state --------------------------------------------------------
# No nvidia-smi: falls back to listing PCI display devices. The host may have
# a real nvidia-smi, so _t_hide takes it off PATH outright.
arch_reset
_t_unstub nvidia-smi
_t_hide nvidia-smi
_t_stub lspci 'echo "01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GA104"'
check_gpu_state
_t_full_path
_t_contains "$(_t_report)" "=== PCI VGA Devices ===" \
"check_gpu_state: logs PCI display devices when nvidia-smi is absent"
_t_eq "" "$(_t_findings)" "check_gpu_state: records no finding without nvidia-smi"
# An idle GPU pinned in P0 is the condition the check exists for.
arch_reset
_t_stub_stdin nvidia-smi <<'STUB_BODY'
case "$1" in
--query-gpu=pstate) echo P0 ;;
--query-gpu=utilization.gpu) echo 2 ;;
--query-gpu=power.draw) echo 31.5 ;;
*) echo "full nvidia-smi output" ;;
esac
STUB_BODY
check_gpu_state
_t_contains "$(_t_report)" "NVIDIA pstate: P0" \
"check_gpu_state: records the reported pstate"
_t_contains "$(_t_report)" "NVIDIA util: 2%" \
"check_gpu_state: records the reported utilisation"
_t_contains "$(_t_report)" "NVIDIA power: 31.5W" \
"check_gpu_state: records the reported power draw"
_t_contains "$(_t_findings)" "P0 high-performance state while mostly idle" \
"check_gpu_state: flags a GPU idling in P0"
_t_contains "$(_t_actions)" "prefer iGPU mode" \
"check_gpu_state: recommends the iGPU for desktop workloads"
# A busy GPU in P0 is normal and must NOT be flagged.
arch_reset
_t_stub_stdin nvidia-smi <<'STUB_BODY'
case "$1" in
--query-gpu=pstate) echo P0 ;;
--query-gpu=utilization.gpu) echo 87 ;;
--query-gpu=power.draw) echo 210 ;;
*) echo "out" ;;
esac
STUB_BODY
check_gpu_state
_t_eq "" "$(_t_findings)" "check_gpu_state: does not flag a P0 GPU that is actually busy"
# An idle GPU in a low-power state is also fine.
arch_reset
_t_stub_stdin nvidia-smi <<'STUB_BODY'
case "$1" in
--query-gpu=pstate) echo P8 ;;
--query-gpu=utilization.gpu) echo 0 ;;
--query-gpu=power.draw) echo 9 ;;
*) echo "out" ;;
esac
STUB_BODY
check_gpu_state
_t_eq "" "$(_t_findings)" "check_gpu_state: does not flag an idle GPU in a low-power state"
# nvidia-smi present but answering nothing: the report records "unknown".
arch_reset
_t_stub nvidia-smi 'exit 0'
check_gpu_state
_t_contains "$(_t_report)" "NVIDIA pstate: unknown" \
"check_gpu_state: records 'unknown' when nvidia-smi returns nothing"
# --- check_journal_size -----------------------------------------------------
arch_reset
_t_stub journalctl 'echo "Archived and active journals take up 4.2G in the file system."'
check_journal_size
_t_contains "$(_t_report)" "Journal usage:" "check_journal_size: records journal usage"
_t_contains "$(_t_findings)" "journal is large (4.2G)" \
"check_journal_size: flags a multi-gigabyte journal"
# The real journalctl format, with NO space before the unit -- this is what
# the machine actually prints, and requiring a space made the check dead.
arch_reset
_t_stub journalctl 'echo "Archived and active journals take up 240.0M in the file system."'
check_journal_size
_t_eq "" "$(_t_findings)" "check_journal_size: does not flag a journal measured in megabytes"
_t_contains "$(_t_report)" "240.0M" \
"check_journal_size: records the megabyte figure verbatim"
# A space-separated figure must keep working too.
arch_reset
_t_stub journalctl 'echo "Archived and active journals take up 6.1 G in the file system."'
check_journal_size
_t_contains "$(_t_findings)" "journal is large (6.1G)" \
"check_journal_size: still flags a space-separated gigabyte figure"
arch_reset
_t_stub journalctl 'exit 1'
check_journal_size
_t_contains "$(_t_report)" "Journal usage: unknown" \
"check_journal_size: records 'unknown' when journalctl fails"
_t_eq "" "$(_t_findings)" "check_journal_size: records no finding when journalctl fails"
echo
echo "arch_perf_report (probes): ${PASS} passed, ${FAIL} failed"
((FAIL == 0))

View File

@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Tests for lib/arch_perf_report.sh: apply_safe_fixes and print_summary.
# Split from test_arch_perf_report.sh for the 250-line cap.
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=arch_perf_harness.sh
. "${SCRIPT_DIR}/arch_perf_harness.sh"
# shellcheck source=../arch_perf_report.sh
. "${FIXES_DIR}/lib/arch_perf_report.sh"
# --- apply_safe_fixes -------------------------------------------------------
# Off by default: the flag guards every mutation.
arch_reset
APPLY_SAFE_FIXES="false"
apply_safe_fixes >"${TEST_TMPDIR}/out" 2>&1
out="$(cat "${TEST_TMPDIR}/out")"
_t_eq "" "$out" "apply_safe_fixes: does nothing unless APPLY_SAFE_FIXES is true"
_t_eq "" "$(_t_calls)" "apply_safe_fixes: runs no command when disabled"
# fstrim.timer already enabled, no tlp/ppd conflict, small journal: nothing
# to do, but the pass still announces itself.
arch_reset
APPLY_SAFE_FIXES="true"
_t_stub systemctl 'exit 0'
_t_stub journalctl 'echo "Archived and active journals take up 120.0M in the file system."'
apply_safe_fixes >"${TEST_TMPDIR}/out" 2>&1
out="$(cat "${TEST_TMPDIR}/out")"
_t_contains "$out" "Applying safe fixes" "apply_safe_fixes: announces the pass"
_t_lacks "$(_t_calls)" "systemctl enable --now fstrim.timer" \
"apply_safe_fixes: does not re-enable an already-enabled fstrim.timer"
_t_lacks "$(_t_calls)" "journalctl --vacuum-size" \
"apply_safe_fixes: does not vacuum a journal measured in megabytes"
# fstrim.timer disabled: it gets enabled.
arch_reset
APPLY_SAFE_FIXES="true"
_t_stub_stdin systemctl <<'STUB_BODY'
if [[ "$1" == "is-enabled" && "$2" == "fstrim.timer" ]]; then
exit 1
fi
exit 0
STUB_BODY
_t_stub journalctl 'echo "120.0M"'
apply_safe_fixes >"${TEST_TMPDIR}/out" 2>&1
out="$(cat "${TEST_TMPDIR}/out")"
_t_contains "$(_t_calls)" "systemctl enable --now fstrim.timer" \
"apply_safe_fixes: enables a disabled fstrim.timer"
_t_contains "$(_t_actions)" "Enabled and started fstrim.timer" \
"apply_safe_fixes: records enabling fstrim.timer as an action"
# tlp and power-profiles-daemon both enabled: tlp is disabled to break the
# conflict.
arch_reset
APPLY_SAFE_FIXES="true"
_t_stub systemctl 'exit 0'
_t_stub journalctl 'echo "120.0M"'
apply_safe_fixes >"${TEST_TMPDIR}/out" 2>&1
out="$(cat "${TEST_TMPDIR}/out")"
_t_contains "$(_t_calls)" "systemctl disable --now tlp.service" \
"apply_safe_fixes: disables tlp.service when it conflicts with ppd"
_t_contains "$(_t_actions)" "Disabled tlp.service" \
"apply_safe_fixes: records disabling tlp.service as an action"
# A multi-gigabyte journal gets vacuumed. This only fires because the size
# regex now tolerates journalctl's spaceless "4.2G" output.
arch_reset
APPLY_SAFE_FIXES="true"
_t_stub systemctl 'exit 0'
_t_stub journalctl 'echo "Archived and active journals take up 4.2G in the file system."'
apply_safe_fixes >"${TEST_TMPDIR}/out" 2>&1
out="$(cat "${TEST_TMPDIR}/out")"
_t_contains "$(_t_calls)" "journalctl --vacuum-size=300M" \
"apply_safe_fixes: vacuums a multi-gigabyte journal"
_t_contains "$(_t_actions)" "Vacuumed systemd journal to 300M" \
"apply_safe_fixes: records the vacuum as an action"
# --- print_summary ----------------------------------------------------------
arch_reset
out="$(print_summary 2>&1)"
_t_contains "$out" "Arch Performance Diagnostics" "print_summary: prints the banner"
_t_contains "$out" "Report: ${REPORT_FILE}" "print_summary: names the report file"
_t_contains "$out" "No high-confidence bottlenecks detected" \
"print_summary: reports a clean run when there are no findings"
_t_contains "$out" "systemd-analyze blame" \
"print_summary: suggests the deep-analysis commands"
arch_reset
add_finding "first problem" >/dev/null
add_finding "second problem" >/dev/null
out="$(print_summary 2>&1)"
_t_contains "$out" "Likely issues found (2)" \
"print_summary: counts the findings it lists"
_t_contains "$out" "- first problem" "print_summary: lists the first finding"
_t_contains "$out" "- second problem" "print_summary: lists the second finding"
_t_lacks "$out" "No high-confidence bottlenecks" \
"print_summary: does not claim a clean run when findings exist"
arch_reset
add_action "do the thing" >/dev/null
out="$(print_summary 2>&1)"
_t_contains "$out" "Actions/recommendations:" \
"print_summary: prints the actions section when actions exist"
_t_contains "$out" "- do the thing" "print_summary: lists the recorded action"
echo
echo "arch_perf_report (fixes/summary): ${PASS} passed, ${FAIL} failed"
((FAIL == 0))