#!/usr/bin/env bash # # Shell-level integration test for next-version-code.sh (fdroid-repo-ci#6) -- # the actual CLI entry point, run the same way sign-apk.sh/fdroid-update.sh # are tested: through with-nixpkgs.sh, against the pinned interpreter, # exercising real argv/exit-code/stdout behaviour rather than importing a # function. The arithmetic itself, and every clamp case, is covered offline # and without nix by test_next_version_code.py; this file only has to prove # the wrapper script wires that up correctly, plus the two things only the # wrapper (not the Python module directly) can be asked about: a local file # path as the index source, and an unreachable URL as one. # # bash test_next_version_code.sh set -euo pipefail here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) source "$here/test_lib.sh" work=$(mktemp -d) trap 'rm -rf "$work"' EXIT APP_ID="de.example.app" # "now" is pinned for the whole script, the same reasoning # test_next_version_code.py uses NEXT_VERSION_CODE_NOW for: every expected # result below is then a fixed number, not one that depends on the real # wall clock (and, unlike the Python suite, this file drives the real CLI # through with-nixpkgs.sh, so it is also slower -- one more reason not to # let it depend on when it happens to run). export NEXT_VERSION_CODE_NOW="2026-06-01T00:00:00+00:00" # The committer timestamp for most cases: the *same* instant as "now" above, # as Unix seconds (`git log -1 --format=%ct`'s own unit) -- comfortably # inside tolerance, so a normal invocation is not accidentally # forward-clamped. Verified equal to NEXT_VERSION_CODE_NOW by construction: # both come from 2026-06-01T00:00:00Z. COMMITTER_TS=1780272000 echo "--- wrong argument count is refused ---" assert_failure "no arguments" bash "$here/next-version-code.sh" assert_failure "one argument" bash "$here/next-version-code.sh" "$work/index.json" assert_failure "two arguments" bash "$here/next-version-code.sh" "$work/index.json" "$APP_ID" echo "--- a local file path works end to end, through the real CLI ---" cat > "$work/index.json" < "$work/other-app.json" <<'JSON' {"packages": {"some.other.app": {"versions": {"h": {"manifest": {"versionCode": 5}}}}}} JSON out2=$(bash "$here/next-version-code.sh" "$work/other-app.json" "$APP_ID" "$COMMITTER_TS") if [[ "$out2" =~ ^[0-9]+$ ]]; then pass "an application id absent from the index is not an error" else fail "an application id absent from the index is not an error (got '$out2')" fi echo "--- a commit dated far in the future is clamped through the real CLI, and warns ---" # "now" is still pinned at 2026-06-01T00:00:00Z (exported above), so a # committer date one century later (2126-01-01T00:00:00Z, hardcoded rather # than computed with `date`, whose -d/-j flags differ between GNU and BSD) # is unambiguously beyond tolerance. future_ts=4922899200 out6=$(bash "$here/next-version-code.sh" "$work/other-app.json" "$APP_ID" "$future_ts" \ 2>/tmp/nvc_stderr4.$$) || true err6=$(cat /tmp/nvc_stderr4.$$); rm -f /tmp/nvc_stderr4.$$ if [[ "$out6" =~ ^[0-9]+$ ]]; then pass "a far-future commit date still exits 0 (clamp, not rejection)" else fail "a far-future commit date still exits 0 (clamp, not rejection) (got '$out6')" fi assert_contains "a far-future commit date warns on stderr" "$err6" "warning" echo "--- a missing local file fails loudly, prints nothing on stdout ---" out3=$(bash "$here/next-version-code.sh" "$work/does-not-exist.json" "$APP_ID" "$COMMITTER_TS" 2>/tmp/nvc_stderr.$$) && rc=0 || rc=$? err3=$(cat /tmp/nvc_stderr.$$); rm -f /tmp/nvc_stderr.$$ if [ "${rc:-0}" -ne 0 ]; then pass "a missing index file exits non-zero"; else fail "a missing index file exits non-zero (got 0)" fi if [ -z "$out3" ]; then pass "a missing index file prints nothing on stdout"; else fail "a missing index file prints nothing on stdout (got '$out3')" fi assert_contains "the error explains the index could not be read" "$err3" "could not read the index" echo "--- an unreachable URL fails loudly too, the same way, through the real network path ---" # port 1 is a reserved, unassigned TCP port -- nothing listens there, so # this never leaves the loopback interface and needs no real network access, # the same trick test_publish.sh uses. out4=$(bash "$here/next-version-code.sh" "http://127.0.0.1:1/index-v2.json" "$APP_ID" "$COMMITTER_TS" 2>/tmp/nvc_stderr2.$$) && rc4=0 || rc4=$? err4=$(cat /tmp/nvc_stderr2.$$); rm -f /tmp/nvc_stderr2.$$ if [ "${rc4:-0}" -ne 0 ]; then pass "an unreachable index URL exits non-zero"; else fail "an unreachable index URL exits non-zero (got 0)" fi if [ -z "$out4" ]; then pass "an unreachable index URL prints nothing on stdout"; else fail "an unreachable index URL prints nothing on stdout (got '$out4')" fi assert_contains "the error explains the index could not be read (URL case)" "$err4" "could not read the index" echo "--- malformed JSON fails loudly ---" echo "{not valid json" > "$work/malformed.json" out5=$(bash "$here/next-version-code.sh" "$work/malformed.json" "$APP_ID" "$COMMITTER_TS" 2>/tmp/nvc_stderr3.$$) && rc5=0 || rc5=$? err5=$(cat /tmp/nvc_stderr3.$$); rm -f /tmp/nvc_stderr3.$$ if [ "${rc5:-0}" -ne 0 ]; then pass "malformed JSON exits non-zero"; else fail "malformed JSON exits non-zero (got 0)" fi assert_contains "the error explains the index could not be read (malformed JSON)" "$err5" "could not read the index" echo "--- a non-numeric committer timestamp is refused, not silently coerced ---" assert_failure "non-numeric committer timestamp" \ bash "$here/next-version-code.sh" "$work/index.json" "$APP_ID" "not-a-timestamp" report_and_exit