diff --git a/.github/workflows/shell-tests.yml b/.github/workflows/shell-tests.yml new file mode 100644 index 00000000..8a960f3f --- /dev/null +++ b/.github/workflows/shell-tests.yml @@ -0,0 +1,56 @@ +name: Shell tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + shell-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install bats + run: sudo apt-get update && sudo apt-get install -y bats + + - name: Run bats suites + run: bats linux_configuration/tests/*.bats + + # Only the side-effect-free tests run here. The rest of + # linux_configuration/tests/ drives pacman, /etc, systemd or adb and + # cannot run on an Ubuntu runner without root and an Arch container -- + # see docs note in the accompanying evidence artifact. + # + # Deliberately NOT in this list (both fail today, and both look like they + # are catching real polling-efficiency regressions rather than being + # stale -- they need a fix in the scripts they cover, not in the tests): + # test_music_parallelism.sh + # 'idle mode uses the idle interval' expects 30s but the daemon + # waits 15s, i.e. it wakes twice as often as intended when idle. + # test_usage_monitoring_installer_efficiency.sh + # 'logger template must sleep between day rollover checks'. + - name: Run side-effect-free shell tests + run: | + set -euo pipefail + tests=( + test_android_guardian_post_fs_data.sh + test_android_guardian_service.sh + test_i3blocks_persist_common.sh + test_setup_dns_blocker.sh + ) + failed=0 + for t in "${tests[@]}"; do + printf '\n=== %s ===\n' "$t" + if bash "linux_configuration/tests/$t"; then + printf 'PASS %s\n' "$t" + else + printf 'FAIL %s\n' "$t" + failed=$((failed + 1)) + fi + done + if [ "$failed" -gt 0 ]; then + printf '\n%d shell test(s) failed\n' "$failed" + exit 1 + fi diff --git a/docs/superpowers/evidence/shell-tests-ci-2026-07-19.json b/docs/superpowers/evidence/shell-tests-ci-2026-07-19.json new file mode 100644 index 00000000..df24c91b --- /dev/null +++ b/docs/superpowers/evidence/shell-tests-ci-2026-07-19.json @@ -0,0 +1,40 @@ +{ + "intent": "Run the repo's shell tests in CI instead of leaving them manual-only, and repair the ones broken by an earlier directory reorganisation so they can participate.", + "scope": [ + ".github/workflows/shell-tests.yml (new): runs the bats suites plus the side-effect-free .sh tests on ubuntu-latest", + "linux_configuration/tests/test_android_guardian_service.sh, test_music_parallelism.sh, test_usage_monitoring_installer_efficiency.sh: stale path repairs", + "Non-goal: running the ~8 Arch-specific tests (pacman, /etc, systemd, adb). They need root and an Arch container; excluded with a comment in the workflow.", + "Non-goal: fixing the two efficiency regressions these repairs uncovered — those are bugs in the covered scripts, not in the tests." + ], + "changes": [ + "New Shell tests workflow, mirroring the existing pre-commit.yml style: checkout, apt-install bats, run all *.bats, then run an explicit allowlist of side-effect-free .sh tests, accumulating failures so one bad test does not mask the rest.", + "test_music_parallelism.sh and test_usage_monitoring_installer_efficiency.sh pointed at scripts// paths that moved under scripts/periodic_background/ in an earlier reorganisation; both now resolve.", + "test_android_guardian_service.sh created its temp worktree at scripts/single_use/utils/android_guardian while copying into scripts/periodic_background/utils/android_guardian, so the cp always failed. The mkdir now matches the cp target and the test passes." + ], + "verification": [ + { + "command": "bats linux_configuration/tests/*.bats", + "result": "pass", + "evidence": "1..30, all ok." + }, + { + "command": "bash linux_configuration/tests/", + "result": "pass", + "evidence": "test_android_guardian_post_fs_data.sh, test_android_guardian_service.sh, test_i3blocks_persist_common.sh, test_setup_dns_blocker.sh — 0 failures. Before this change test_android_guardian_service.sh failed with 'cp: cannot create regular file ... No such file or directory'." + }, + { + "command": "local simulation of the workflow's two run steps", + "result": "pass", + "evidence": "Both steps exit 0, so the workflow should be green on first run." + } + ], + "risks": [ + "Two repaired tests still fail and are deliberately excluded from CI, because they appear to catch genuine polling-efficiency regressions rather than being stale: test_music_parallelism.sh asserts idle mode waits IDLE_CHECK_INTERVAL (30s) but the daemon waits 15s — it wakes twice as often as intended when idle, contrary to the repo's polling guidance; test_usage_monitoring_installer_efficiency.sh asserts the logger template sleeps between day-rollover checks. Both need a fix in the scripts they cover. Until then the exclusion list hides two known-red tests, which is why it is commented in the workflow rather than left implicit.", + "The allowlist is manual: a new .sh test will not run in CI until someone adds it. Chosen over a glob because most tests in that directory cannot run on an Ubuntu runner.", + "Ubuntu's bats may lag the Arch version used locally (1.13.0); the suite uses only core bats features, no bats-assert or bats-support." + ], + "rollback": [ + "git revert this commit: CI stops running shell tests and the three path repairs are undone, restoring the spurious 'No such file' failure in test_android_guardian_service.sh.", + "Validate after rollback: .github/workflows/shell-tests.yml is absent and the three tests reference their pre-reorganisation paths again." + ] +} diff --git a/linux_configuration/tests/test_android_guardian_service.sh b/linux_configuration/tests/test_android_guardian_service.sh index 49c2ff5c..41e1fc18 100755 --- a/linux_configuration/tests/test_android_guardian_service.sh +++ b/linux_configuration/tests/test_android_guardian_service.sh @@ -28,7 +28,7 @@ cleanup() { trap cleanup EXIT WORKTREE="$TMP_DIR/worktree" -mkdir -p "$WORKTREE/scripts/single_use/utils/android_guardian" +mkdir -p "$WORKTREE/scripts/periodic_background/utils/android_guardian" cp "$TARGET_SCRIPT" "$WORKTREE/scripts/periodic_background/utils/android_guardian/service.sh" printf 'Checking skip-main avoids boot side effects...\n' diff --git a/linux_configuration/tests/test_music_parallelism.sh b/linux_configuration/tests/test_music_parallelism.sh index 08c7758a..60ab34f2 100755 --- a/linux_configuration/tests/test_music_parallelism.sh +++ b/linux_configuration/tests/test_music_parallelism.sh @@ -5,7 +5,7 @@ set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) REPO_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd) -TARGET_SCRIPT="$REPO_DIR/scripts/digital_wellbeing/music_parallelism.sh" +TARGET_SCRIPT="$REPO_DIR/scripts/periodic_background/digital_wellbeing/music_parallelism.sh" fail() { printf 'FAIL: %s\n' "$1" >&2 diff --git a/linux_configuration/tests/test_usage_monitoring_installer_efficiency.sh b/linux_configuration/tests/test_usage_monitoring_installer_efficiency.sh index d93ffd2d..0f660e63 100755 --- a/linux_configuration/tests/test_usage_monitoring_installer_efficiency.sh +++ b/linux_configuration/tests/test_usage_monitoring_installer_efficiency.sh @@ -5,7 +5,7 @@ set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) REPO_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd) -INSTALLER="$REPO_DIR/scripts/system-maintenance/bin/install_usage_monitoring.sh" +INSTALLER="$REPO_DIR/scripts/periodic_background/system-maintenance/bin/install_usage_monitoring.sh" fail() { printf 'FAIL: %s\n' "$1" >&2