#!/usr/local/bin/zsh # Quick-n-dirty script to ease running the IMAP tests in various configurations. # Also generates coverage reports (requires Rust nightly). # TODO redo in more standard fashion under `make check`. # Configuration: # export MH_TEST_IMAP_LOG_LEVEL=trace # export MH_TEST_NOCLEANUP=1 # export MH_TEST_STUNNEL_DEBUG=7 # export MH_TEST_STUNNEL_OUTPUT=/dev/stderr # export MH_TEST_VERBOSE=1 # export RUST_BACKTRACE=1 # abs_srcdir=$HOME/work/nmh # abs_builddir=$abs_srcdir/.o/clang13 # LLVM_PROFDATA=llvm-profdata13 # LLVM_COV=llvm-cov13 # MAKE=make # MAKE_JOBS=-j4 # PANDA_IMAPD=/usr/local/libexec/imapd # # optional: # gandi_user='example@example.com' # gandi_pw='...' #gmail_user='example@example.com' #gmail_oauth=/path/to/oauth-gmail set -ex abs_builddir=$PWD cf=$1 if ! [[ -n $cf ]]; then print -u2 "usage imaptest CONFIGURATION ACTION" exit 2 fi shift . $cf for v in \ abs_srcdir \ LLVM_PROFDATA \ LLVM_COV \ MAKE \ PANDA_IMAPD \ ; do if ! eval "[[ -n \$$v ]]"; then print -u2 "$v must be set in $cf" exit 2 fi done testdir=$abs_builddir/test/testdir export CARGO_TARGET_DIR=$abs_builddir/target # Coverage documentation # https://doc.rust-lang.org/beta/unstable-book/compiler-flags/source-based-code-coverage.html # https://clang.llvm.org/docs/SourceBasedCodeCoverage.html # https://llvm.org/docs/CommandGuide/llvm-profdata.html # https://llvm.org/docs/CommandGuide/llvm-cov.html # Bugs # https://github.com/rust-lang/rust/issues/79121 Tracking Issue for LLVM InstrProf code coverage # https://github.com/rust-lang/rust/issues/85902 Add a cargo option to generate coverage reports using -Z instrument-coverage # https://github.com/rust-lang/rust/issues/79649 Add support for branch coverage in source-based coverage report-coverage() { typeset profile=$1 typeset profile_dir=$2 typeset profdata=$abs_builddir/covdata/$profile.profdata find $abs_builddir/covdata/$profile_dir -name '*.profraw' | $nop xargs $LLVM_PROFDATA merge --sparse \ -o $profdata $nop $LLVM_COV show -Xdemangler=$HOME/.cargo/bin/rustfilt '--ignore-filename-regex=/tests/' '--ignore-filename-regex=/tests\.rs' '--ignore-filename-regex=\.cargo' --format=html \ -o $abs_builddir/covdata/html/$profile --instr-profile=$profdata \ ${=${(j: --object :)test_objects}} } check-litter() { setopt LOCAL_OPTIONS NULL_GLOB typeset litter=($testdir/*.actual) (( $#litter > 0 )) || return 0 print -u2 "$1 littered $litter" false } report_only=false coverage=false typeset -a actions profiles while [[ $# -gt 0 ]]; do word=$1 shift case $word in -n) nop=(print --) ;; -cover*) coverage=: if [[ $word = -cover-report ]]; then report_only=: else $nop rm -rf $abs_builddir/covdata fi . ~/.cargo/env export RUSTFLAGS="-Zinstrument-coverage $RUSTFLAGS" ;; all) # We test implicit TLS with Gmail and explicit with Gandi; any reason to test both ways both places? set -- cargot test live/panda live/dovecot live/cyrus live/gandi-starttls live/gmail "$@" ;; build|clean) actions+=$word ;; cargot|test|live/*) actions+=$word profiles+=$word ;; test/*) actions+=$word profiles+=test ;; *) print -u2 "get outta here $word" exit 3 ;; esac done if ! $report_only; then for action in $actions; do case $action in build) (cd $abs_builddir && $nop $MAKE $MAKE_JOBS all cargo) ;; cargot) $nop env LLVM_PROFILE_FILE="$abs_builddir/covdata/cargot/%m-%p.profraw" cargo t -- --test-threads=1 ;; test) tests=( test/imap/test-astring test/imap/test-bad test/imap/test-bad-fetch-body test/imap/test-folder-create-disallowed # Downloads all mail from your test account; better be sure you want that! # test/imap/test-gmail-all test/imap/test-inc test/imap/test-inc-missing-msg test/imap/test-inc-missing-msg-case-2 # Handled specially below. # test/imap/test-live test/imap/test-login test/imap/test-mark test/imap/test-quirks-gmail # TODO fix the bitrot # test/imap/test-refile test/imap/test-rmm test/imap/test-scan test/imap/test-server-drops test/imap/test-uidvalidity test/imap/test-xoauth ) (cd $abs_builddir && for test in $tests; do $nop env PANDA_IMAPD=$PANDA_IMAPD MH_COVERAGE_PROFILE=test $MAKE check TESTS=$test check-litter $test done) ;; test/*) (cd $abs_builddir && $nop env PANDA_IMAPD=$PANDA_IMAPD MH_COVERAGE_PROFILE=test $MAKE check TESTS=$action) check-litter $action ;; live/panda) (cd $abs_builddir && $nop env PANDA_IMAPD=$PANDA_IMAPD MH_COVERAGE_PROFILE=live/panda MH_IMAP_TEST_SERVER=panda \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; live/dovecot) (cd $abs_builddir && $nop env MH_COVERAGE_PROFILE=live/dovecot MH_IMAP_TEST_SERVER=127.0.0.1 MH_IMAP_TEST_PORT=1043 \ MH_IMAP_TEST_USER=test MH_IMAP_TEST_PASSWORD=testpw MH_IMAP_TEST_EMAIL_ADDRESS=test MH_IMAP_TEST_TLS=no \ MH_IMAP_SERVER_DRAFT_BORN_UNSEEN=' ' MH_IMAP_SERVER_EATS_TRAILING_EOL=' ' \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; live/cyrus) (cd $abs_builddir && $nop env MH_COVERAGE_PROFILE=live/cyrus MH_IMAP_TEST_SERVER=127.0.0.1 MH_IMAP_TEST_PORT=143 MH_IMAP_TEST_USER=test \ MH_IMAP_TEST_PASSWORD=test MH_IMAP_TEST_EMAIL_ADDRESS=test MH_IMAP_TEST_TLS=no MH_IMAP_TEST_MAILBOX_ROOT=test/ \ MH_IMAP_SERVER_DRAFT_BORN_UNSEEN='U' \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; # Looks like Gandi use Dovecot live/gandi) (cd $abs_builddir && $nop env MH_COVERAGE_PROFILE=live/gandi MH_IMAP_TEST_SERVER=mail.gandi.net MH_IMAP_TEST_PORT=imaps \ MH_IMAP_TEST_USER=$gandi_user MH_IMAP_TEST_PASSWORD=$gandi_pw MH_IMAP_TEST_EMAIL_ADDRESS=$gandi_user \ MH_IMAP_TEST_TLS=implicit MH_IMAP_TEST_MAILBOX_ROOT=test/ \ MH_IMAP_SERVER_DRAFT_BORN_UNSEEN=' ' \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; live/gandi-starttls) (cd $abs_builddir && $nop env MH_COVERAGE_PROFILE=live/gandi-starttls MH_IMAP_TEST_SERVER=mail.gandi.net MH_IMAP_TEST_PORT=imap \ MH_IMAP_TEST_USER=$gandi_user MH_IMAP_TEST_PASSWORD=$gandi_pw MH_IMAP_TEST_EMAIL_ADDRESS=$gandi_user \ MH_IMAP_TEST_TLS=explicit MH_IMAP_TEST_MAILBOX_ROOT=test/ \ MH_IMAP_SERVER_DRAFT_BORN_UNSEEN=' ' \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; live/gmail) (cd $abs_builddir && $nop env MH_COVERAGE_PROFILE=live/gmail MH_IMAP_TEST_SERVER=gmail MH_IMAP_TEST_PORT=imaps MH_IMAP_TEST_USER=$gmail_user \ MH_IMAP_TEST_OAUTH_FILE=$gmail_oauth MH_IMAP_TEST_EMAIL_ADDRESS=$gmail_user MH_IMAP_TEST_MAILBOX_ROOT=test/ \ MH_IMAP_SERVER_DRAFT_BORN_UNSEEN='U' \ $MAKE check TESTS=test/imap/test-live) check-litter $action ;; report-coverage) ;; clean) $nop rm -rf $abs_builddir/target $nop rm -rf $testdir ;; esac done fi if $coverage; then test_objects=( $abs_builddir/target/debug/imap-folder-manager $($nop env LLVM_PROFILE_FILE="$abs_builddir/covdata/cargot/%m-%p.profraw" cargo t --tests --no-run --message-format=json 2>/dev/null \ | $nop perl -MJSON::PP -lne 'eval { $item = decode_json($_) }; if ($@) { @all=(); die($@) } $fns = $item->{profile}->{test} && $item->{filenames}; $fns && push(@all, @$fns); END { print join("\n", @all) }') ) print -l $test_objects cd $abs_srcdir report-coverage all (( ${profiles[(i)live/*]} <= ${#profiles} )) && report-coverage live live for profile in $profiles; do report-coverage $profile $profile done $nop chmod -R a+rX $abs_builddir/covdata/html exit fi