X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=test%2Ftest-lib.sh;h=7855609248e72d1961cc22e21192b577a901395b;hp=7684c2e7ca03ed580fb00bab34d44e7157e441ee;hb=59a9c36316293b161528097a73c72d5f5ed58781;hpb=223987bacef4dcc51952084707d1a664765c7c6e diff --git a/test/test-lib.sh b/test/test-lib.sh old mode 100644 new mode 100755 index 7684c2e7..78556092 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (c) 2005 Junio C Hamano # @@ -15,6 +15,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +if [ ${BASH_VERSINFO[0]} -lt 4 ]; then + echo "Error: The notmuch test suite requires a bash version >= 4.0" + echo "due to use of associative arrays within the test suite." + echo "Please try again with a newer bash (or help us fix the" + echo "test suite to be more portable). Thanks." + exit 1 +fi + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in @@ -49,15 +57,6 @@ unset CDPATH unset GREP_OPTIONS -case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in - 1|2|true) - echo "* warning: Some tests will not work if GIT_TRACE" \ - "is set as to trace on STDERR ! *" - echo "* warning: Please set GIT_TRACE to something" \ - "other than 1, 2 or true ! *" - ;; -esac - # Convenience # # A regexp to match 5 and 40 hexdigits @@ -130,21 +129,22 @@ if test -n "$color"; then *) test -n "$quiet" && return;; esac shift - printf "* %s" "$*" + printf " " + printf "$@" tput sgr0 - echo ) } else say_color() { test -z "$1" && test -n "$quiet" && return shift - echo "* $*" + printf " " + printf "$@" } fi error () { - say_color error "error: $*" + say_color error "error: $*\n" GIT_EXIT_OK=t exit 1 } @@ -158,17 +158,13 @@ error "Test script did not set test_description." if test "$help" = "t" then - echo "$test_description" + echo "Tests ${test_description}" exit 0 fi +echo $(basename "$0"): "Testing ${test_description}" + exec 5>&1 -if test "$verbose" = "t" -then - exec 4>&2 3>&1 -else - exec 4>/dev/null 3>/dev/null -fi test_failure=0 test_count=0 @@ -221,10 +217,10 @@ remove_cr () { increment_mtime_amount=0 increment_mtime () { - dir=$1 + dir="$1" increment_mtime_amount=$((increment_mtime_amount + 1)) - touch -d "+${increment_mtime_amount} seconds" $dir + touch -d "+${increment_mtime_amount} seconds" "$dir" } # Generate a new message in the mail directory, with a unique message @@ -243,6 +239,12 @@ increment_mtime () # Generate the message in directory 'directory/of/choice' within # the mail store. The directory will be created if necessary. # +# [filename]=name +# +# Store the message in file 'name'. The default is to store it +# in 'msg-', where is three-digit number of the +# message. +# # [body]=text # # Text to use as the body of the email message @@ -279,10 +281,14 @@ generate_message () local additional_headers gen_msg_cnt=$((gen_msg_cnt + 1)) - gen_msg_name=msg-$(printf "%03d" $gen_msg_cnt) + if [ -z "${template[filename]}" ]; then + gen_msg_name="msg-$(printf "%03d" $gen_msg_cnt)" + else + gen_msg_name=${template[filename]} + fi if [ -z "${template[id]}" ]; then - gen_msg_id="${gen_msg_name}@notmuch-test-suite" + gen_msg_id="${gen_msg_name%:2,*}@notmuch-test-suite" else gen_msg_id="${template[id]}" fi @@ -291,7 +297,7 @@ generate_message () gen_msg_filename="${MAIL_DIR}/$gen_msg_name" else gen_msg_filename="${MAIL_DIR}/${template[dir]}/$gen_msg_name" - mkdir -p $(dirname $gen_msg_filename) + mkdir -p "$(dirname "$gen_msg_filename")" fi if [ -z "${template[body]}" ]; then @@ -311,7 +317,7 @@ generate_message () fi if [ -z "${template[date]}" ]; then - template[date]="Tue, 05 Jan 2001 15:43:57 -0800" + template[date]="Tue, 05 Jan 2001 15:43:57 -0000" fi additional_headers="" @@ -345,8 +351,11 @@ ${additional_headers}" ${additional_headers}" fi + # Note that in the way we're setting it above and using it below, + # `additional_headers' will also serve as the header / body separator + # (empty line in between). -cat <$gen_msg_filename + cat <"$gen_msg_filename" From: ${template[from]} To: ${template[to]} Message-Id: <${gen_msg_id}> @@ -357,50 +366,150 @@ ${template[body]} EOF # Ensure that the mtime of the containing directory is updated - increment_mtime $(dirname ${gen_msg_filename}) + increment_mtime "$(dirname "${gen_msg_filename}")" } -# Generate a new message and add it to the index. +# Generate a new message and add it to the database. # # All of the arguments and return values supported by generate_message # are also supported here, so see that function for details. add_message () { - generate_message "$@" + generate_message "$@" && + notmuch new > /dev/null +} - $NOTMUCH new > /dev/null +# Deliver a message with emacs and add it to the database +# +# Uses emacs to generate and deliver a message to the mail store. +# Accepts arbitrary extra emacs/elisp functions to modify the message +# before sending, which is useful to doing things like attaching files +# to the message and encrypting/signing. +emacs_deliver_message () +{ + local subject="$1" + local body="$2" + shift 2 + # before we can send a message, we have to prepare the FCC maildir + mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp} + ../smtp-dummy sent_message & + smtp_dummy_pid=$! + test_emacs "(setq message-send-mail-function 'message-smtpmail-send-it) (setq smtpmail-smtp-server \"localhost\") (setq smtpmail-smtp-service \"25025\") (notmuch-hello) (notmuch-mua-mail) (message-goto-to) (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\") (message-goto-subject) (insert \"${subject}\") (message-goto-body) (insert \"${body}\") $@ (message-send-and-exit)" >/dev/null 2>&1 + wait ${smtp_dummy_pid} + notmuch new >/dev/null } -tests=0 -test_failures=0 +# Generate a corpus of email and add it to the database. +# +# This corpus is fixed, (it happens to be 50 messages from early in +# the history of the notmuch mailing list), which allows for reliably +# testing commands that need to operate on a not-totally-trivial +# number of messages. +add_email_corpus () +{ + rm -rf ${MAIL_DIR} + if [ -d ../corpus.mail ]; then + cp -a ../corpus.mail ${MAIL_DIR} + else + cp -a ../corpus ${MAIL_DIR} + notmuch new >/dev/null + cp -a ${MAIL_DIR} ../corpus.mail + fi +} -pass_if_equal () +test_begin_subtest () { - output=$1 - expected=$2 + if [ -n "$inside_subtest" ]; then + exec 1>&6 2>&7 # Restore stdout and stderr + error "bug in test script: Missing test_expect_equal in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}" + fi + test_subtest_name="$1" + # Remember stdout and stderr file descriptios and redirect test + # output to the previously prepared file descriptors 3 and 4 (see + # below) + if test "$verbose" != "t"; then exec 4>test.output 3>&4; fi + exec 6>&1 7>&2 >&3 2>&4 + inside_subtest=t +} - tests=$((tests + 1)) +# Pass test if two arguments match +# +# Note: Unlike all other test_expect_* functions, this function does +# not accept a test name. Instead, the caller should call +# test_begin_subtest before calling this function in order to set the +# name. +test_expect_equal () +{ + exec 1>&6 2>&7 # Restore stdout and stderr + inside_subtest= + test "$#" = 3 && { prereq=$1; shift; } || prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test_expect_equal" - if [ "$output" = "$expected" ]; then - echo " PASS" - else - echo " FAIL" - testname=test-$(printf "%03d" $tests) - echo "$expected" > $testname.expected - echo "$output" > $testname.output - diff -u $testname.expected $testname.output || true - test_failures=$((test_failures + 1)) + output="$1" + expected="$2" + if ! test_skip "$@" + then + if [ "$output" = "$expected" ]; then + test_ok_ "$test_subtest_name" + else + testname=$this_test.$test_count + echo "$expected" > $testname.expected + echo "$output" > $testname.output + test_failure_ "$test_subtest_name" "$(diff -u $testname.expected $testname.output)" + fi fi } -TEST_DIR=$(pwd)/test.$$ -MAIL_DIR=${TEST_DIR}/mail -export NOTMUCH_CONFIG=${TEST_DIR}/notmuch-config -NOTMUCH=$(find_notmuch_binary $(pwd)) +test_expect_equal_file () +{ + exec 1>&6 2>&7 # Restore stdout and stderr + inside_subtest= + test "$#" = 3 && { prereq=$1; shift; } || prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test_expect_equal" + + output="$1" + expected="$2" + if ! test_skip "$@" + then + if diff -q "$expected" "$output" >/dev/null ; then + test_ok_ "$test_subtest_name" + else + testname=$this_test.$test_count + cp "$output" $testname.output + cp "$expected" $testname.expected + test_failure_ "$test_subtest_name" "$(diff -u $testname.expected $testname.output)" + fi + fi +} + +test_expect_equal_failure () +{ + exec 1>&6 2>&7 # Restore stdout and stderr + inside_subtest= + test "$#" = 3 && { prereq=$1; shift; } || prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test_expect_equal" + + output="$1" + expected="$2" + if ! test_skip "$@" + then + if [ "$output" = "$expected" ]; then + test_known_broken_ok_ "$test_subtest_name" + else + test_known_broken_failure_ "$test_subtest_name" + testname=$this_test.$test_count + echo "$expected" > $testname.expected + echo "$output" > $testname.output + fi + fi +} NOTMUCH_NEW () { - $NOTMUCH new | grep -v -E -e '^Processed [0-9]*( total)? file|Found [0-9]* total file' + notmuch new | grep -v -E -e '^Processed [0-9]*( total)? file|Found [0-9]* total file' } notmuch_search_sanitize () @@ -413,6 +522,20 @@ notmuch_show_sanitize () { sed -e "$NOTMUCH_SHOW_FILENAME_SQUELCH" } +notmuch_show_sanitize_all () +{ + sed \ + -e 's| filename:.*| filename:XXXXX|' \ + -e 's| id:[^ ]* | id:XXXXX |' +} + +notmuch_json_show_sanitize () +{ + sed -e 's|, |,\n |g' | \ + sed \ + -e 's|"id": "[^"]*",|"id": "XXXXX",|' \ + -e 's|"filename": "[^"]*",|"filename": "YYYYY",|' +} # End of notmuch helper functions @@ -446,25 +569,30 @@ test_have_prereq () { test_ok_ () { test_success=$(($test_success + 1)) - say_color "" " ok $test_count: $@" + say_color pass "%-6s" "PASS" + echo " $@" } test_failure_ () { test_failure=$(($test_failure + 1)) - say_color error "FAIL $test_count: $1" + say_color error "%-6s" "FAIL" + echo " $1" shift echo "$@" | sed -e 's/^/ /' + if test "$verbose" != "t"; then cat test.output; fi test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; } } test_known_broken_ok_ () { test_fixed=$(($test_fixed+1)) - say_color "" " FIXED $test_count: $@" + say_color pass "%-6s" "FIXED" + echo " $@" } test_known_broken_failure_ () { test_broken=$(($test_broken+1)) - say_color skip " still broken $test_count: $@" + say_color pass "%-6s" "BROKEN" + echo " $@" } test_debug () { @@ -473,6 +601,7 @@ test_debug () { test_run_ () { test_cleanup=: + if test "$verbose" != "t"; then exec 4>test.output 3>&4; fi eval >&3 2>&4 "$1" eval_ret=$? eval >&3 2>&4 "$test_cleanup" @@ -482,7 +611,7 @@ test_run_ () { test_skip () { test_count=$(($test_count+1)) to_skip= - for skp in $GIT_SKIP_TESTS + for skp in $NOTMUCH_SKIP_TESTS do case $this_test.$test_count in $skp) @@ -497,7 +626,8 @@ test_skip () { case "$to_skip" in t) say_color skip >&3 "skipping test: $@" - say_color skip "skip $test_count: $1" + say_color skip "%-6s" "SKIP" + echo " $1" : true ;; *) @@ -512,7 +642,6 @@ test_expect_failure () { error "bug in the test script: not 2 or 3 parameters to test-expect-failure" if ! test_skip "$@" then - say >&3 "checking known breakage: $2" test_run_ "$2" if [ "$?" = 0 -a "$eval_ret" = 0 ] then @@ -521,7 +650,6 @@ test_expect_failure () { test_known_broken_failure_ "$1" fi fi - echo >&3 "" } test_expect_success () { @@ -530,7 +658,6 @@ test_expect_success () { error "bug in the test script: not 2 or 3 parameters to test-expect-success" if ! test_skip "$@" then - say >&3 "expecting success: $2" test_run_ "$2" if [ "$?" = 0 -a "$eval_ret" = 0 ] then @@ -539,7 +666,6 @@ test_expect_success () { test_failure_ "$@" fi fi - echo >&3 "" } test_expect_code () { @@ -548,7 +674,6 @@ test_expect_code () { error "bug in the test script: not 3 or 4 parameters to test-expect-code" if ! test_skip "$@" then - say >&3 "expecting exit code $1: $3" test_run_ "$3" if [ "$?" = 0 -a "$eval_ret" = "$1" ] then @@ -557,7 +682,6 @@ test_expect_code () { test_failure_ "$@" fi fi - echo >&3 "" } # test_external runs external test scripts that provide continuous @@ -603,7 +727,6 @@ test_external_without_stderr () { [ -f "$stderr" ] || error "Internal error: $stderr disappeared." descr="no stderr: $1" shift - say >&3 "expecting no stderr from previous command" if [ ! -s "$stderr" ]; then rm "$stderr" test_ok_ "$descr" @@ -691,34 +814,65 @@ test_done () { echo "failed $test_failure" >> $test_results_path echo "" >> $test_results_path - if test "$test_fixed" != 0 - then - say_color pass "fixed $test_fixed known breakage(s)" - fi - if test "$test_broken" != 0 - then - say_color error "still have $test_broken known breakage(s)" - msg="remaining $(($test_count-$test_broken)) test(s)" + echo + + if [ "$test_failure" = "0" ]; then + if [ "$test_broken" = "0" ]; then + rm -rf "$remove_tmp" + fi + exit 0 else - msg="$test_count test(s)" + exit 1 fi - case "$test_failure" in - 0) - say_color pass "passed all $msg" - - test -d "$remove_trash" && - cd "$(dirname "$remove_trash")" && - rm -rf "$(basename "$remove_trash")" - - exit 0 ;; +} - *) - say_color error "failed $test_failure among $msg" - exit 1 ;; +test_emacs () { + # Construct a little test script here for the benefit of the user, + # (who can easily run "run_emacs" to get the same emacs environment + # for investigating any failures). + cat < run_emacs +#!/bin/sh +export PATH=$PATH +export NOTMUCH_CONFIG=$NOTMUCH_CONFIG + +# We assume that the user will give a command-line argument only if +# wanting to run in batch mode. +if [ \$# -gt 0 ]; then + BATCH=--batch +fi - esac +# Here's what we are using here: +# +# --batch: Quit after given commands and print all (messages) +# +# --no-init-file Don't load users ~/.emacs +# +# --no-site-file Don't load the site-wide startup stuff +# +# --directory Ensure that the local elisp sources are found +# +# --load Force loading of notmuch.el and test-lib.el +# +# notmuch-test-wait Function for tests to use to wait for process completion +# +# message-signature Avoiding appending user's signature on messages +# +# set-frame-width 80 columns (avoids crazy 10-column default of --batch) + +emacs \$BATCH --no-init-file --no-site-file \ + --directory ../../emacs --load notmuch.el \ + --directory .. --load test-lib.el \ + --eval "(defun notmuch-test-wait () + (while (get-buffer-process (current-buffer)) + (sleep-for 0.1)))" \ + --eval "(setq message-signature nil)" \ + --eval "(progn (set-frame-width (window-frame (get-buffer-window)) 80) \$@)" +EOF + chmod a+x ./run_emacs + ./run_emacs "$@" } + find_notmuch_path () { dir="$1" @@ -739,7 +893,6 @@ find_notmuch_path () # Test the binaries we have just built. The tests are kept in # test/ subdirectory and are run in 'trash directory' subdirectory. TEST_DIRECTORY=$(pwd) -# FIXME: Only the normal case bellow is updated to notmuch if test -n "$valgrind" then make_symlink () { @@ -782,18 +935,15 @@ then make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit } - # override all git executables in TEST_DIRECTORY/.. + # override notmuch executable in TEST_DIRECTORY/.. GIT_VALGRIND=$TEST_DIRECTORY/valgrind mkdir -p "$GIT_VALGRIND"/bin - for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-* - do - make_valgrind_symlink $file - done + make_valgrind_symlink $TEST_DIRECTORY/../notmuch OLDIFS=$IFS IFS=: for path in $PATH do - ls "$path"/git-* 2> /dev/null | + ls "$path"/notmuch 2> /dev/null | while read file do make_valgrind_symlink "$file" @@ -803,11 +953,6 @@ then PATH=$GIT_VALGRIND/bin:$PATH GIT_EXEC_PATH=$GIT_VALGRIND/bin export GIT_VALGRIND -elif test -n "$GIT_TEST_INSTALLED" ; then - GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || - error "Cannot run git from $GIT_TEST_INSTALLED." - PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH - GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} else # normal case notmuch_path=`find_notmuch_path "$TEST_DIRECTORY"` test -n "$notmuch_path" && PATH="$notmuch_path:$PATH" @@ -815,24 +960,25 @@ fi export PATH # Test repository -test="trash directory.$(basename "$0" .sh)" +test="tmp.$(basename "$0" .sh)" test -n "$root" && test="$root/$test" case "$test" in -/*) TRASH_DIRECTORY="$test" ;; - *) TRASH_DIRECTORY="$TEST_DIRECTORY/$test" ;; +/*) TMP_DIRECTORY="$test" ;; + *) TMP_DIRECTORY="$TEST_DIRECTORY/$test" ;; esac -test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY +test ! -z "$debug" || remove_tmp=$TMP_DIRECTORY rm -fr "$test" || { GIT_EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" exit 1 } -MAIL_DIR="${TRASH_DIRECTORY}/mail" -export NOTMUCH_CONFIG="${TRASH_DIRECTORY}/notmuch-config" +MAIL_DIR="${TMP_DIRECTORY}/mail" +export GNUPGHOME="${TMP_DIRECTORY}/gnupg" +export NOTMUCH_CONFIG="${TMP_DIRECTORY}/notmuch-config" mkdir -p "${test}" -mkdir "$MAIL_DIR" +mkdir -p "${MAIL_DIR}" cat <"${NOTMUCH_CONFIG}" [database] @@ -849,12 +995,18 @@ EOF # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || error "Cannot setup test environment" +if test "$verbose" = "t" +then + exec 4>&2 3>&1 +else + exec 4>test.output 3>&4 +fi + this_test=${0##*/} -this_test=${this_test%%-*} -for skp in $GIT_SKIP_TESTS +for skp in $NOTMUCH_SKIP_TESTS do to_skip= - for skp in $GIT_SKIP_TESTS + for skp in $NOTMUCH_SKIP_TESTS do case "$this_test" in $skp)