#!/usr/bin/env bash
. ./wvtest-bup.sh || exit $?
. ./test/lib/btl.sh || exit $?

set -o pipefail

top="$(WVPASS pwd)" || exit $?
tmpdir="$(WVPASS wvmktempdir)" || exit $?

bup() { "$top/bup" "$@"; }

WVPASS "$top/dev/sync-tree" "$top/test/sampledata/" "$tmpdir/src/"

export BUP_DIR="$tmpdir/bup"
export GIT_DIR="$tmpdir/bup"

WVPASS bup init
WVPASS cd "$tmpdir"

WVSTART "fsck"

WVPASS bup index src
WVPASS bup save -n fsck-test src/b2
WVPASS bup save -n fsck-test src/var/cmd
WVPASS bup save -n fsck-test src/var/doc
WVPASS bup save -n fsck-test src/var/lib
WVPASS bup save -n fsck-test src/y
WVPASS bup fsck
WVPASS bup fsck "$BUP_DIR"/objects/pack/pack-*.pack
WVPASS bup fsck --quick

if ! bup fsck --par2-ok; then
    have_par2=''
    WVSKIP "tests requiring par2"
    WVEXPRC 2 bup fsck -g
    WVEXPRC 2 bup fsck -r
else
    have_par2=1
    WVPASS bup fsck -g
    WVPASS bup fsck -r
fi

WVSTART "fsck (index repairs)"
WVPASS chmod u+w "$BUP_DIR"/objects/pack/*.idx
WVPASS bup damage "$BUP_DIR"/objects/pack/*.idx -n10 -s1 -S0
WVFAIL bup fsck --quick
WVFAIL bup fsck --quick --disable-par2
if test "$have_par2"; then
    WVEXPRC 1 bup fsck -r
    WVPASS chmod u+w "$BUP_DIR"/objects/pack/*.idx
    WVPASS bup damage "$BUP_DIR"/objects/pack/*.idx -n10 -s1 -S0
    bup fsck -r --disable-par2
    WVPASSEQ 2 $?
fi

WVSTART "fsck (pack repairs)"
WVPASS bup damage "$BUP_DIR"/objects/pack/*.pack -n10 -s1 -S0
WVFAIL bup fsck --quick
WVFAIL bup fsck --quick --disable-par2

WVPASS chmod u+w "$BUP_DIR"/objects/pack/*.idx
WVPASS bup damage "$BUP_DIR"/objects/pack/*.idx -n10 -s1 -S0
WVFAIL bup fsck --quick -j4
WVPASS bup damage "$BUP_DIR"/objects/pack/*.pack -n10 -s1024 --percent 0.4 -S0
WVFAIL bup fsck --quick

if ! test "$have_par2"; then
    WVEXPRC '[^01]' bup fsck --quick -rvv -j9
    WVPASS cd "$top"
    WVPASS rm -rf "$tmpdir"
    exit 0
fi

bup fsck --quick -rvv -j9
WVPASSEQ 1 $?

git_idxs=("$BUP_DIR"/objects/pack/pack-*.idx)
some_idx="${git_idxs[0]}"
some_idx="${some_idx%.idx}.par2"

vols=("$BUP_DIR"/objects/pack/pack-*.vol*.par2)
some_vol="${vols[0]}"

WVPASS cp -p "$some_idx" some-pack.par2
WVPASS cp -p "$some_vol" some-pack.vol.par2

WVSTART 'fsck rejects empty par2 index files'
WVPASS echo -n > "$some_idx"
WVFAIL bup fsck -v
WVPASS test -e "$some_idx" -a ! -s "$some_idx"
WVFAIL bup fsck -vr
WVPASS test -e "$some_idx" -a ! -s "$some_idx"
WVFAIL bup fsck -vg
WVPASS test -e "$some_idx" -a ! -s "$some_idx"
WVPASS cp -p some-pack.par2 "$some_idx"

WVSTART 'fsck rejects empty par2 vol files'
WVPASS echo -n > "$some_vol"
WVFAIL bup fsck -v
WVPASS test -e "$some_vol" -a ! -s "$some_vol"
WVFAIL bup fsck -vr
WVPASS test -e "$some_vol" -a ! -s "$some_vol"
WVFAIL bup fsck -vg
WVPASS test -e "$some_vol" -a ! -s "$some_vol"
WVPASS cp -p some-pack.vol.par2 "$some_vol"

# This must do "too much" damage.  Currently par2 is invoked with
# -c200, which should allow up to 200 damaged "blocks", but since
# we don't specify the block size, it's dynamically computed.
# Even if we did specify a size, the actual size appears to be
# affected by the input file sizes, and the specific behavior
# doesn't appear to be documented/promised -- see par2
# comandline.cpp.  Also worth noting that bup damage's output is
# currently probabilistic, so it might not actually damage any
# given byte.  For now, just try to overdo it -- randomly change
# (or not 1/256th of the time) 600 evenly spaced bytes in each
# pack file.
WVPASS bup damage "$BUP_DIR"/objects/pack/*.pack -n600 -s1 --equal -S0
WVFAIL bup fsck

WVEXPRC '[!01]' bup fsck -rvv   # too many errors to be repairable
WVEXPRC '[!01]' bup fsck -r   # too many errors to be repairable


WVSTART "fsck detects orphaned pack-related files"
WVPASS rm -rf "$BUP_DIR"
WVPASS bup init
WVPASS bup index src
WVPASS bup save -n lib --strip "$(pwd)" src/var/lib
WVPASS bup save -n doc --strip "$(pwd)" src/var/doc
packs=($(cd bup/objects/pack/ && ls -rt *.pack))
doc_pack="${packs[1]}"
pack_stem="${doc_pack%.pack}"
WVPASS bup rm --unsafe doc
WVPASS test -e bup/objects/pack/"$doc_pack"
WVPASS bup gc --unsafe
WVPASS test ! -e bup/objects/pack/"$doc_pack"
WVPASS touch bup/objects/pack/"$pack_stem"
WVPASS touch bup/objects/pack/"$pack_stem."
WVPASS touch bup/objects/pack/"$pack_stem.lingering"
WVPASS err-to log bup fsck
WVPASS grep -E '^No pack file for ' log | WVPASS sort > lingering
WVPASSEQ "$(< lingering)" \
"No pack file for $pack_stem
No pack file for $pack_stem.
No pack file for $pack_stem.lingering"


WVPASS cd "$top"
WVPASS rm -rf "$tmpdir"
