3 . `dirname "$(readlink -f "$0")"`/libcloud-pin
5 read -rd "\000" helpmessage <<EOF
6 $(basename $0): Install and test Arvados components.
8 Exit non-zero if any tests fail.
11 $(basename $0) WORKSPACE=/path/to/arvados [options]
15 --skip FOO Do not test the FOO component.
16 --only FOO Do not test anything except the FOO component.
17 --leave-temp Do not remove GOPATH, virtualenv, and other temp dirs at exit.
18 Instead, show which directories were used this time so they
19 can be reused in subsequent invocations.
20 --skip-install Do not run any install steps. Just run tests.
21 You should provide GOPATH, GEMHOME, and VENVDIR options
22 from a previous invocation if you use this option.
23 --only-install Run specific install step
24 WORKSPACE=path Arvados source tree to test.
25 CONFIGSRC=path Dir with api server config files to copy into source tree.
26 (If none given, leave config files alone in source tree.)
27 services/api_test="TEST=test/functional/arvados/v1/collections_controller_test.rb"
28 Restrict apiserver tests to the given file
29 sdk/python_test="--test-suite test.test_keep_locator"
30 Restrict Python SDK tests to the given class
31 apps/workbench_test="TEST=test/integration/pipeline_instances_test.rb"
32 Restrict Workbench tests to the given file
33 services/arv-git-httpd_test="-check.vv"
34 Show all log messages, even when tests pass (also works
35 with services/keepstore_test etc.)
37 Print more debug messages
38 envvar=value Set \$envvar to value. Primarily useful for WORKSPACE,
39 *_test, and other examples shown above.
41 Assuming --skip-install is not given, all components are installed
42 into \$GOPATH, \$VENDIR, and \$GEMHOME before running any tests. Many
43 test suites depend on other components being installed, and installing
44 everything tends to be quicker than debugging dependencies.
46 As a special concession to the current CI server config, CONFIGSRC
47 defaults to $HOME/arvados-api-server if that directory exists.
49 More information and background:
51 https://arvados.org/projects/arvados/wiki/Running_tests
56 apps/workbench_benchmark
57 apps/workbench_profile
61 services/dockercleaner
67 services/arv-git-httpd
78 # First make sure to remove any ARVADOS_ variables from the calling
79 # environment that could interfere with the tests.
80 unset $(env | cut -d= -f1 | grep \^ARVADOS_)
82 # Reset other variables that could affect our [tests'] behavior by
100 for var in VENVDIR VENV3DIR GOPATH GITDIR GEMHOME PERLINSTALLBASE
102 if [[ -z "${leave_temp[$var]}" ]]
104 if [[ -n "${!var}" ]]
109 leaving+=" $var=\"${!var}\""
112 if [[ -n "$leaving" ]]; then
113 echo "Leaving behind temp dirs: $leaving"
119 echo >&2 "Fatal: $* (encountered in ${FUNCNAME[1]} at ${BASH_SOURCE[1]} line ${BASH_LINENO[0]})"
124 for x in "${successes[@]}"
129 if [[ ${#failures[@]} == 0 ]]
131 echo "All test suites passed."
133 echo "Failures (${#failures[@]}):"
134 for x in "${failures[@]}"
143 create-plot-data-from-log.sh $BUILD_NUMBER "$WORKSPACE/apps/workbench/log/test.log" "$WORKSPACE/apps/workbench/log/"
144 rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log"
146 rotate_logfile "$WORKSPACE/services/api/log/" "test.log"
153 ( [[ -n "$WORKSPACE" ]] && [[ -d "$WORKSPACE/services" ]] ) \
154 || fatal "WORKSPACE environment variable not set to a source directory (see: $0 --help)"
155 echo Checking dependencies:
156 echo -n 'virtualenv: '
157 virtualenv --version \
158 || fatal "No virtualenv. Try: apt-get install virtualenv"
161 || fatal "No go binary. See http://golang.org/doc/install"
163 gcc --version | egrep ^gcc \
164 || fatal "No gcc. Try: apt-get install build-essential"
166 find /usr/include -wholename '*fuse/fuse.h' \
167 || fatal "No fuse/fuse.h. Try: apt-get install libfuse-dev"
168 echo -n 'pyconfig.h: '
169 find /usr/include -name pyconfig.h | egrep --max-count=1 . \
170 || fatal "No pyconfig.h. Try: apt-get install python-dev"
172 PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" nginx -v \
173 || fatal "No nginx. Try: apt-get install nginx"
175 perl -v | grep version \
176 || fatal "No perl. Try: apt-get install perl"
177 for mod in ExtUtils::MakeMaker JSON LWP Net::SSL; do
178 echo -n "perl $mod: "
179 perl -e "use $mod; print \"\$$mod::VERSION\\n\"" \
180 || fatal "No $mod. Try: apt-get install perl-modules libcrypt-ssleay-perl libjson-perl"
184 || fatal "No gitolite. Try: apt-get install gitolite3"
188 # i.e. rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log"
189 # $BUILD_NUMBER is set by Jenkins if this script is being called as part of a Jenkins run
190 if [[ -f "$1/$2" ]]; then
191 THEDATE=`date +%Y%m%d%H%M%S`
192 mv "$1/$2" "$1/$THEDATE-$BUILD_NUMBER-$2"
193 gzip "$1/$THEDATE-$BUILD_NUMBER-$2"
200 skip[apps/workbench_profile]=1
207 echo >&2 "$helpmessage"
216 only="$1"; skip[$1]=""; shift
223 only_install="$1"; shift
226 leave_temp[VENVDIR]=1
227 leave_temp[VENV3DIR]=1
229 leave_temp[GEMHOME]=1
230 leave_temp[PERLINSTALLBASE]=1
236 suite="${arg%%_test=*}"
238 testargs["$suite"]="$args"
241 eval export $(echo $arg | cut -d= -f1)=\"$(echo $arg | cut -d= -f2-)\"
244 echo >&2 "$0: Unrecognized option: '$arg'. Try: $0 --help"
251 echo 'Starting API server...'
253 && eval $(python sdk/python/tests/run_test_server.py start --auth admin) \
254 && export ARVADOS_TEST_API_HOST="$ARVADOS_API_HOST" \
255 && export ARVADOS_TEST_API_INSTALLED="$$" \
256 && (env | egrep ^ARVADOS)
259 start_nginx_proxy_services() {
260 echo 'Starting keepproxy, arv-git-httpd, and nginx ssl proxy...'
262 && python sdk/python/tests/run_test_server.py start_keep_proxy \
263 && python sdk/python/tests/run_test_server.py start_arv-git-httpd \
264 && python sdk/python/tests/run_test_server.py start_nginx \
265 && export ARVADOS_TEST_PROXY_SERVICES=1
269 if [[ -n "$ARVADOS_TEST_PROXY_SERVICES" ]]; then
270 unset ARVADOS_TEST_PROXY_SERVICES
272 && python sdk/python/tests/run_test_server.py stop_nginx \
273 && python sdk/python/tests/run_test_server.py stop_arv-git-httpd \
274 && python sdk/python/tests/run_test_server.py stop_keep_proxy
276 if [[ -n "$ARVADOS_TEST_API_HOST" ]]; then
277 unset ARVADOS_TEST_API_HOST
279 && python sdk/python/tests/run_test_server.py stop
284 failures+=("($(basename $0) interrupted)")
291 echo "WORKSPACE=$WORKSPACE"
293 if [[ -z "$CONFIGSRC" ]] && [[ -d "$HOME/arvados-api-server" ]]; then
294 # Jenkins expects us to use this by default.
295 CONFIGSRC="$HOME/arvados-api-server"
298 # Clean up .pyc files that may exist in the workspace
300 find -name '*.pyc' -delete
302 # Set up temporary install dirs (unless existing dirs were supplied)
303 for tmpdir in VENVDIR VENV3DIR GOPATH GEMHOME PERLINSTALLBASE
305 if [[ -n "${!tmpdir}" ]]; then
306 leave_temp[$tmpdir]=1
307 mkdir -p "${!tmpdir}"
309 eval "$tmpdir"='$(mktemp -d)'
313 setup_ruby_environment() {
314 if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
315 source "$HOME/.rvm/scripts/rvm"
317 elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
318 source "/usr/local/rvm/scripts/rvm"
324 if [[ "$using_rvm" == true ]]; then
325 # If rvm is in use, we can't just put separate "dependencies"
326 # and "gems-under-test" paths to GEM_PATH: passenger resets
327 # the environment to the "current gemset", which would lose
328 # our GEM_PATH and prevent our test suites from running ruby
329 # programs (for example, the Workbench test suite could not
330 # boot an API server or run arv). Instead, we have to make an
331 # rvm gemset and use it for everything.
333 [[ `type rvm | head -n1` == "rvm is a function" ]] \
336 # Put rvm's favorite path back in first place (overriding
337 # virtualenv, which just put itself there). Ignore rvm's
338 # complaint about not being in first place already.
339 rvm use @default 2>/dev/null
341 # Create (if needed) and switch to an @arvados-tests
342 # gemset. (Leave the choice of ruby to the caller.)
343 rvm use @arvados-tests --create \
344 || fatal 'rvm gemset setup'
348 # When our "bundle install"s need to install new gems to
349 # satisfy dependencies, we want them to go where "gem install
350 # --user-install" would put them. (However, if the caller has
351 # already set GEM_HOME, we assume that's where dependencies
352 # should be installed, and we should leave it alone.)
354 if [ -z "$GEM_HOME" ]; then
355 user_gempath="$(gem env gempath)"
356 export GEM_HOME="${user_gempath%%:*}"
358 PATH="$(gem env gemdir)/bin:$PATH"
360 # When we build and install our own gems, we install them in our
361 # $GEMHOME tmpdir, and we want them to be at the front of GEM_PATH and
362 # PATH so integration tests prefer them over other versions that
363 # happen to be installed in $user_gempath, system dirs, etc.
365 tmpdir_gem_home="$(env - PATH="$PATH" HOME="$GEMHOME" gem env gempath | cut -f1 -d:)"
366 PATH="$tmpdir_gem_home/bin:$PATH"
367 export GEM_PATH="$tmpdir_gem_home:$(gem env gempath)"
369 echo "Will install dependencies to $(gem env gemdir)"
370 echo "Will install arvados gems to $tmpdir_gem_home"
371 echo "Gem search path is GEM_PATH=$GEM_PATH"
376 if [[ "$using_rvm" == true ]]; then
379 GEM_HOME="$tmpdir_gem_home" GEM_PATH="$tmpdir_gem_home" "$@"
383 gem_uninstall_if_exists() {
384 if gem list "$1\$" | egrep '^\w'; then
385 gem uninstall --force --all --executables "$1"
389 export PERLINSTALLBASE
390 export PERLLIB="$PERLINSTALLBASE/lib/perl5:${PERLLIB:+$PERLLIB}"
393 mkdir -p "$GOPATH/src/git.curoverse.com"
394 ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
395 || fatal "symlink failed"
397 if ! [[ -e "$VENVDIR/bin/activate" ]] || ! [[ -e "$VENVDIR/bin/pip" ]]; then
398 virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed"
400 . "$VENVDIR/bin/activate"
402 if (pip install setuptools | grep setuptools-0) || [ "$($VENVDIR/bin/easy_install --version | cut -d\ -f2 | cut -d. -f1)" -lt 18 ]; then
403 pip install --upgrade setuptools pip
406 # Needed for run_test_server.py which is used by certain (non-Python) tests.
407 pip freeze 2>/dev/null | egrep ^PyYAML= \
408 || pip install PyYAML >/dev/null \
409 || fatal "pip install PyYAML failed"
411 # Preinstall forked version of libcloud, because nodemanager "pip install"
412 # won't pick it up by default.
413 pip freeze 2>/dev/null | egrep ^apache-libcloud==$LIBCLOUD_PIN \
414 || pip install --pre --ignore-installed https://github.com/curoverse/libcloud/archive/apache-libcloud-$LIBCLOUD_PIN.zip >/dev/null \
415 || fatal "pip install apache-libcloud failed"
417 # Deactivate Python 2 virtualenv
420 # If Python 3 is available, set up its virtualenv in $VENV3DIR.
421 # Otherwise, skip dependent tests.
422 PYTHON3=$(which python3)
423 if [ "0" = "$?" ]; then
424 virtualenv --python "$PYTHON3" --setuptools "$VENV3DIR" \
425 || fatal "python3 virtualenv $VENV3DIR failed"
427 . "$VENV3DIR/bin/activate"
429 if (pip install setuptools | grep setuptools-0) || [ "$($VENV3DIR/bin/easy_install --version | cut -d\ -f2 | cut -d. -f1)" -lt 18 ]; then
430 pip install --upgrade setuptools pip
433 # Deactivate Python 3 virtualenv
437 skip[services/dockercleaner]=1
440 Warning: python3 could not be found
441 services/dockercleaner install and tests will be skipped
446 # Reactivate Python 2 virtualenv
447 . "$VENVDIR/bin/activate"
449 # Note: this must be the last time we change PATH, otherwise rvm will
451 setup_ruby_environment
455 if ! which bundler >/dev/null
457 gem install --user-install bundler || fatal 'Could not install bundler'
461 if [[ "$1" != "0" ]]; then
462 title "!!!!!! $2 FAILED !!!!!!"
463 failures+=("$2 (`timer`)")
465 successes+=("$2 (`timer`)")
474 echo -n "$(($SECONDS - $t0))s"
478 while ! do_test_once ${@} && [[ "$retry" == 1 ]]
480 read -p 'Try again? [Y/n] ' x
481 if [[ "$x" != "y" ]] && [[ "$x" != "" ]]
490 if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$1" ]] )
492 title "Running $1 tests"
494 if [[ "$2" == "go" ]]
496 covername="coverage-$(echo "$1" | sed -e 's/\//_/g')"
497 coverflags=("-covermode=count" "-coverprofile=$WORKSPACE/tmp/.$covername.tmp")
498 if [[ -n "${testargs[$1]}" ]]
500 # "go test -check.vv giturl" doesn't work, but this
502 cd "$WORKSPACE/$1" && go test ${coverflags[@]} ${testargs[$1]}
504 # The above form gets verbose even when testargs is
505 # empty, so use this form in such cases:
506 go test ${coverflags[@]} "git.curoverse.com/arvados.git/$1"
509 go tool cover -html="$WORKSPACE/tmp/.$covername.tmp" -o "$WORKSPACE/tmp/$covername.html"
510 rm "$WORKSPACE/tmp/.$covername.tmp"
511 elif [[ "$2" == "pip" ]]
513 # $3 can name a path directory for us to use, including trailing
514 # slash; e.g., the bin/ subdirectory of a virtualenv.
516 && "${3}python" setup.py test ${testargs[$1]}
517 elif [[ "$2" != "" ]]
524 checkexit $result "$1 tests"
525 title "End of $1 tests (`timer`)"
528 title "Skipping $1 tests"
533 if [[ -z "$skip_install" || (-n "$only_install" && "$only_install" == "$1") ]]
535 title "Running $1 install"
537 if [[ "$2" == "go" ]]
539 go get -t "git.curoverse.com/arvados.git/$1"
540 elif [[ "$2" == "pip" ]]
542 # $3 can name a path directory for us to use, including trailing
543 # slash; e.g., the bin/ subdirectory of a virtualenv.
545 # Need to change to a different directory after creating
546 # the source dist package to avoid a pip bug.
547 # see https://arvados.org/issues/5766 for details.
549 # Also need to install twice, because if it believes the package is
550 # already installed, pip it won't install it. So the first "pip
551 # install" ensures that the dependencies are met, the second "pip
552 # install" ensures that we've actually installed the local package
555 && "${3}python" setup.py sdist rotate --keep=1 --match .tar.gz \
557 && "${3}pip" install --quiet "$WORKSPACE/$1/dist"/*.tar.gz \
558 && "${3}pip" install --quiet --no-deps --ignore-installed "$WORKSPACE/$1/dist"/*.tar.gz
559 elif [[ "$2" != "" ]]
565 checkexit $? "$1 install"
566 title "End of $1 install (`timer`)"
568 title "Skipping $1 install"
573 txt="********** $1 **********"
574 printf "\n%*s%s\n\n" $((($COLUMNS-${#txt})/2)) "" "$txt"
577 bundle_install_trylocal() {
580 echo "(Running bundle install --local. 'could not find package' messages are OK.)"
581 if ! bundle install --local --no-deployment; then
582 echo "(Running bundle install again, without --local.)"
583 bundle install --no-deployment
590 cd "$WORKSPACE/doc" \
591 && bundle_install_trylocal \
599 with_test_gemset gem_uninstall_if_exists "$gemname" \
600 && cd "$WORKSPACE/$srcpath" \
601 && bundle_install_trylocal \
602 && gem build "$gemname.gemspec" \
603 && with_test_gemset gem install --no-ri --no-rdoc $(ls -t "$gemname"-*.gem|head -n1)
607 install_gem arvados sdk/ruby
609 do_install sdk/ruby ruby_sdk
612 cd "$WORKSPACE/sdk/perl" \
613 && perl Makefile.PL INSTALL_BASE="$PERLINSTALLBASE" \
614 && make install INSTALLDIRS=perl
616 do_install sdk/perl perl_sdk
619 install_gem arvados-cli sdk/cli
621 do_install sdk/cli cli
623 install_login-sync() {
624 install_gem arvados-login-sync services/login-sync
626 do_install services/login-sync login-sync
628 # Install the Python SDK early. Various other test suites (like
629 # keepproxy) bring up run_test_server.py, which imports the arvados
630 # module. We can't actually *test* the Python SDK yet though, because
631 # its own test suite brings up some of those other programs (like
633 declare -a pythonstuff
640 for p in "${pythonstuff[@]}"
644 if [ -n "$PYTHON3" ]; then
645 do_install services/dockercleaner pip "$VENV3DIR/bin/"
648 install_apiserver() {
649 cd "$WORKSPACE/services/api" \
650 && RAILS_ENV=test bundle_install_trylocal
652 rm -f config/environments/test.rb
653 cp config/environments/test.rb.example config/environments/test.rb
655 if [ -n "$CONFIGSRC" ]
657 for f in database.yml application.yml
659 cp "$CONFIGSRC/$f" config/ || fatal "$f"
663 # Fill in a random secret_token and blob_signing_key for testing
664 SECRET_TOKEN=`echo 'puts rand(2**512).to_s(36)' |ruby`
665 BLOB_SIGNING_KEY=`echo 'puts rand(2**512).to_s(36)' |ruby`
667 sed -i'' -e "s:SECRET_TOKEN:$SECRET_TOKEN:" config/application.yml
668 sed -i'' -e "s:BLOB_SIGNING_KEY:$BLOB_SIGNING_KEY:" config/application.yml
670 # Set up empty git repo (for git tests)
672 sed -i'' -e "s:/var/cache/git:$GITDIR:" config/application.default.yml
675 mkdir -p $GITDIR/test
678 && git config user.email "jenkins@ci.curoverse.com" \
679 && git config user.name "Jenkins, CI" \
682 && git commit -m 'initial commit'
684 # Clear out any lingering postgresql connections to the test
685 # database, so that we can drop it. This assumes the current user
686 # is a postgresql superuser.
687 cd "$WORKSPACE/services/api" \
688 && test_database=$(python -c "import yaml; print yaml.load(file('config/database.yml'))['test']['database']") \
689 && psql "$test_database" -c "SELECT pg_terminate_backend (pg_stat_activity.procpid::int) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$test_database';" 2>/dev/null
691 cd "$WORKSPACE/services/api" \
692 && RAILS_ENV=test bundle exec rake db:drop \
693 && RAILS_ENV=test bundle exec rake db:setup \
694 && RAILS_ENV=test bundle exec rake db:fixtures:load
696 do_install services/api apiserver
700 services/arv-git-httpd
704 services/datamanager/summary
705 services/datamanager/collection
710 for g in "${gostuff[@]}"
715 install_workbench() {
716 cd "$WORKSPACE/apps/workbench" \
717 && mkdir -p tmp/cache \
718 && RAILS_ENV=test bundle_install_trylocal
720 do_install apps/workbench workbench
722 test_doclinkchecker() {
726 ARVADOS_API_HOST=qr1hi.arvadosapi.com
727 # Make sure python-epydoc is installed or the next line won't
729 PYTHONPATH=$WORKSPACE/sdk/python/ bundle exec rake linkchecker baseurl=file://$WORKSPACE/doc/.site/ arvados_workbench_host=https://workbench.$ARVADOS_API_HOST arvados_api_host=$ARVADOS_API_HOST
732 do_test doc doclinkchecker
737 cd "$WORKSPACE/services/api" \
738 && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[services/api]}
740 do_test services/api apiserver
742 # Shortcut for when we're only running apiserver tests. This saves a bit of time,
743 # because we don't need to start up the api server for subsequent tests.
744 if [ ! -z "$only" ] && [ "$only" == "services/api" ]; then
745 rotate_logfile "$WORKSPACE/services/api/log/" "test.log"
752 cd "$WORKSPACE/sdk/ruby" \
753 && bundle exec rake test TESTOPTS=-v ${testargs[sdk/ruby]}
755 do_test sdk/ruby ruby_sdk
758 cd "$WORKSPACE/sdk/cli" \
759 && mkdir -p /tmp/keep \
760 && KEEP_LOCAL_STORE=/tmp/keep bundle exec rake test TESTOPTS=-v ${testargs[sdk/cli]}
765 cd "$WORKSPACE/services/login-sync" \
766 && bundle exec rake test TESTOPTS=-v ${testargs[services/login-sync]}
768 do_test services/login-sync login-sync
770 for p in "${pythonstuff[@]}"
774 do_test services/dockercleaner pip "$VENV3DIR/bin/"
776 for g in "${gostuff[@]}"
782 start_nginx_proxy_services \
783 && cd "$WORKSPACE/apps/workbench" \
784 && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[apps/workbench]}
786 do_test apps/workbench workbench
788 test_workbench_benchmark() {
789 start_nginx_proxy_services \
790 && cd "$WORKSPACE/apps/workbench" \
791 && RAILS_ENV=test bundle exec rake test:benchmark ${testargs[apps/workbench_benchmark]}
793 do_test apps/workbench_benchmark workbench_benchmark
795 test_workbench_profile() {
796 start_nginx_proxy_services \
797 && cd "$WORKSPACE/apps/workbench" \
798 && RAILS_ENV=test bundle exec rake test:profile ${testargs[apps/workbench_profile]}
800 do_test apps/workbench_profile workbench_profile