3 read -rd "\000" helpmessage <<EOF
4 $(basename $0): Install and test Arvados components.
6 Exit non-zero if any tests fail.
9 $(basename $0) WORKSPACE=/path/to/arvados [options]
13 --skip FOO Do not test the FOO component.
14 --only FOO Do not test anything except the FOO component.
15 --leave-temp Do not remove GOPATH, virtualenv, and other temp dirs at exit.
16 Instead, show which directories were used this time so they
17 can be reused in subsequent invocations.
18 --skip-install Do not run any install steps. Just run tests.
19 You should provide GOPATH, GEMHOME, and VENVDIR options
20 from a previous invocation if you use this option.
21 --only-install Run specific install step
22 WORKSPACE=path Arvados source tree to test.
23 CONFIGSRC=path Dir with api server config files to copy into source tree.
24 (If none given, leave config files alone in source tree.)
25 services/api_test="TEST=test/functional/arvados/v1/collections_controller_test.rb"
26 Restrict apiserver tests to the given file
27 sdk/python_test="--test-suite test.test_keep_locator"
28 Restrict Python SDK tests to the given class
29 apps/workbench_test="TEST=test/integration/pipeline_instances_test.rb"
30 Restrict Workbench tests to the given file
31 services/arv-git-httpd_test="-check.vv"
32 Show all log messages, even when tests pass (also works
33 with services/keepstore_test etc.)
35 Print more debug messages
36 envvar=value Set \$envvar to value. Primarily useful for WORKSPACE,
37 *_test, and other examples shown above.
39 Assuming --skip-install is not given, all components are installed
40 into \$GOPATH, \$VENDIR, and \$GEMHOME before running any tests. Many
41 test suites depend on other components being installed, and installing
42 everything tends to be quicker than debugging dependencies.
44 As a special concession to the current CI server config, CONFIGSRC
45 defaults to $HOME/arvados-api-server if that directory exists.
47 More information and background:
49 https://arvados.org/projects/arvados/wiki/Running_tests
54 apps/workbench_benchmark
55 apps/workbench_profile
59 services/dockercleaner
65 services/arv-git-httpd
76 # First make sure to remove any ARVADOS_ variables from the calling
77 # environment that could interfere with the tests.
78 unset $(env | cut -d= -f1 | grep \^ARVADOS_)
80 # Reset other variables that could affect our [tests'] behavior by
98 for var in VENVDIR VENV3DIR GOPATH GITDIR GEMHOME PERLINSTALLBASE
100 if [[ -z "${leave_temp[$var]}" ]]
102 if [[ -n "${!var}" ]]
107 leaving+=" $var=\"${!var}\""
110 if [[ -n "$leaving" ]]; then
111 echo "Leaving behind temp dirs: $leaving"
117 echo >&2 "Fatal: $* (encountered in ${FUNCNAME[1]} at ${BASH_SOURCE[1]} line ${BASH_LINENO[0]})"
122 for x in "${successes[@]}"
127 if [[ ${#failures[@]} == 0 ]]
129 echo "All test suites passed."
131 echo "Failures (${#failures[@]}):"
132 for x in "${failures[@]}"
141 create-plot-data-from-log.sh $BUILD_NUMBER "$WORKSPACE/apps/workbench/log/test.log" "$WORKSPACE/apps/workbench/log/"
142 rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log"
144 rotate_logfile "$WORKSPACE/services/api/log/" "test.log"
151 ( [[ -n "$WORKSPACE" ]] && [[ -d "$WORKSPACE/services" ]] ) \
152 || fatal "WORKSPACE environment variable not set to a source directory (see: $0 --help)"
153 echo Checking dependencies:
154 echo -n 'virtualenv: '
155 virtualenv --version \
156 || fatal "No virtualenv. Try: apt-get install virtualenv"
159 || fatal "No go binary. See http://golang.org/doc/install"
161 gcc --version | egrep ^gcc \
162 || fatal "No gcc. Try: apt-get install build-essential"
164 find /usr/include -wholename '*fuse/fuse.h' \
165 || fatal "No fuse/fuse.h. Try: apt-get install libfuse-dev"
166 echo -n 'pyconfig.h: '
167 find /usr/include -name pyconfig.h | egrep --max-count=1 . \
168 || fatal "No pyconfig.h. Try: apt-get install python-dev"
170 PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" nginx -v \
171 || fatal "No nginx. Try: apt-get install nginx"
173 perl -v | grep version \
174 || fatal "No perl. Try: apt-get install perl"
175 for mod in ExtUtils::MakeMaker JSON LWP Net::SSL; do
176 echo -n "perl $mod: "
177 perl -e "use $mod; print \"\$$mod::VERSION\\n\"" \
178 || fatal "No $mod. Try: apt-get install perl-modules libcrypt-ssleay-perl libjson-perl"
183 # i.e. rotate_logfile "$WORKSPACE/apps/workbench/log/" "test.log"
184 # $BUILD_NUMBER is set by Jenkins if this script is being called as part of a Jenkins run
185 if [[ -f "$1/$2" ]]; then
186 THEDATE=`date +%Y%m%d%H%M%S`
187 mv "$1/$2" "$1/$THEDATE-$BUILD_NUMBER-$2"
188 gzip "$1/$THEDATE-$BUILD_NUMBER-$2"
195 skip[apps/workbench_profile]=1
202 echo >&2 "$helpmessage"
211 only="$1"; skip[$1]=""; shift
218 only_install="$1"; shift
221 leave_temp[VENVDIR]=1
222 leave_temp[VENV3DIR]=1
224 leave_temp[GEMHOME]=1
225 leave_temp[PERLINSTALLBASE]=1
231 suite="${arg%%_test=*}"
233 testargs["$suite"]="$args"
236 eval export $(echo $arg | cut -d= -f1)=\"$(echo $arg | cut -d= -f2-)\"
239 echo >&2 "$0: Unrecognized option: '$arg'. Try: $0 --help"
246 echo 'Starting API server...'
248 && eval $(python sdk/python/tests/run_test_server.py start --auth admin) \
249 && export ARVADOS_TEST_API_HOST="$ARVADOS_API_HOST" \
250 && export ARVADOS_TEST_API_INSTALLED="$$" \
251 && (env | egrep ^ARVADOS)
254 start_nginx_proxy_services() {
255 echo 'Starting keepproxy, arv-git-httpd, and nginx ssl proxy...'
257 && python sdk/python/tests/run_test_server.py start_keep_proxy \
258 && python sdk/python/tests/run_test_server.py start_arv-git-httpd \
259 && python sdk/python/tests/run_test_server.py start_nginx \
260 && export ARVADOS_TEST_PROXY_SERVICES=1
264 if [[ -n "$ARVADOS_TEST_PROXY_SERVICES" ]]; then
265 unset ARVADOS_TEST_PROXY_SERVICES
267 && python sdk/python/tests/run_test_server.py stop_nginx \
268 && python sdk/python/tests/run_test_server.py stop_arv-git-httpd \
269 && python sdk/python/tests/run_test_server.py stop_keep_proxy
271 if [[ -n "$ARVADOS_TEST_API_HOST" ]]; then
272 unset ARVADOS_TEST_API_HOST
274 && python sdk/python/tests/run_test_server.py stop
279 failures+=("($(basename $0) interrupted)")
286 echo "WORKSPACE=$WORKSPACE"
288 if [[ -z "$CONFIGSRC" ]] && [[ -d "$HOME/arvados-api-server" ]]; then
289 # Jenkins expects us to use this by default.
290 CONFIGSRC="$HOME/arvados-api-server"
293 # Clean up .pyc files that may exist in the workspace
295 find -name '*.pyc' -delete
297 # Set up temporary install dirs (unless existing dirs were supplied)
298 for tmpdir in VENVDIR VENV3DIR GOPATH GEMHOME PERLINSTALLBASE
300 if [[ -n "${!tmpdir}" ]]; then
301 leave_temp[$tmpdir]=1
302 mkdir -p "${!tmpdir}"
304 eval "$tmpdir"='$(mktemp -d)'
308 setup_ruby_environment() {
309 if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
310 source "$HOME/.rvm/scripts/rvm"
312 elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
313 source "/usr/local/rvm/scripts/rvm"
319 if [[ "$using_rvm" == true ]]; then
320 # If rvm is in use, we can't just put separate "dependencies"
321 # and "gems-under-test" paths to GEM_PATH: passenger resets
322 # the environment to the "current gemset", which would lose
323 # our GEM_PATH and prevent our test suites from running ruby
324 # programs (for example, the Workbench test suite could not
325 # boot an API server or run arv). Instead, we have to make an
326 # rvm gemset and use it for everything.
328 [[ `type rvm | head -n1` == "rvm is a function" ]] \
331 # Put rvm's favorite path back in first place (overriding
332 # virtualenv, which just put itself there). Ignore rvm's
333 # complaint about not being in first place already.
334 rvm use @default 2>/dev/null
336 # Create (if needed) and switch to an @arvados-tests
337 # gemset. (Leave the choice of ruby to the caller.)
338 rvm use @arvados-tests --create \
339 || fatal 'rvm gemset setup'
343 # When our "bundle install"s need to install new gems to
344 # satisfy dependencies, we want them to go where "gem install
345 # --user-install" would put them. (However, if the caller has
346 # already set GEM_HOME, we assume that's where dependencies
347 # should be installed, and we should leave it alone.)
349 if [ -z "$GEM_HOME" ]; then
350 user_gempath="$(gem env gempath)"
351 export GEM_HOME="${user_gempath%%:*}"
353 PATH="$(gem env gemdir)/bin:$PATH"
355 # When we build and install our own gems, we install them in our
356 # $GEMHOME tmpdir, and we want them to be at the front of GEM_PATH and
357 # PATH so integration tests prefer them over other versions that
358 # happen to be installed in $user_gempath, system dirs, etc.
360 tmpdir_gem_home="$(env - PATH="$PATH" HOME="$GEMHOME" gem env gempath | cut -f1 -d:)"
361 PATH="$tmpdir_gem_home/bin:$PATH"
362 export GEM_PATH="$tmpdir_gem_home:$(gem env gempath)"
364 echo "Will install dependencies to $(gem env gemdir)"
365 echo "Will install arvados gems to $tmpdir_gem_home"
366 echo "Gem search path is GEM_PATH=$GEM_PATH"
371 if [[ "$using_rvm" == true ]]; then
374 GEM_HOME="$tmpdir_gem_home" GEM_PATH="$tmpdir_gem_home" "$@"
378 gem_uninstall_if_exists() {
379 if gem list "$1\$" | egrep '^\w'; then
380 gem uninstall --force --all --executables "$1"
384 export PERLINSTALLBASE
385 export PERLLIB="$PERLINSTALLBASE/lib/perl5:${PERLLIB:+$PERLLIB}"
388 mkdir -p "$GOPATH/src/git.curoverse.com"
389 ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
390 || fatal "symlink failed"
392 virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed"
393 . "$VENVDIR/bin/activate"
395 if (pip install setuptools | grep setuptools-0) || [ "$($VENVDIR/bin/easy_install --version | cut -d\ -f2 | cut -d. -f1)" -lt 18 ]; then
396 pip install --upgrade setuptools
399 # Note: this must be the last time we change PATH, otherwise rvm will
401 setup_ruby_environment
405 if ! which bundler >/dev/null
407 gem install --user-install bundler || fatal 'Could not install bundler'
410 # Needed for run_test_server.py which is used by certain (non-Python) tests.
411 pip freeze 2>/dev/null | egrep ^PyYAML= \
412 || pip install PyYAML >/dev/null \
413 || fatal "pip install PyYAML failed"
415 # If Python 3 is available, set up its virtualenv in $VENV3DIR.
416 # Otherwise, skip dependent tests.
417 PYTHON3=$(which python3)
418 if [ "0" = "$?" ]; then
419 virtualenv --python "$PYTHON3" --setuptools "$VENV3DIR" \
420 || fatal "python3 virtualenv $VENV3DIR failed"
423 skip[services/dockercleaner]=1
426 Warning: python3 could not be found
427 services/dockercleaner install and tests will be skipped
433 if [[ "$1" != "0" ]]; then
434 title "!!!!!! $2 FAILED !!!!!!"
435 failures+=("$2 (`timer`)")
437 successes+=("$2 (`timer`)")
446 echo -n "$(($SECONDS - $t0))s"
450 while ! do_test_once ${@} && [[ "$retry" == 1 ]]
452 read -p 'Try again? [Y/n] ' x
453 if [[ "$x" != "y" ]] && [[ "$x" != "" ]]
461 if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$1" ]] )
463 title "Running $1 tests"
465 if [[ "$2" == "go" ]]
467 if [[ -n "${testargs[$1]}" ]]
469 # "go test -check.vv giturl" doesn't work, but this
471 cd "$WORKSPACE/$1" && go test ${testargs[$1]}
473 # The above form gets verbose even when testargs is
474 # empty, so use this form in such cases:
475 go test "git.curoverse.com/arvados.git/$1"
477 elif [[ "$2" == "pip" ]]
479 # $3 can name a path directory for us to use, including trailing
480 # slash; e.g., the bin/ subdirectory of a virtualenv.
482 && "${3}python" setup.py test ${testargs[$1]}
483 elif [[ "$2" != "" ]]
490 checkexit $result "$1 tests"
491 title "End of $1 tests (`timer`)"
494 title "Skipping $1 tests"
499 if [[ -z "$skip_install" || (-n "$only_install" && "$only_install" == "$1") ]]
501 title "Running $1 install"
503 if [[ "$2" == "go" ]]
505 go get -t "git.curoverse.com/arvados.git/$1"
506 elif [[ "$2" == "pip" ]]
508 # $3 can name a path directory for us to use, including trailing
509 # slash; e.g., the bin/ subdirectory of a virtualenv.
511 # Need to change to a different directory after creating
512 # the source dist package to avoid a pip bug.
513 # see https://arvados.org/issues/5766 for details.
515 # Also need to install twice, because if it believes the package is
516 # already installed, pip it won't install it. So the first "pip
517 # install" ensures that the dependencies are met, the second "pip
518 # install" ensures that we've actually installed the local package
521 && "${3}python" setup.py sdist rotate --keep=1 --match .tar.gz \
523 && "${3}pip" install --quiet "$WORKSPACE/$1/dist"/*.tar.gz \
524 && "${3}pip" install --quiet --no-deps --ignore-installed "$WORKSPACE/$1/dist"/*.tar.gz
525 elif [[ "$2" != "" ]]
531 checkexit $? "$1 install"
532 title "End of $1 install (`timer`)"
534 title "Skipping $1 install"
539 txt="********** $1 **********"
540 printf "\n%*s%s\n\n" $((($COLUMNS-${#txt})/2)) "" "$txt"
543 bundle_install_trylocal() {
546 echo "(Running bundle install --local. 'could not find package' messages are OK.)"
547 if ! bundle install --local --no-deployment; then
548 echo "(Running bundle install again, without --local.)"
549 bundle install --no-deployment
556 cd "$WORKSPACE/doc" \
557 && bundle_install_trylocal \
565 with_test_gemset gem_uninstall_if_exists "$gemname" \
566 && cd "$WORKSPACE/$srcpath" \
567 && bundle_install_trylocal \
568 && gem build "$gemname.gemspec" \
569 && with_test_gemset gem install --no-ri --no-rdoc $(ls -t "$gemname"-*.gem|head -n1)
573 install_gem arvados sdk/ruby
575 do_install sdk/ruby ruby_sdk
578 cd "$WORKSPACE/sdk/perl" \
579 && perl Makefile.PL INSTALL_BASE="$PERLINSTALLBASE" \
580 && make install INSTALLDIRS=perl
582 do_install sdk/perl perl_sdk
585 install_gem arvados-cli sdk/cli
587 do_install sdk/cli cli
589 install_login-sync() {
590 install_gem arvados-login-sync services/login-sync
592 do_install services/login-sync login-sync
594 # Install the Python SDK early. Various other test suites (like
595 # keepproxy) bring up run_test_server.py, which imports the arvados
596 # module. We can't actually *test* the Python SDK yet though, because
597 # its own test suite brings up some of those other programs (like
599 declare -a pythonstuff
606 for p in "${pythonstuff[@]}"
610 if [ -n "$PYTHON3" ]; then
611 do_install services/dockercleaner pip "$VENV3DIR/bin/"
614 install_apiserver() {
615 cd "$WORKSPACE/services/api" \
616 && RAILS_ENV=test bundle_install_trylocal
618 rm -f config/environments/test.rb
619 cp config/environments/test.rb.example config/environments/test.rb
621 if [ -n "$CONFIGSRC" ]
623 for f in database.yml application.yml
625 cp "$CONFIGSRC/$f" config/ || fatal "$f"
629 # Fill in a random secret_token and blob_signing_key for testing
630 SECRET_TOKEN=`echo 'puts rand(2**512).to_s(36)' |ruby`
631 BLOB_SIGNING_KEY=`echo 'puts rand(2**512).to_s(36)' |ruby`
633 sed -i'' -e "s:SECRET_TOKEN:$SECRET_TOKEN:" config/application.yml
634 sed -i'' -e "s:BLOB_SIGNING_KEY:$BLOB_SIGNING_KEY:" config/application.yml
636 # Set up empty git repo (for git tests)
638 sed -i'' -e "s:/var/cache/git:$GITDIR:" config/application.default.yml
641 mkdir -p $GITDIR/test
644 && git config user.email "jenkins@ci.curoverse.com" \
645 && git config user.name "Jenkins, CI" \
648 && git commit -m 'initial commit'
650 # Clear out any lingering postgresql connections to the test
651 # database, so that we can drop it. This assumes the current user
652 # is a postgresql superuser.
653 cd "$WORKSPACE/services/api" \
654 && test_database=$(python -c "import yaml; print yaml.load(file('config/database.yml'))['test']['database']") \
655 && 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
657 cd "$WORKSPACE/services/api" \
658 && RAILS_ENV=test bundle exec rake db:drop \
659 && RAILS_ENV=test bundle exec rake db:setup \
660 && RAILS_ENV=test bundle exec rake db:fixtures:load
662 do_install services/api apiserver
666 services/arv-git-httpd
670 services/datamanager/summary
671 services/datamanager/collection
676 for g in "${gostuff[@]}"
681 install_workbench() {
682 cd "$WORKSPACE/apps/workbench" \
683 && mkdir -p tmp/cache \
684 && RAILS_ENV=test bundle_install_trylocal
686 do_install apps/workbench workbench
688 test_doclinkchecker() {
692 ARVADOS_API_HOST=qr1hi.arvadosapi.com
693 # Make sure python-epydoc is installed or the next line won't
695 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
698 do_test doc doclinkchecker
703 cd "$WORKSPACE/services/api" \
704 && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[services/api]}
706 do_test services/api apiserver
708 # Shortcut for when we're only running apiserver tests. This saves a bit of time,
709 # because we don't need to start up the api server for subsequent tests.
710 if [ ! -z "$only" ] && [ "$only" == "services/api" ]; then
711 rotate_logfile "$WORKSPACE/services/api/log/" "test.log"
718 cd "$WORKSPACE/sdk/ruby" \
719 && bundle exec rake test TESTOPTS=-v ${testargs[sdk/ruby]}
721 do_test sdk/ruby ruby_sdk
724 cd "$WORKSPACE/sdk/cli" \
725 && mkdir -p /tmp/keep \
726 && KEEP_LOCAL_STORE=/tmp/keep bundle exec rake test TESTOPTS=-v ${testargs[sdk/cli]}
731 cd "$WORKSPACE/services/login-sync" \
732 && bundle exec rake test TESTOPTS=-v ${testargs[services/login-sync]}
734 do_test services/login-sync login-sync
736 for p in "${pythonstuff[@]}"
740 do_test services/dockercleaner pip "$VENV3DIR/bin/"
742 for g in "${gostuff[@]}"
748 start_nginx_proxy_services \
749 && cd "$WORKSPACE/apps/workbench" \
750 && RAILS_ENV=test bundle exec rake test TESTOPTS=-v ${testargs[apps/workbench]}
752 do_test apps/workbench workbench
754 test_workbench_benchmark() {
755 start_nginx_proxy_services \
756 && cd "$WORKSPACE/apps/workbench" \
757 && RAILS_ENV=test bundle exec rake test:benchmark ${testargs[apps/workbench_benchmark]}
759 do_test apps/workbench_benchmark workbench_benchmark
761 test_workbench_profile() {
762 start_nginx_proxy_services \
763 && cd "$WORKSPACE/apps/workbench" \
764 && RAILS_ENV=test bundle exec rake test:profile ${testargs[apps/workbench_profile]}
766 do_test apps/workbench_profile workbench_profile