#!/bin/sh

set -e
silent="-s"
if [ -z "$maria_path" ]
then
    maria_path="."
fi

# test data is always put in the current directory or a tmp subdirectory of it
tmp="./tmp"

if test '!' -d $tmp
then
  mkdir $tmp
fi

echo "MARIA RECOVERY TESTS"

check_table_is_same()
{
    # Computes checksum of new table and compares to checksum of old table
    # Shows any difference in table's state (info from the index's header)

    $maria_path/maria_chk -dvv $table | grep -v "Creation time:" > $tmp/maria_chk_message.txt 2>&1

    # save the index file (because we want to test idempotency afterwards)
    cp $table.MAI tmp/
    # In the repair below it's good to use -q because it will die on any
    # incorrectness of the data file if UNDO was badly applied.
    # QQ: Remove the following line when we also can recover the index file
    $maria_path/maria_chk -s -rq $table

    $maria_path/maria_chk -s -e $table
    checksum2=`$maria_path/maria_chk -dss $table`
    if test "$checksum" != "$checksum2"
        then
        echo "checksum differs for $table before and after recovery"
        return 1;
    fi

    diff $tmp/maria_chk_message.good.txt $tmp/maria_chk_message.txt > $tmp/maria_chk_diff.txt || true
    if [ -s $tmp/maria_chk_diff.txt ]
        then
        echo "Differences in maria_chk -dvv, recovery not yet perfect !"
        echo "========DIFF START======="
        cat $tmp/maria_chk_diff.txt
        echo "========DIFF END======="
    fi
    mv tmp/$table.MAI .
}

apply_log()
{
    # applies log, can verify if applying did write to log or not

    shouldchangelog=$1
    if [ "$shouldchangelog" != "shouldnotchangelog" ] &&
        [ "$shouldchangelog" != "shouldchangelog" ] &&
        [ "$shouldchangelog" != "dontknow" ]
        then
        echo "bad argument '$shouldchangelog'"
        return 1
    fi
    log_md5=`md5sum maria_log.*`
    echo "applying log"
    $maria_path/maria_read_log -a > $tmp/maria_read_log_$table.txt
    log_md5_2=`md5sum maria_log.*`
    if [ "$log_md5" != "$log_md5_2" ]
        then
        if [ "$shouldchangelog" == "shouldnotchangelog" ]
            then
            echo "maria_read_log should not have modified the log"
            return 1
        fi
        else
        if [ "$shouldchangelog" == "shouldchangelog" ]
            then
            echo "maria_read_log should have modified the log"
            return 1
        fi
    fi
}

# To not flood the screen, we redirect all the commands below to a text file
# and just give a final error if their output is not as expected

(

# this message is to remember about the problem with -b (see @todo below)
echo "!!!!!!!! REMEMBER to FIX this BLOB issue !!!!!!!"

echo "Testing the REDO PHASE ALONE"
# runs a program inserting/deleting rows, then moves the resulting table
# elsewhere; applies the log and checks that the data file is
# identical to the saved original.
# Does not test the index file as we don't have logging for it yet.

set -- "ma_test1 $silent -M -T -c" "ma_test2 $silent -L -K -W -P -M -T -c" "ma_test2 $silent -M -T -c -b65000"
while [ $# != 0 ]
do
  prog=$1
  rm -f maria_log.* maria_log_control
  echo "TEST WITH $prog"
  $maria_path/$prog
  # derive table's name from program's name
  table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' `
  $maria_path/maria_chk -dvv $table | grep -v "Creation time:"> $tmp/maria_chk_message.good.txt 2>&1
  checksum=`$maria_path/maria_chk -dss $table`
  mv $table.MAD $tmp/$table-good.MAD
  mv $table.MAI $tmp/$table-good.MAI
  apply_log "shouldnotchangelog"
  cmp $table.MAD $tmp/$table-good.MAD
  check_table_is_same
  echo "testing idempotency"
  apply_log "shouldnotchangelog"
  cmp $table.MAD $tmp/$table-good.MAD
  check_table_is_same
  shift
done

echo "Testing the REDO AND UNDO PHASE"
# The test programs look like:
# work; commit (time T1); work; exit-without-commit (time T2)
# We first run the test program and let it exit after T1's commit.
# Then we run it again and let it exit at T2. Then we compare
# and expect identity.

for take_checkpoint in "no" "yes"
do
for blobs in "" "-b" # we test table without blobs and then table with blobs
do
  for test_undo in 1 2 3
  do
  # first iteration tests rollback of insert, second tests rollback of delete
  set -- "ma_test1 $silent -M -T -c -N $blobs -H1" "--testflag=1" "--testflag=2 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs -H2" "--testflag=3" "--testflag=4 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs -H2 " "--testflag=2" "--testflag=3 --test-undo=" "ma_test2 $silent -L -K -W -P -M -T -c $blobs -H1" "-t1" "-t2 -u"
  # -N (create NULL fields) is needed because --test-undo adds it anyway
  while [ $# != 0 ]
    do
    prog=$1
    if [ "$take_checkpoint" == "no" ]
        then
        prog=`echo $prog | sed 's/ -H[0-9]//'`
        fi
    commit_run_args=$2
    abort_run_args=$3;
    rm -f maria_log.* maria_log_control
    echo "TEST WITH $prog $commit_run_args (commit at end)"
    $maria_path/$prog $commit_run_args
    # derive table's name from program's name
    table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' `
    $maria_path/maria_chk -dvv $table | grep -v "Creation time:"> $tmp/maria_chk_message.good.txt 2>&1
    checksum=`$maria_path/maria_chk -dss $table`
    mv $table.MAD $tmp/$table-good.MAD
    mv $table.MAI $tmp/$table-good.MAI
    rm maria_log.* maria_log_control
    echo "TEST WITH $prog $abort_run_args$test_undo (additional aborted work)"
    $maria_path/$prog $abort_run_args$test_undo
    cp $table.MAD $tmp/$table.MAD.before_undo
    if [ $test_undo -lt 3 ]
        then
        apply_log "shouldchangelog" # should undo aborted work
        else
        # probably nothing to undo went to log or data file
        apply_log "dontknow"
    fi
    cp $table.MAD $tmp/$table.MAD.after_undo

    # It is impossible to do a "cmp" between .good and .after_undo,
    # because the UNDO phase generated log
    # records whose LSN tagged pages. Another reason is that rolling back
    # INSERT only marks the rows free, does not empty them (optimization), so
    # traces of the INSERT+rollback remain.

    check_table_is_same
    echo "testing idempotency"
    apply_log "shouldnotchangelog"
    cmp $table.MAD $tmp/$table.MAD.after_undo
    check_table_is_same
    echo "testing applying of CLRs to recreate table"
    rm $table.MA?
    apply_log "shouldnotchangelog"
    # the cmp below fails with ma_test1+blobs! @todo RECOVERY BUG why?
    # It is probably serious; REDOs shouldn't place rows in different
    # positions from what the run-time code did. Indeed it may lead to
    # more or less free space...
    # Execution of UNDO re-inserted rows at different positions than
    # originally. This generated REDOs which do not insert at the same
    # positions as the execution of UNDOs, but at the same positions
    # as before the row was originally deleted.
    if [ "$blobs" == "" ]
        then
        cmp $table.MAD $tmp/$table.MAD.after_undo
    fi
    check_table_is_same
    shift 3
  done
  rm -f $table.* $tmp/$table* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt
done
done
done

) 2>&1 > $tmp/ma_test_recovery.output

# also note that maria_chk -dvv shows differences for ma_test2 in UNDO phase,
# this is normal: removing records does not shrink the data/key file,
# does not put back the "analyzed,optimized keys"(etc) index state.
diff $maria_path/ma_test_recovery.expected $tmp/ma_test_recovery.output > /dev/null || diff_failed=1
if [ "$diff_failed" == "1" ]
    then
    echo "UNEXPECTED OUTPUT OF TESTS, FAILED"
    echo "For more info, do diff $maria_path/ma_test_recovery.expected $tmp/ma_test_recovery.output"
    exit 1
    fi
echo "ALL RECOVERY TESTS OK"
# this message is to remember about the problem with -b (see @todo above)
echo "!!!!!!!! BUT REMEMBER to FIX this BLOB issue !!!!!!!"
