#!/usr/bin/env bash # # Tests for publish.sh -- the one script in this repo that needs real # network to do its actual job (fdroid-repo-ci#1), so its happy path against # a genuine bucket is out of scope here. What this asserts instead: # # * argument/credential validation, offline; # * `--dry-run` builds the exact command a real run would use, offline; # * a real invocation against a closed local port fails on the network call # itself, not on argument parsing -- proving the command it built is # well-formed, without needing a real bucket or reaching beyond loopback. set -euo pipefail here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # Captured BEFORE the fake credentials below are exported. Those fakes are # deliberate -- they keep the offline tests from ever reaching a real service # -- but they also overwrite the real ones for the rest of this file, so the # live round trip at the bottom has to hold on to the originals here or it # would authenticate as AKIAFAKETESTKEY and fail every time. A live test that # always fails gets disabled, which is worse than not having one. LIVE_KEY_ID="${AWS_ACCESS_KEY_ID:-}" LIVE_SECRET="${AWS_SECRET_ACCESS_KEY:-}" LIVE_REGION="${AWS_DEFAULT_REGION:-}" source "$here/test_lib.sh" work=$(mktemp -d) trap 'rm -rf "$work"' EXIT mkdir -p "$work/repo" echo '{}' > "$work/repo/index-v2.json" echo "--- missing credentials are refused, not sent as empty ---" assert_failure "publish.sh refuses with no AWS_ACCESS_KEY_ID" \ env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY \ bash "$here/publish.sh" "$work/repo" mybucket https://s3.example.invalid export AWS_ACCESS_KEY_ID=AKIAFAKETESTKEY export AWS_SECRET_ACCESS_KEY=fake-secret-not-real echo "--- missing local directory is refused ---" assert_failure "publish.sh refuses a non-existent local directory" \ bash "$here/publish.sh" "$work/does-not-exist" mybucket https://s3.example.invalid echo "--- --dry-run builds the right command, touches no network ---" out=$(bash "$here/publish.sh" --dry-run "$work/repo" mybucket https://s3.example.invalid myprefix) assert_contains "dry-run names the destination bucket and prefix" "$out" "s3://mybucket/myprefix" assert_contains "dry-run names the endpoint" "$out" "--endpoint-url https://s3.example.invalid" assert_contains "dry-run goes through with-nixpkgs.sh, same as every other script" "$out" "with-nixpkgs.sh" if echo "$out" | grep -q -- --delete; then fail "dry-run does not silently add --delete (it did!)" else pass "dry-run does not silently add --delete" fi echo "--- --dry-run with no prefix omits the trailing slash entirely ---" out_noprefix=$(bash "$here/publish.sh" --dry-run "$work/repo" mybucket https://s3.example.invalid) assert_contains "no-prefix dry-run targets the bucket root" "$out_noprefix" "s3://mybucket " echo "--- a real invocation fails on the network call, not on arguments ---" # port 1 is a reserved, unassigned TCP port -- nothing listens there, so this # never leaves the loopback interface and needs no real network access. real_out=$(bash "$here/publish.sh" "$work/repo" mybucket "http://127.0.0.1:1" 2>&1) && rc=0 || rc=$? if [ "${rc:-0}" -ne 0 ]; then pass "publish.sh against a closed port exits non-zero"; else fail "publish.sh against a closed port exits non-zero (got 0)" fi assert_contains "the failure is a connection error, not an argument error" "$real_out" "Could not connect" # --- live round trip, opt-in ------------------------------------------------ # Skipped unless a scratch bucket and credentials are present, so the default # offline run is unchanged. This is the only test here that talks to a real # server, and the only one that could have caught the Garage checksum # rejection (#3): everything above proves the command is well formed, which is # a different claim from a server accepting it. if [ -n "${FDROID_CI_LIVE_BUCKET:-}" ] && [ -n "${FDROID_CI_LIVE_ENDPOINT:-}" ] \ && [ -n "$LIVE_KEY_ID" ] && [ -n "$LIVE_SECRET" ]; then echo "--- a real round trip against a real endpoint ---" export AWS_ACCESS_KEY_ID="$LIVE_KEY_ID" export AWS_SECRET_ACCESS_KEY="$LIVE_SECRET" [ -n "$LIVE_REGION" ] && export AWS_DEFAULT_REGION="$LIVE_REGION" live_dir=$(mktemp -d) stamp="live-$(date -u +%s)-$$" printf 'publish.sh live probe %s\n' "$stamp" > "$live_dir/probe.txt" if bash "$here/publish.sh" "$live_dir" "$FDROID_CI_LIVE_BUCKET" \ "$FDROID_CI_LIVE_ENDPOINT" "$stamp" >/dev/null 2>&1; then pass "publish.sh uploaded to a real bucket" else fail "publish.sh uploaded to a real bucket" fi got=$(bash "$here/with-nixpkgs.sh" awscli2 aws --endpoint-url "$FDROID_CI_LIVE_ENDPOINT" \ s3 cp "s3://$FDROID_CI_LIVE_BUCKET/$stamp/probe.txt" - 2>/dev/null || true) if [ "$got" = "publish.sh live probe $stamp" ]; then pass "the uploaded object reads back byte-identical" else fail "the uploaded object reads back byte-identical" fi bash "$here/with-nixpkgs.sh" awscli2 aws --endpoint-url "$FDROID_CI_LIVE_ENDPOINT" \ s3 rm --recursive "s3://$FDROID_CI_LIVE_BUCKET/$stamp/" >/dev/null 2>&1 || true rm -rf "$live_dir" else skip "live round trip (set FDROID_CI_LIVE_BUCKET, FDROID_CI_LIVE_ENDPOINT and AWS credentials)" fi report_and_exit