diff --git a/README.md b/README.md index 3b1b18c..c91a100 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # pyenv.github.io hi there + +## Tests + +Install [Bats](https://github.com/bats-core/bats-core), then run: + +```sh +bats pythons/test/update.bats +``` diff --git a/pythons/test/update.bats b/pythons/test/update.bats new file mode 100644 index 0000000..d4ded4b --- /dev/null +++ b/pythons/test/update.bats @@ -0,0 +1,122 @@ +#!/usr/bin/env bats + +setup() { + site="$BATS_TEST_TMPDIR/site" + mkdir -p "$site/binaries" + cp "$BATS_TEST_DIRNAME/../update.sh" "$BATS_TEST_DIRNAME/../index.html" "$site" + cd "$site" || return +} + +write_meta() { + local name="$1" + local archive="$2" + cat > "binaries/$name.meta" < "binaries/$archive" + printf definition > "binaries/$name" + write_meta "$name" "$archive" +} + +write_archives() { + write_binary 3.14.0-ubuntu-24.04-x86_64 \ + 3.14.0-ubuntu-24.04-x86_64.tar.xz archive-data + write_binary 3.13.0-ubuntu-24.04-x86_64 \ + 3.13.0-ubuntu-24.04-x86_64.tar.gz gzip-archive-data +} + +assert_success() { + [ "$status" -eq 0 ] +} + +assert_failure() { + [ "$status" -ne 0 ] +} + +@test "indexes xz and gzip prebuilt archives" { + write_archives + + run bash ./update.sh + assert_success + + xz_sha=8a6111c3ca752ed6d5f8e8a6daa3ba4b8c3b0bf55f00a87ac2b285024ef87e5f + [ binaries/3.14.0-ubuntu-24.04-x86_64.tar.xz -ef "$xz_sha" ] + xz_entry='
  • 3.14.0-ubuntu-24.04-x86_64.tar.xz (definition)
  • ' + grep -Fqx "$xz_entry" index.html + + gzip_sha=c809857f5fa564e1a2fdb3618161114bfb9a9c624ade6b580f6d79df0adfcc26 + [ binaries/3.13.0-ubuntu-24.04-x86_64.tar.gz -ef "$gzip_sha" ] + gzip_entry='
  • 3.13.0-ubuntu-24.04-x86_64.tar.gz (definition)
  • ' + grep -Fqx "$gzip_entry" index.html +} + +@test "repeated updates do not duplicate entries" { + write_archives + bash ./update.sh + cp index.html index.before + + run bash ./update.sh + assert_success + + cmp -s index.before index.html + [ "$(grep -Fc '3.14.0-ubuntu-24.04-x86_64.tar.xz' index.html)" -eq 1 ] + [ "$(grep -Fc '3.13.0-ubuntu-24.04-x86_64.tar.gz' index.html)" -eq 1 ] +} + +@test "rejects unsafe archive names before updating files" { + write_archives + printf 'archive=bad\narchive=name.tar.gz\n' > binaries/z-invalid.meta + printf definition > binaries/z-invalid + mkdir source + printf source-data > source/example.tar.gz + printf '
  • example.tar.gz
  • \n' >> index.html + cp -R . "$BATS_TEST_TMPDIR/site.before" + + run bash ./update.sh + assert_failure + + [[ "$output" == *"Invalid archive name in binaries/z-invalid.meta"* ]] + diff -r "$BATS_TEST_TMPDIR/site.before" . +} + +@test "uses a safe archive name from metadata" { + write_binary custom-definition python-build.tar.xz archive-data + + run bash ./update.sh + assert_success + + entry='
  • python-build.tar.xz (definition)
  • ' + grep -Fqx "$entry" index.html +} + +@test "rejects a missing definition" { + write_binary 3.14.0-ubuntu-24.04-x86_64 \ + 3.14.0-ubuntu-24.04-x86_64.tar.xz archive-data + rm binaries/3.14.0-ubuntu-24.04-x86_64 + + run bash ./update.sh + assert_failure +} + +@test "rejects a missing archive" { + write_binary 3.14.0-ubuntu-24.04-x86_64 \ + 3.14.0-ubuntu-24.04-x86_64.tar.xz archive-data + rm binaries/3.14.0-ubuntu-24.04-x86_64.tar.xz + + run bash ./update.sh + assert_failure +} diff --git a/pythons/test/update.sh b/pythons/test/update.sh deleted file mode 100755 index 08fe0df..0000000 --- a/pythons/test/update.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "${BASH_SOURCE%/*}/.." - -fail() { - echo "$1" >&2 - exit 1 -} - -write_meta() { - cat > binaries/3.14.0-ubuntu-24.04-x86_64.meta < "$tmpdir/binaries/3.14.0-ubuntu-24.04-x86_64.tar.gz" -printf definition > "$tmpdir/binaries/3.14.0-ubuntu-24.04-x86_64" - -cd "$tmpdir" -write_meta 3.14.0-ubuntu-24.04-x86_64.tar.gz -bash ./update.sh >/dev/null 2>&1 || fail "update failed" - -sha=8a6111c3ca752ed6d5f8e8a6daa3ba4b8c3b0bf55f00a87ac2b285024ef87e5f -[ "binaries/3.14.0-ubuntu-24.04-x86_64.tar.gz" -ef "$sha" ] || - fail "checksum path is not a hardlink to the archive" - -entry='
  • 3.14.0-ubuntu-24.04-x86_64.tar.gz (definition)
  • ' -grep -Fqx "$entry" index.html || fail "prebuilt archive is missing from index.html" - -cp index.html index.before -bash ./update.sh >/dev/null 2>&1 || fail "second update failed" -cmp -s index.before index.html || fail "second update changed index.html" -[ "$(grep -Fxc "$entry" index.html)" -eq 1 ] || fail "prebuilt archive is listed more than once" - -bad_name=$'bad\nname' -printf 'archive=bad\narchive=name.tar.gz\n' > "binaries/$bad_name.meta" -printf archive-data > "binaries/$bad_name.tar.gz" -printf definition > "binaries/$bad_name" -rm "$sha" -if output="$(bash ./update.sh 2>&1)"; then - fail "update accepted a control character in an archive name" -fi -case "$output" in -*"Invalid archive name in binaries/"*) ;; -*) fail "update did not reject the invalid archive name during validation" ;; -esac -[ ! -e "$sha" ] || fail "update created a checksum link before name validation completed" -rm "binaries/$bad_name.meta" "binaries/$bad_name.tar.gz" "binaries/$bad_name" - -mkdir source -printf source-data > source/example.tar.gz -printf '
  • example.tar.gz
  • \n' >> index.html -cp index.html index.before -cp binaries/3.14.0-ubuntu-24.04-x86_64.meta binaries/z-invalid.meta -sed -i 's/^archive=.*/archive=invalid.tar.gz/' binaries/z-invalid.meta -if bash ./update.sh >/dev/null 2>&1; then - fail "update accepted invalid metadata" -fi -[ ! -e "$sha" ] || fail "update created a binary checksum link before validation completed" -source_sha=6bb69d845f4a714ca982e2903d2c03fabeb2448b67185bca413d3efddea9397c -[ ! -e "$source_sha" ] || fail "update created a source checksum link before validation completed" -cmp -s index.before index.html || fail "update changed index.html before validation completed" -rm -rf source binaries/z-invalid.meta - -write_meta ../outside.tar.gz -printf outside > outside.tar.gz -if bash ./update.sh >/dev/null 2>&1; then - fail "update accepted an archive outside binaries" -fi - -write_meta 3.14.0-ubuntu-24.04-x86_64.tar.gz -rm binaries/3.14.0-ubuntu-24.04-x86_64 -if bash ./update.sh >/dev/null 2>&1; then - fail "update accepted a missing definition" -fi - -printf definition > binaries/3.14.0-ubuntu-24.04-x86_64 -rm binaries/3.14.0-ubuntu-24.04-x86_64.tar.gz -if bash ./update.sh >/dev/null 2>&1; then - fail "update accepted a missing archive" -fi - -echo "ok" diff --git a/pythons/update.sh b/pythons/update.sh index bfc49e3..3968883 100755 --- a/pythons/update.sh +++ b/pythons/update.sh @@ -67,10 +67,6 @@ for meta in binaries/*.meta; do exit 1 ;; esac - if [ "$archive" != "$name.tar.gz" ]; then - echo "Invalid archive in $meta" >&2 - exit 1 - fi if [ ! -f "binaries/$archive" ] || [ ! -f "binaries/$name" ]; then echo "Missing archive or definition for $name" >&2 exit 1