Skip to content
quarry Artifact [0a2b986cd4]
Login

Artifact [0a2b986cd4]

Artifact 0a2b986cd466caac9c5c19a9eb69bc56adb5aba0dd7077d60f4066987a2e3092:


#!/bin/sh
# Prove the latest backup restores: open its store with zit and its
# database with sqlite, in a scratch directory, without touching the
# live forge. Run after any change to backup.sh, and on a schedule.
set -eu
src=/srv/backups/latest
# On disk beside the backups: /tmp is a RAM disk smaller than the stores.
work=$(mktemp -d /srv/backups/.restore-test.XXXXXX); trap 'rm -rf "$work"' EXIT
( cd "$src" && sha256sum -c SHA256SUMS >/dev/null ) || { echo "restore-test: checksum mismatch in $src" >&2; exit 1; }
tar -C "$work" -xzf "$src/stores.tar.gz"
tip=$(cd "$work" && mkdir co && cd co && /srv/quarry/bin/zit open trunk --store="$work/quarry/.zit" >/dev/null && /srv/quarry/bin/zit status | awk '/^checkout:/ {print substr($2,1,12)}')
[ -n "$tip" ] || { echo "restore-test: the restored store would not open" >&2; exit 1; }
# A Git mirror restores with its import map: its imported head reads, or
# an import the backup caught interrupted finishes without a source.
for map in "$work"/*/.zit-import-map; do
  [ -e "$map" ] || continue
  repo=$(dirname "$map")
  if [ -e "$repo/.zit-import-pending" ]; then
    /srv/quarry/bin/zit import-git --recover "$repo" >/dev/null 2>&1 || { echo "restore-test: $(basename "$repo"): interrupted import does not recover" >&2; exit 1; }
  fi
  # A mirror somebody committed on has no imported head live either; the
  # copy only has to read as well as the repository it was taken from.
  /srv/quarry/bin/zit info --imported-head -F json -R "$repo" >/dev/null 2>&1 ||
    ! /srv/quarry/bin/zit info --imported-head -F json -R "/srv/quarry/repos/$(basename "$repo")" >/dev/null 2>&1 ||
    { echo "restore-test: $(basename "$repo"): restored Git mirror has no imported head" >&2; exit 1; }
done
accts=$(sqlite3 "$src/oltp.db" "select count(*) from account")
echo "restore-test: store opens at trunk $tip, oltp has $accts accounts — restorable"