From e728ed013e15f76b96c10e0228c195fed184696d Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Fri, 4 Oct 2013 20:58:07 -0500 Subject: [PATCH] Be more careful when testing that repeated saves can produce the same tree. Previously, test.sh would run multiple saves with no intervening modifications, and check to see that the top-level "save -t" hash didn't change, but with the addition of metadata this may fail on some platforms where the test process itself (the save runs, etc.) affects atime values. That's because save is pulling the metadata for unindexed parent directories directly from the filesystem. And note that atime is only special here because the test itself may incidentally alter it -- we would see the same problem if any of the other metdata for one of the unindexed parent directories changed during the test run (i.e. mtime, uid, gid, ...). To fix this, move the relevant test code from test.sh to test-redundant-saves.sh, and use a newly added subdir-hash tool so that we can compare the hashes of the roots of the indexed subtrees instead of the top-level "save -t" hashes, ignoring the unindexed parents entirely. Thanks to Robert Edmonds for running rc3 through the Debian buildds which lead to the kFreeBSD test failure that demonstrated the problem. Signed-off-by: Rob Browning --- Makefile | 1 + t/subtree-hash | 31 +++++++++++++++++++++ t/test-redundant-saves.sh | 57 +++++++++++++++++++++++++++++++++++++++ t/test.sh | 13 --------- 4 files changed, 89 insertions(+), 13 deletions(-) create mode 100755 t/subtree-hash create mode 100755 t/test-redundant-saves.sh diff --git a/Makefile b/Makefile index d8686ff..c0310b0 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,7 @@ runtests-cmdline: all t/test-restore-single-file.sh t/test-rm-between-index-and-save.sh t/test-command-without-init-fails.sh + t/test-redundant-saves.sh t/test.sh stupid: diff --git a/t/subtree-hash b/t/subtree-hash new file mode 100755 index 0000000..45e727c --- /dev/null +++ b/t/subtree-hash @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -eo pipefail + +# Usage: subtree-hash ROOT_HASH [SUBDIR ...] + +subtree_hash() +{ + root_hash="$1" + if test "$#" -eq 1; then + echo $root_hash + else + subdir="$2" + subtree_info="$(git ls-tree "$root_hash" | grep -E " $subdir\$")" || true + if test "$(echo "$subtree_info" | wc -l)" -ne 1; then + echo "Found more than one matching line in subtree $root_hash" 1>&2 + return 1 + fi + + subtree_hash="$(echo "$subtree_info" | cut -d' ' -f 3 | cut -d$'\t' -f 1)" || true + if test -z "$subtree_hash"; then + echo "Unable to find subtree hash in git output: $subtree_info" 1>&2 + return 1 + fi + + shift 2 + subtree_hash "$subtree_hash" "$@" + fi +} + +subtree_hash "$@" diff --git a/t/test-redundant-saves.sh b/t/test-redundant-saves.sh new file mode 100755 index 0000000..5bf00b1 --- /dev/null +++ b/t/test-redundant-saves.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Test that running save more than once with no other changes produces +# the exact same tree. + +# Note: we can't compare the top-level hash (i.e. the output of "save +# -t" because that currently pulls the metadata for unindexed parent +# directories directly from the filesystem, and the relevant atimes +# may change between runs. So instead we extract the roots of the +# indexed trees for comparison via t/subtree-hash. + +. ./wvtest-bup.sh + +set -eo pipefail + +WVSTART 'all' + +top="$(pwd)" +tmpdir="$(wvmktempdir)" +export BUP_DIR="$tmpdir/bup" +export GIT_DIR="$BUP_DIR" + +bup() { "$top/bup" "$@"; } + +mkdir -p "$tmpdir/src" +mkdir -p "$tmpdir/src/d" +mkdir -p "$tmpdir/src/d/e" +touch "$tmpdir/src/"{f,b,a,d} +touch "$tmpdir/src/d/z" + +WVPASS bup init +WVPASS bup index -u "$tmpdir/src" + +declare -a indexed_top +IFS=/ +indexed_top="${tmpdir##/}" +indexed_top=(${indexed_top%%/}) +unset IFS + +tree1=$(bup save -t "$tmpdir/src") || WVFAIL +indexed_tree1="$(t/subtree-hash "$tree1" "${indexed_top[@]}" src)" + +WVPASSEQ "$(cd "$tmpdir/src" && bup index -m)" "" + +tree2=$(bup save -t "$tmpdir/src") || WVFAIL +indexed_tree2="$(t/subtree-hash "$tree2" "${indexed_top[@]}" src)" + +WVPASSEQ "$indexed_tree1" "$indexed_tree2" + +WVPASSEQ "$(bup index -s / | grep ^D)" "" + +tree3=$(bup save -t /) || WVFAIL +indexed_tree3="$(t/subtree-hash "$tree3" "${indexed_top[@]}")" + +WVPASSEQ "$indexed_tree3" "$indexed_tree3" + +rm -rf "$tmpdir" diff --git a/t/test.sh b/t/test.sh index 3656689..8352845 100755 --- a/t/test.sh +++ b/t/test.sh @@ -123,19 +123,6 @@ WVPASSEQ "$(cd $D && bup index -m)" \ f a ./" -tree1=$(bup save -t $D) || WVFAIL -WVPASSEQ "$(cd $D && bup index -m)" "" -tree2=$(bup save -t $D) || WVFAIL -if ! [[ $(uname) =~ CYGWIN ]]; then - # On Cygwin, the access time may change. - WVPASSEQ "$tree1" "$tree2" -fi -WVPASSEQ "$(bup index -s / | grep ^D)" "" -tree3=$(bup save -t /) || WVFAIL -if ! [[ $(uname) =~ CYGWIN ]]; then - # On Cygwin, the access time may change. - WVPASSEQ "$tree1" "$tree3" -fi WVPASS bup save -r :$BUP_DIR -n r-test $D WVFAIL bup save -r :$BUP_DIR/fake/path -n r-test $D WVFAIL bup save -r :$BUP_DIR -n r-test $D/fake/path -- 2.39.2