Commit Graph
19 Commits
Author SHA1 Message Date
Tobias KaupatandClaude Sonnet 5.5 d644d71eec fix: keep backup.sh executable in the sabotage self test
The sed+mv rewrite left backup.sh at mode 644, so /bin/backup in the
sabotage image was not executable and the suite failed for the wrong
reason. Restore the executable bit and make --sabotage fail when
backup.sh is not executable or the log contains 'permission denied'.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 11:06:20 +02:00
Tobias KaupatandClaude Sonnet 5.5 140b29ef5a test: check the msmtp config copy at real container startup
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:40:42 +02:00
Tobias KaupatandClaude Sonnet 5.5 bc3dfcd950 test: probe the image once for all features
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:39:42 +02:00
Tobias KaupatandClaude Sonnet 5.5 421006e90b test: copy the structure config into the tool container instead of bind mounting
Works with a remote DOCKER_HOST as well.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:39:18 +02:00
Tobias KaupatandClaude Sonnet 5.5 e4016ef8fe test: print only the comment header for run.sh --help
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:39:03 +02:00
Tobias KaupatandClaude Sonnet 5.5 8607aa441c test: describe the structure suite fallback in the run.sh header
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:38:56 +02:00
Tobias KaupatandClaude Sonnet 5.5 c49d1810ca test: sabotage self test must fail the backup assertions by name
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:38:48 +02:00
Tobias KaupatandClaude Sonnet 5.5 abe01179de test: avoid GNU-only sed -i in the sabotage self test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:38:48 +02:00
Tobias KaupatandClaude Sonnet 5.5 66ca99bda3 test: make snapshot_count fail loudly on restic errors
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:36:37 +02:00
Tobias KaupatandClaude Sonnet 5.5 0d841ee98e test: make the failed-backup snapshot assertion target the repo the run used
Fail the backup via a nonexistent source on the initialised default repo
instead of a nonexistent repository, so snapshot_count can actually go red.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:36:11 +02:00
Tobias KaupatandClaude Sonnet 5.5 1c610aec4b test: match the snapshot hostname via restic --host in the stream test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:18:29 +02:00
Tobias KaupatandClaude Sonnet 5.5 6e06da89a3 test: assert the restic restore exit code
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:18:04 +02:00
Tobias KaupatandClaude Sonnet 5.5 76975658a7 fix: reject --suite without a value instead of running all suites
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:16:59 +02:00
Tobias KaupatandClaude Sonnet 5.5 aab8db6f89 test: cover CHECK_CRON cron line and pre/post-check hooks
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 10:13:07 +02:00
Tobias KaupatandClaude Opus 5 c138bd24d3 test: prove RESTIC_JOB_ARGS reaches restic backup
The suite recorded RESTIC_JOB_ARGS only indirectly through backup-last.log,
which proves nothing about restic ever seeing the arguments. Removing
${RESTIC_JOB_ARGS} from the restic backup call in backup.sh left compat at
32 passed, 0 failed - exactly the failure class this PR is supposed to
catch, and exactly blocker 1 of PR #109.

compat.sh gets a section that runs a backup with
RESTIC_JOB_ARGS=--exclude=/data/skipme.txt and requires the excluded file
to be absent from the restore while the other file is restored intact, so
the arguments must have a visible effect.

features.sh gets the matching assertion inside the existing `stream`
feature gate (RESTIC_JOB_ARGS=--host=jobargshost must show up in the
snapshot metadata of a stdin backup). It is reported as SKIP until PR #109
is rebased, which is the point of the gate.

Verification on Git-Bash:
  bash test/run.sh -> structure 13/13, compat 39 passed 0 failed,
                      features 4 SKIP, exit 0
  sabotage (backup.sh:40 ${RESTIC_JOB_ARGS} removed), rebuilt image
  IMAGE=rbd-sab-jobargs bash test/compat.sh
    -> FAIL RESTIC_JOB_ARGS is passed to restic backup
       "the excluded file was backed up anyway"
    -> 38 passed, 1 failed, exit 1
backup.sh was restored with git checkout and the sabotage image removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Agent-Id: agent-4966d0e6-7f4d-4b37-be3d-0648ed56cb8a
2026-10-17 23:36:56 +02:00
Tobias KaupatandClaude Opus 5 0aced54891 test: prove restic check actually fails on a corrupted repository
compat.sh only grepped the check output for "Check Successful". check.sh
prints that string whenever restic exits 0, so a `restic check` that had
been turned into a no-op kept the suite green - the integrity check, half
the purpose of this image, was untested.

Adds a section that backs up, overwrites the first pack file under
/mnt/restic/data with garbage and then requires the failure path:
"Check Failed with Status", no "Check Successful", and
/var/log/check-error-last.log written. It uses its own throwaway container
so the later tests do not inherit the broken repository.

Verification on Git-Bash:
  bash test/compat.sh                    -> 36 passed, 0 failed
  sabotage (check.sh: restic check -> true), rebuilt image
  IMAGE=rbd-sab-check bash test/compat.sh -> 33 passed, 3 failed, exit 1
    - restic check detects a corrupted repository
    - a corrupted repository is not reported as successful
    - failing check writes check-error-last.log
check.sh was restored with git checkout and the sabotage image removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Agent-Id: agent-4966d0e6-7f4d-4b37-be3d-0648ed56cb8a
2026-10-17 23:30:57 +02:00
Tobias KaupatandClaude Opus 5 6cb2f72cf9 fix: make the test suites work on Windows/Git-Bash out of the box
MSYS rewrites POSIX-looking arguments before docker sees them, so
`docker exec <id> /usr/bin/backup` arrived as
`C:/Program Files/Git/usr/bin/backup` and the structure suite could not
read `--config /test/structure.yml`. 23 of 32 compat assertions and the
whole structure suite failed on Git-Bash, while test/lib.sh claimed the
suites behave identically on every platform.

test/lib.sh and test/run.sh now export MSYS_NO_PATHCONV=1 and
MSYS2_ARG_CONV_EXCL='*' themselves - lib.sh for the suites that source it,
run.sh for its own docker calls and the suites it starts as separate
processes. Both variables are ignored on Linux and macOS. README documents
that nothing has to be exported by hand.

Verified on Git-Bash without any variable set in the environment:
structure 13/13, compat 32/32, features 4 SKIP, exit 0, and
`bash test/run.sh --sabotage` still reports "sabotage check ok".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Agent-Id: agent-4966d0e6-7f4d-4b37-be3d-0648ed56cb8a
2026-10-17 23:27:02 +02:00
Tobias KaupatandClaude Opus 5 9f1c80951d ci: use the container-structure-test image instead of a pinned download
The pinned release URL returned 404. test/run.sh already falls back to the
official tool image when the binary is absent, so CI and local runs now take
the same path.

Also pin *.txt to LF and make the required-features lookup tolerate CRLF, so
the feature gate works on a Windows checkout too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Agent-Id: agent-7034f75b-1ddc-4aa1-a4ea-3a54b340e8d9
2026-10-17 22:50:15 +02:00
Tobias KaupatandClaude Opus 5 10b197f1f5 test: add container test suites and run them in CI
The repository had no tests: CI only built the image, and the old
container-structure-test setup was parked as config-broken.yml /
docker-compose.test.broken.yml. This adds suites that actually run the image.

- test/compat.sh: backup, restore, forget, check, hooks, failure handling and
  timezone behaviour against the default configuration. These describe what
  users depend on today, so a change that turns them red is a breaking change.
- test/features.sh: optional features, each guarded by a detection check
  against the built image. Absent features are reported as SKIP, so open pull
  requests do not turn master red, and their feature tests start running by
  themselves once the pull request is rebased. Covers #109 (RESTIC_STREAM),
  #99 (docker cli, bash) and #84 (msmtp).
- test/required-features.txt: once a feature is merged its gate is listed here
  and a missing feature becomes a failure instead of a skip.
- test/structure.yml: revived image layout checks, falls back to the official
  container-structure-test image when the tool is not installed.
- test/run.sh --sabotage: breaks the backup call on a throwaway copy of the
  tree and expects the suite to fail, so the tests cannot be watered down into
  always passing. CI runs this as its own step.
- .github/workflows/test.yml: shellcheck plus all suites on every pull request.

Also adds .gitattributes pinning shell scripts, the Dockerfile and YAML to LF.
With a Windows checkout (core.autocrlf=true) the scripts were checked out with
CRLF, and the resulting image failed to start with
"exec /entry.sh: no such file or directory".

No runtime file is touched, the image itself is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Agent-Id: agent-7034f75b-1ddc-4aa1-a4ea-3a54b340e8d9
2026-10-17 22:47:26 +02:00