#!/usr/bin/env bash set -euo pipefail repository_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) workspace_venv=$(cd "$repository_root/../.venv" && pwd) test_tmp=$(mktemp -d) export ANSIBLE_COLLECTIONS_PATH="$repository_root/.ansible/collections" export ANSIBLE_ROLES_PATH="$(dirname "$repository_root")" playbook="$workspace_venv/bin/ansible-playbook" inventory="$repository_root/tests/inventory" converge="$repository_root/tests/converge.yml" run_converge() { "$playbook" -i "$inventory" "$converge" "$@" } restore_default() { run_converge >/dev/null 2>&1 } cleanup() { exit_status=$? restore_default || true sudo rm -rf -- "$test_tmp" exit "$exit_status" } trap cleanup EXIT require_clean_recap() { recap_file=$1 grep -Eq 'changed=0 .*failed=0' "$recap_file" } require_changed_recap() { recap_file=$1 grep -Eq 'changed=[1-9][0-9]* .*failed=0' "$recap_file" } binary_digest() { sha256sum /usr/local/bin/seriatim | awk '{print $1}' } state_digest() { sudo sha256sum /usr/local/src/seriatim.ansible-build-state/* | sha256sum | awk '{print $1}' } cd "$repository_root" "$workspace_venv/bin/ansible-galaxy" collection install \ -p .ansible/collections -r collections/requirements.yml "$playbook" -i "$inventory" "$converge" --syntax-check "$workspace_venv/bin/ansible-lint" . run_converge "$playbook" -i "$inventory" tests/verify.yml run_converge | tee "$test_tmp/default-repeat.log" require_clean_recap "$test_tmp/default-repeat.log" printf '%s\n' 'corrupt build inputs' | sudo tee /usr/local/src/seriatim.ansible-build-state/build-inputs.json >/dev/null run_converge | tee "$test_tmp/build-input-repair.log" require_changed_recap "$test_tmp/build-input-repair.log" "$playbook" -i "$inventory" tests/verify.yml run_converge | tee "$test_tmp/build-input-repair-repeat.log" require_clean_recap "$test_tmp/build-input-repair-repeat.log" sudo chown "$(id -u):$(id -g)" /usr/local/bin/seriatim sudo chmod 0777 /usr/local/bin/seriatim sudo chown "$(id -u):$(id -g)" /usr/local/src/seriatim.ansible-build-state sudo chmod 0700 /usr/local/src/seriatim.ansible-build-state sudo chown "$(id -u):$(id -g)" /usr/local/src/seriatim.ansible-build-state/* sudo chmod 0600 /usr/local/src/seriatim.ansible-build-state/* run_converge | tee "$test_tmp/metadata-repair.log" require_changed_recap "$test_tmp/metadata-repair.log" "$playbook" -i "$inventory" tests/verify.yml run_converge | tee "$test_tmp/metadata-repair-repeat.log" require_clean_recap "$test_tmp/metadata-repair-repeat.log" custom_binary="$test_tmp/missing-binary-parent/seriatim" custom_state="$test_tmp/custom-build-state" test ! -e "$(dirname "$custom_binary")" run_converge \ -e "seriatim_binary_path=$custom_binary" \ -e "seriatim_build_state_dir=$custom_state" | tee "$test_tmp/custom-path.log" require_changed_recap "$test_tmp/custom-path.log" test "$($custom_binary --version)" = 'seriatim version v1.5.0' test "$(stat -c '%U:%G %a' "$(dirname "$custom_binary")")" = 'root:root 755' run_converge \ -e "seriatim_binary_path=$custom_binary" \ -e "seriatim_build_state_dir=$custom_state" | tee "$test_tmp/custom-path-repeat.log" require_clean_recap "$test_tmp/custom-path-repeat.log" baseline_binary=$(binary_digest) baseline_state=$(state_digest) for scenario in \ '{"test_distribution":"Debian","test_distribution_version":"26.04","test_architecture":"x86_64"}' \ '{"test_distribution":"Ubuntu","test_distribution_version":"24.04","test_architecture":"x86_64"}' \ '{"test_distribution":"Ubuntu","test_distribution_version":"26.04","test_architecture":"riscv64"}' do if "$playbook" -i "$inventory" tests/unsupported.yml -e "$scenario"; then echo "unsupported platform scenario unexpectedly succeeded: $scenario" >&2 exit 1 fi test "$(binary_digest)" = "$baseline_binary" test "$(state_digest)" = "$baseline_state" done sudo touch /usr/local/src/seriatim/ansible-untracked-test sudo sed -i '1s/^/ansible-test-change\n/' /usr/local/src/seriatim/go.mod run_converge "$playbook" -i "$inventory" tests/verify.yml compiler_wrapper="$test_tmp/go-version-wrapper" sed 's|@GO@|/snap/bin/go|' >"$compiler_wrapper" <<'WRAPPER' #!/bin/sh if [ "${1:-}" = version ]; then echo 'go version go1.26.99 linux/amd64' exit 0 fi exec @GO@ "$@" WRAPPER chmod 0755 "$compiler_wrapper" run_converge -e "seriatim_go_binary=$compiler_wrapper" | tee "$test_tmp/compiler-change.log" require_changed_recap "$test_tmp/compiler-change.log" run_converge -e "seriatim_go_binary=$compiler_wrapper" | tee "$test_tmp/compiler-repeat.log" require_clean_recap "$test_tmp/compiler-repeat.log" run_converge | tee "$test_tmp/compiler-restore.log" require_changed_recap "$test_tmp/compiler-restore.log" run_converge | tee "$test_tmp/compiler-restored-repeat.log" require_clean_recap "$test_tmp/compiler-restored-repeat.log" failure_wrapper="$test_tmp/go-failure-wrapper" sed 's|@GO@|/snap/bin/go|' >"$failure_wrapper" <<'WRAPPER' #!/bin/sh if [ "${1:-}" = version ]; then exec @GO@ version fi echo 'deliberate integration-test build failure' >&2 exit 42 WRAPPER chmod 0755 "$failure_wrapper" baseline_binary=$(binary_digest) baseline_state=$(state_digest) if run_converge -e "seriatim_go_binary=$failure_wrapper"; then echo 'deliberate build failure unexpectedly succeeded' >&2 exit 1 fi test "$(binary_digest)" = "$baseline_binary" test "$(state_digest)" = "$baseline_state" test "$(/usr/local/bin/seriatim --version)" = 'seriatim version v1.5.0' run_converge | tee "$test_tmp/final-restore.log" require_clean_recap "$test_tmp/final-restore.log" "$playbook" -i "$inventory" tests/verify.yml trap - EXIT sudo rm -rf -- "$test_tmp"