test: bats unit suite + shellcheck CI gating Docker publish#86
Open
PhilippMundhenk wants to merge 4 commits into
Open
test: bats unit suite + shellcheck CI gating Docker publish#86PhilippMundhenk wants to merge 4 commits into
PhilippMundhenk wants to merge 4 commits into
Conversation
Adds focused test coverage for the existing shell scripts plus a
GitHub Actions workflow that runs both static analysis and the unit
suite on every push (except master) and every pull request.
Coverage:
trigger_telegram.sh - env gating (token, chat id); wget invoked
with the right token URL and url-encoded body
trigger_inotify.sh - env gating; sshpass argv contains user@host
and remote path; non-zero exit when sshpass
fails
sendtoftps.sh - env gating; curl argv contains credentials,
ftp:// URL and file; non-zero exit + diagnostic
output on curl failure
remove_blank.sh - no-op when REMOVE_BLANK_THRESHOLD is unset;
pdfinfo/gs/pdftk pipeline runs when set
scantoemail.sh - prints trigger banner and delegates to
scanRear.sh with forwarded argv
scantoocr.sh, - placeholder scripts still emit the
scantoimage.sh "not implemented" notice
script_lint - every shell script parses with `bash -n`,
script/ files keep the executable bit, the
Dockerfile copies script/ into the image and
installs the packages remove_blank depends on
Mocking is done by shadowing external commands (`curl`, `wget`,
`sshpass`, `pdfinfo`, `gs`, `pdftk`, `nawk`, `bc`) via a PATH-prefixed
sandbox directory. See tests/helpers/common.bash for `mock_command`
and `mock_record`.
CI installs `bats` and `shellcheck` from the Ubuntu repos. Shellcheck
runs at --severity=error so pre-existing style issues do not break the
build; tighten once those are cleaned up.
Makefile gains `test`, `lint`, `bats` targets.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test.yml gains a workflow_call trigger so it can be reused. * publishMaster.yml, publishBranchesPRs.yml and publishTags.yml each add a `tests` job that calls test.yml, and `needs: tests` on the build-and-push-image job, so a shellcheck or bats failure aborts the Docker build instead of silently shipping a broken image. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The new test workflow runs shellcheck --severity=error and surfaced
several real bugs/quality issues in the existing scripts. None of them
change observable behaviour for typical Docker usage, but the fixes
let CI go green and prevent footguns:
run.sh, update-container.sh,
script/sendtoftps.sh,
script/trigger_inotify.sh
+ missing shebang line (SC2148)
script/scanRear.sh,
script/scantofile-0.2.4-1.sh
`gm convert ${gm_opts[@]}` -> `"${gm_opts[@]}"` so options
containing spaces (or future additions) are not word-split (SC2068)
script/scantoemail-0.2.4-1.sh
`scanRear.sh $@` -> `scanRear.sh "$@"` so a friendly-name with
spaces is forwarded as one argument (SC2068)
files/runScanner.sh
* `exit -1` -> `exit 1`. Exit codes are 0..255; -1 wraps to 255
and is non-portable across shells (SC2242).
* `if [[ -z {$NAME} ]]; then $NAME="Scanner"; fi`
The literal-braces test was always false (SC2157) and the LHS
`$NAME=...` is a syntax error when NAME is empty (SC2281), so
the intended "default NAME to Scanner" never ran. The Dockerfile
sets NAME via ENV so this rarely bit anyone, but the fixed form
now actually defaults correctly when the env var is missing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PhilippMundhenk
added a commit
that referenced
this pull request
May 17, 2026
ocr_enqueue.bats (5 cases): argument validation, job file format, atomic-rename hygiene (no leftover .tmp), sortable timestamp prefix, FIFO ordering of two enqueues. ocr_worker.bats (6 cases): startup recovery sweeps in_progress/ back to pending/; successful upload removes the job and writes the output PDF; REMOVE_ORIGINAL_AFTER_OCR removes the source PDF on success; repeated curl failures land in failed/ with ATTEMPTS=MAX; missing OCR_SERVER/PORT/PATH fails the job rather than looping forever; missing input PDF fails the job. Worker tests use a copy of the script with the linear backoff sed'd down to zero and a short OCR_QUEUE_POLL_SECONDS so a full failure cycle completes in seconds. To make the worker testable without a writable /scans, add an OCR_OUTPUT_DIR env var (defaults to /scans, override in tests to a sandbox dir). tests/helpers/common.bash is identical to the file added in #86 so a later merge of either branch is a clean no-op. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds focused shell-script test coverage and wires it into the publish workflows so a Docker image can no longer be built/pushed if static analysis or unit tests fail. Also fixes the real bugs in existing scripts that shellcheck surfaced.
What is tested
trigger_telegram.shtrigger_inotify.shsshpassargv containsuser@host+ remote path, non-zero exit on ssh failuresendtoftps.shcurlinvoked with credentials/URL/file, non-zero exit + diagnostic output on failureremove_blank.shREMOVE_BLANK_THRESHOLDunset; pdfinfo/gs/pdftk pipeline runs when setscantoemail-0.2.4-1.shscanRear.shis invoked with forwarded argvscantoocr.sh/scantoimage.shbash -n;script/files keep the executable bit; Dockerfile copiesscript/into the image and installspdfinfo/gs/pdftkMocking is done by shadowing external commands (
curl,wget,sshpass,pdfinfo,gs,pdftk,nawk,bc) via a PATH-prefixed sandbox directory — seetests/helpers/common.bashformock_command/mock_record.CI integration
test.ymlgains aworkflow_calltrigger so the three existing publish workflows (publishMaster,publishBranchesPRs,publishTags) can each declare atestsjob that reuses it, withneeds: testson the build job. A shellcheck or bats failure now aborts the Docker build instead of silently shipping a broken image.Drive-by fixes uncovered by shellcheck
Running
shellcheck --severity=erroragainst the existing scripts flagged real bugs. Fixed in this PR so CI is green from day one:run.sh,update-container.sh,script/sendtoftps.sh,script/trigger_inotify.sh.script/scanRear.shandscript/scantofile-0.2.4-1.sh(gm convert ${gm_opts[@]}→"${gm_opts[@]}").$@inscript/scantoemail-0.2.4-1.sh(would drop spaces in a forwarded friendly-name).exit -1infiles/runScanner.sh→exit 1(exit codes are 0–255).files/runScanner.sh:if [[ -z {$NAME} ]]; then $NAME="Scanner"; fi— literal braces meant the test was always false (SC2157) and the LHS was a syntax error when NAME is empty (SC2281). Replaced with the intendedif [[ -z "$NAME" ]]; then NAME="Scanner"; fi. Rarely triggered because the Dockerfile setsENV NAME="Scanner", but now it actually works.What is not covered
The full
scantofile/scanRearscan pipeline (would need hours of mocked-up fixtures or live hardware),runScanner.shinterface detection (deeply tied to host networking), and the lighttpd PHP front-end. Worth a follow-up if you want broader coverage.The OCR queue tests will land with #85 once that PR merges; this branch is based on
masterand so doesn't see the queue scripts yet.Test plan
bats tests/unit— all green in CI.shellcheck --severity=error— clean in CI.make test/make lintwork locally for a maintainer withbatsandshellcheckinstalled.🤖 Generated with Claude Code