#!/bin/bash read -rd "\000" helpmessage <&2 "Fatal: $* (encountered in ${FUNCNAME[1]} at ${BASH_SOURCE[1]} line ${BASH_LINENO[0]})" exit 1 } report_outcomes() { for x in "${successes[@]}" do echo "Pass: $x" done if [[ ${#failures[@]} == 0 ]] then echo "All test suites passed." else echo "Failures (${#failures[@]}):" for x in "${failures[@]}" do echo "Fail: $x" done fi } exit_cleanly() { trap - INT create-plot-data-from-log.sh $BUILD_NUMBER "$WORKSPACE/apps/workbench/log/test.log" "$WORKSPACE/apps/workbench/log/" rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log" stop_services rotate_logfile "$WORKSPACE/services/api/log/" "test.log" report_outcomes clear_temp exit ${#failures} } sanity_checks() { ( [[ -n "$WORKSPACE" ]] && [[ -d "$WORKSPACE/services" ]] ) \ || fatal "WORKSPACE environment variable not set to a source directory (see: $0 --help)" echo Checking dependencies: echo -n 'virtualenv: ' virtualenv --version \ || fatal "No virtualenv. Try: apt-get install virtualenv" echo -n 'go: ' go version \ || fatal "No go binary. See http://golang.org/doc/install" echo -n 'gcc: ' gcc --version | egrep ^gcc \ || fatal "No gcc. Try: apt-get install build-essential" echo -n 'fuse.h: ' find /usr/include -wholename '*fuse/fuse.h' \ || fatal "No fuse/fuse.h. Try: apt-get install libfuse-dev" echo -n 'pyconfig.h: ' find /usr/include -name pyconfig.h | egrep --max-count=1 . \ || fatal "No pyconfig.h. Try: apt-get install python-dev" echo -n 'nginx: ' PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" nginx -v \ || fatal "No nginx. Try: apt-get install nginx" } rotate_logfile() { # i.e. rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log" # $BUILD_NUMBER is set by Jenkins if this script is being called as part of a Jenkins run if [[ -f "$1/$2" ]]; then THEDATE=`date +%Y%m%d%H%M%S` mv "$1/$2" "$1/$THEDATE-$BUILD_NUMBER-$2" gzip "$1/$THEDATE-$BUILD_NUMBER-$2" fi } declare -a failures declare -A skip declare -A testargs skip[apps/workbench_profile]=1 while [[ -n "$1" ]] do arg="$1"; shift case "$arg" in --help) echo >&2 "$helpmessage" echo >&2 exit 1 ;; --skip) skipwhat="$1"; shift skip[$skipwhat]=1 ;; --only) only="$1"; skip[$1]=""; shift ;; --skip-install) skip_install=1 ;; --only-install) skip_install=1 only_install="$1"; shift ;; --leave-temp) leave_temp[VENVDIR]=1 leave_temp[VENV3DIR]=1 leave_temp[GOPATH]=1 leave_temp[GEMHOME]=1 ;; --retry) retry=1 ;; *_test=*) suite="${arg%%_test=*}" args="${arg#*=}" testargs["$suite"]="$args" ;; *=*) eval export $(echo $arg | cut -d= -f1)=\"$(echo $arg | cut -d= -f2-)\" ;; *) echo >&2 "$0: Unrecognized option: '$arg'. Try: $0 --help" exit 1 ;; esac done start_api() { echo 'Starting API server...' cd "$WORKSPACE" \ && eval $(python sdk/python/tests/run_test_server.py start --auth admin) \ && export ARVADOS_TEST_API_HOST="$ARVADOS_API_HOST" \ && export ARVADOS_TEST_API_INSTALLED="$$" \ && (env | egrep ^ARVADOS) } start_nginx_proxy_services() { echo 'Starting keepproxy, arv-git-httpd, and nginx ssl proxy...' cd "$WORKSPACE" \ && python sdk/python/tests/run_test_server.py start_keep_proxy \ && python sdk/python/tests/run_test_server.py start_arv-git-httpd \ && python sdk/python/tests/run_test_server.py start_nginx \ && export ARVADOS_TEST_PROXY_SERVICES=1 } stop_services() { if [[ -n "$ARVADOS_TEST_PROXY_SERVICES" ]]; then unset ARVADOS_TEST_PROXY_SERVICES cd "$WORKSPACE" \ && python sdk/python/tests/run_test_server.py stop_nginx \ && python sdk/python/tests/run_test_server.py stop_arv-git-httpd \ && python sdk/python/tests/run_test_server.py stop_keep_proxy fi if [[ -n "$ARVADOS_TEST_API_HOST" ]]; then unset ARVADOS_TEST_API_HOST cd "$WORKSPACE" \ && python sdk/python/tests/run_test_server.py stop fi } interrupt() { failures+=("($(basename $0) interrupted)") exit_cleanly } trap interrupt INT sanity_checks echo "WORKSPACE=$WORKSPACE" if [[ -z "$CONFIGSRC" ]] && [[ -d "$HOME/arvados-api-server" ]]; then # Jenkins expects us to use this by default. CONFIGSRC="$HOME/arvados-api-server" fi # Clean up .pyc files that may exist in the workspace cd "$WORKSPACE" find -name '*.pyc' -delete # Set up temporary install dirs (unless existing dirs were supplied) for tmpdir in VENVDIR VENV3DIR GOPATH GEMHOME do if [[ -n "${!tmpdir}" ]]; then leave_temp[$tmpdir]=1 else eval $tmpdir=$(mktemp -d) fi done setup_ruby_environment() { if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then source "$HOME/.rvm/scripts/rvm" using_rvm=true elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then source "/usr/local/rvm/scripts/rvm" using_rvm=true else using_rvm=false fi if [[ "$using_rvm" == true ]]; then # If rvm is in use, we can't just put separate "dependencies" # and "gems-under-test" paths to GEM_PATH: passenger resets # the environment to the "current gemset", which would lose # our GEM_PATH and prevent our test suites from running ruby # programs (for example, the Workbench test suite could not # boot an API server or run arv). Instead, we have to make an # rvm gemset and use it for everything. [[ `type rvm | head -n1` == "rvm is a function" ]] \ || fatal 'rvm check' # Put rvm's favorite path back in first place (overriding # virtualenv, which just put itself there). Ignore rvm's # complaint about not being in first place already. rvm use @default 2>/dev/null # Create (if needed) and switch to an @arvados-tests # gemset. (Leave the choice of ruby to the caller.) rvm use @arvados-tests --create \ || fatal 'rvm gemset setup' rvm env else # When our "bundle install"s need to install new gems to # satisfy dependencies, we want them to go where "gem install # --user-install" would put them. (However, if the caller has # already set GEM_HOME, we assume that's where dependencies # should be installed, and we should leave it alone.) if [ -z "$GEM_HOME" ]; then user_gempath="$(gem env gempath)" export GEM_HOME="${user_gempath%%:*}" fi PATH="$(gem env gemdir)/bin:$PATH" # When we build and install our own gems, we install them in our # $GEMHOME tmpdir, and we want them to be at the front of GEM_PATH and # PATH so integration tests prefer them over other versions that # happen to be installed in $user_gempath, system dirs, etc. tmpdir_gem_home="$(env - PATH="$PATH" HOME="$GEMHOME" gem env gempath | cut -f1 -d:)" PATH="$tmpdir_gem_home/bin:$PATH" export GEM_PATH="$tmpdir_gem_home:$(gem env gempath)" echo "Will install dependencies to $(gem env gemdir)" echo "Will install arvados gems to $tmpdir_gem_home" echo "Gem search path is GEM_PATH=$GEM_PATH" fi } with_test_gemset() { if [[ "$using_rvm" == true ]]; then "$@" else GEM_HOME="$tmpdir_gem_home" "$@" fi } export GOPATH mkdir -p "$GOPATH/src/git.curoverse.com" ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \ || fatal "symlink failed" virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed" . "$VENVDIR/bin/activate" # Note: this must be the last time we change PATH, otherwise rvm will # whine a lot. setup_ruby_environment echo "PATH is $PATH" if ! which bundler >/dev/null then gem install --user-install bundler || fatal 'Could not install bundler' fi # Needed for run_test_server.py which is used by certain (non-Python) tests. pip freeze 2>/dev/null | egrep ^PyYAML= \ || pip install PyYAML \ || fatal "pip install PyYAML failed" # If Python 3 is available, set up its virtualenv in $VENV3DIR. # Otherwise, skip dependent tests. PYTHON3=$(which python3) if [ "0" = "$?" ]; then virtualenv --python "$PYTHON3" --setuptools "$VENV3DIR" \ || fatal "python3 virtualenv $VENV3DIR failed" else PYTHON3= skip[services/dockercleaner]=1 cat >&2 </dev/null cd "$WORKSPACE/services/api" \ && RAILS_ENV=test bundle exec rake db:drop \ && RAILS_ENV=test bundle exec rake db:setup \ && RAILS_ENV=test bundle exec rake db:fixtures:load } do_install services/api apiserver declare -a gostuff gostuff=( services/arv-git-httpd services/crunchstat services/keepstore services/keepproxy sdk/go/arvadosclient sdk/go/keepclient sdk/go/streamer ) for g in "${gostuff[@]}" do do_install "$g" go done install_workbench() { cd "$WORKSPACE/apps/workbench" \ && mkdir -p tmp/cache \ && RAILS_ENV=test bundle_install_trylocal } do_install apps/workbench workbench test_doclinkchecker() { ( set -e cd "$WORKSPACE/doc" ARVADOS_API_HOST=qr1hi.arvadosapi.com # Make sure python-epydoc is installed or the next line won't # do much good! PYTHONPATH=$WORKSPACE/sdk/python/ bundle exec rake linkchecker baseurl=file://$WORKSPACE/doc/.site/ arvados_workbench_host=workbench.$ARVADOS_API_HOST arvados_api_host=$ARVADOS_API_HOST ) } do_test doc doclinkchecker stop_services test_apiserver() { cd "$WORKSPACE/services/api" \ && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[services/api]} } do_test services/api apiserver # Shortcut for when we're only running apiserver tests. This saves a bit of time, # because we don't need to start up the api server for subsequent tests. if [ ! -z "$only" ] && [ "$only" == "services/api" ]; then rotate_logfile "$WORKSPACE/services/api/log/" "test.log" exit_cleanly fi start_api test_ruby_sdk() { cd "$WORKSPACE/sdk/ruby" \ && bundle exec rake test TESTOPTS=-v ${testargs[sdk/ruby]} } do_test sdk/ruby ruby_sdk test_cli() { cd "$WORKSPACE/sdk/cli" \ && mkdir -p /tmp/keep \ && KEEP_LOCAL_STORE=/tmp/keep bundle exec rake test TESTOPTS=-v ${testargs[sdk/cli]} } do_test sdk/cli cli for p in "${pythonstuff[@]}" do do_test "$p" pip done do_test services/dockercleaner pip "$VENV3DIR/bin/" for g in "${gostuff[@]}" do do_test "$g" go done test_workbench() { start_nginx_proxy_services \ && cd "$WORKSPACE/apps/workbench" \ && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[apps/workbench]} } do_test apps/workbench workbench test_workbench_benchmark() { start_nginx_proxy_services \ && cd "$WORKSPACE/apps/workbench" \ && RAILS_ENV=test bundle exec rake test:benchmark ${testargs[apps/workbench_benchmark]} } do_test apps/workbench_benchmark workbench_benchmark test_workbench_profile() { start_nginx_proxy_services \ && cd "$WORKSPACE/apps/workbench" \ && RAILS_ENV=test bundle exec rake test:profile ${testargs[apps/workbench_profile]} } do_test apps/workbench_profile workbench_profile exit_cleanly