#!/bin/sh # # Validate that mosh produces expected output, using screen captures # in tmux. # log() { printf "$@" } error() { printf "$@" >&2 } dump_logs() { dir=$1 shift testname=$(basename $dir .d) for logfile in $dir/*.tmux.log; do printf "travis_fold:start:%s-%s\n" $testname $(basename $logfile) cat $logfile printf "travis_fold:end:%s-%s\n" $testname $(basename $logfile) done } test_success() { exit 0 } test_failure() { error "$@" exit 1 } test_skipped() { error "$@" exit 77 } test_error() { error "$@" exit 99 } test_exitstatus() { status=$1 shift error "$@" exit $status } # Tmux check. tmux_check() { version=$(tmux -V) if [ $? != 0 ]; then error "tmux unavailable\n" return 1 fi version=${version##tmux } version_major=${version%%.*} version_minor=${version##*.} # need version 1.8 for capture-pane if [ $version_major -lt 1 ] || [ $version_major -eq 1 -a $version_minor -lt 8 ]; then error "tmux version %s too old\n" "$version" return 1 fi return 0 } ssh_localhost_check() { ssh localhost : if [ $? -ne 0 ]; then error "ssh to localhost failed\n" return 1 fi return 0 } # These two functions are wrappers for mosh-client/mosh-server to turn # on verbosity and log stderr. mosh_client() { if [ -z "$MOSH_CLIENT" -o -z "$MOSH_E2E_TEST" ]; then test_error "mosh_client: variables missing\n" fi exec 2> "${MOSH_E2E_TEST}.client.stderr" exec "$MOSH_CLIENT" $MOSH_CLIENT_ARGS "$@" } mosh_server() { if [ -z "$MOSH_SERVER" -o -z "$MOSH_E2E_TEST" ]; then test_error "mosh_server: variables missing\n" fi exec 2> "${MOSH_E2E_TEST}.server.stderr" exec "$MOSH_SERVER" new -v $MOSH_SERVER_ARGS -@ "$@" } # main # Set up environment if [ -z "$srcdir" ]; then : ${srcdir:=$PWD} else srcdir="$(cd $srcdir && pwd)" if [ $? -ne 0 ]; then error "can't cd to srcdir: %s\n" "$srcdir" exit 99 fi fi # Wrappers. case "$(basename $0)" in mosh-client) mosh_client "$@" exit ;; mosh-server) mosh_server "$@" exit ;; *) ;; esac if ! tmux_check; then test_skipped "tmux unavailable\n" fi if [ $# -lt 2 ]; then test_error "not enough args\n" fi # Get arguments (only one so far) test_name=$1 shift test_args=$@ # XXX could use AM testsubdir macro instead test_dir=$(basename ${test_name}).d test_script="${test_name}" rm -rf "${test_dir}" mkdir "${test_dir}" trap 'rv=$?; if test $rv -ne 0; then dump_logs '"$test_dir $test_args"'; fi; exit $rv' EXIT # Set up tests to run. server_tests= compare_tests= for i in $test_args; do case $i in baseline|direct|variant) server_tests="$server_tests $i";; verify|same|different) compare_tests="$compare_tests $i";; tmux) tmux=1;; client) client=1;; post) post=1;; mosh-args) mosh_args=$(${test_script} mosh-args);; client-args) export MOSH_CLIENT_ARGS=$(${test_script} client-args);; server-args) export MOSH_SERVER_ARGS=$(${test_script} server-args);; *) error "unknown test type argument %s", $i exit 99 ;; esac done # Run test(s). client_wrapper= if [ -n "$client" ]; then client_wrapper="${test_script} client" fi tmux_stdin="${srcdir}/hold-stdin" if [ -n "$tmux" ]; then tmux_stdin="${test_script} tmux" fi for run in $server_tests; do log "Running server test %s.\n" "$run" # These three variables are for the benefit of the mosh-client and mosh-server wrappers. export MOSH_CLIENT="$PWD/../frontend/mosh-client" export MOSH_SERVER="$PWD/../frontend/mosh-server" export MOSH_E2E_TEST="$PWD/${test_dir}/${run}" # XXX need to quote special chars in server pathname here somehow sut="../../scripts/mosh --client=${srcdir}/mosh-client --server=${srcdir}/mosh-server --local --bind-server=127.0.0.1 ${mosh_args} 127.0.0.1" testarg=$run if [ "$run" = "direct" ]; then sut="" fi # Actually execute code under test # XXX tmux 1.8 requires shell command as a single arg; once we move to 2.0, undo these quotes # XXX this ignores $TMPDIR, because it results in an overlong pathname on OS X tmux_socket="/tmp/.tmux-mosh-test-$$" ${tmux_stdin} tmux -f /dev/null -S "${tmux_socket}" -C new-session "${srcdir}/print-exitstatus ${client_wrapper} ${sut} \"${srcdir}/e2e-test-server\" \"${PWD}/${test_dir}/${run}\" \"${PWD}/${test_script} ${testarg}\"" > "${test_dir}/${run}.tmux.log" rv=$? rm -f "${tmux_socket}" if [ $rv -ne 0 ]; then test_error "tmux failure on test %s\n" "$run" fi # Check for mosh failures if ! grep -q "%%% exitstatus: 0 %%%" "${test_dir}/${run}.tmux.log"; then test_error "mosh-client had non-zero exitstatus\n" fi # Check for server harness failures if [ ! -s "${test_dir}/${run}.capture" ] \ || [ ! -s "${test_dir}/${run}.exitstatus" ]; then test_error "server harness failure on test %s\n" "$run" fi read server_rv < "${test_dir}/${run}.exitstatus" if [ "$server_rv" -ne 0 ]; then test_error "server harness exited with status %s\n" "$server_rv" fi # Check for "round-trip" failures if grep -q "round-trip Instruction verification failed" "${test_dir}/${run}.server.stderr"; then test_error "Round-trip Instruction verification failed on server during %s\n" "$run" fi # XXX We'd also like to check for "target state Instruction # verification failed", a new check, but tmux's lack of BCE # support forces mosh to clear lines with spaces and change a # framebuffer in a way that causes this to fire spuriously. done for compare in $compare_tests; do log "Running server comparison %s.\n" "$compare" # Compare captures if [ "$compare" = verify ]; then test1="direct" test2="baseline" else test1="baseline" test2="variant" fi if diff -q "${test_dir}/${test1}.capture" "${test_dir}/${test2}.capture"; then differ=n else differ=y fi if [ "$compare" = different ]; then desired=y badresult=same else desired=n badresult=different fi if [ $differ != $desired ]; then test_failure "Output is %s between tests %s and %s\n" "$badresult" "$test1" "$test2" fi done # Run a post script (usually a custom validation of results) if [ -n "$post" ]; then "${test_script}" post status=$? if [ $status -ne 0 ]; then test_exitstatus $status "Post test failed with exitstatus %d\n" $status fi fi