Use gem uninstall --force to skip dependency prompt. refs #4785
[arvados.git] / jenkins / run-tests.sh
1 #!/bin/bash
2
3 read -rd "\000" helpmessage <<EOF
4 $(basename $0): Install and test Arvados components.
5
6 Exit non-zero if any tests fail.
7
8 Syntax:
9         $(basename $0) WORKSPACE=/path/to/arvados [options]
10
11 Options:
12
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 WORKSPACE=path Arvados source tree to test.
22 CONFIGSRC=path Dir with api server config files to copy into source tree.
23                (If none given, leave config files alone in source tree.)
24 apiserver_test="TEST=test/functional/arvados/v1/collections_controller_test.rb"
25                Restrict apiserver tests to the given file
26 sdk/python_test="--test-suite test.test_keep_locator"
27                Restrict Python SDK tests to the given class
28 workbench_test="TEST=test/integration/pipeline_instances_test.rb"
29                Restrict Workbench tests to the given file
30 ARVADOS_DEBUG=1
31                Print more debug messages
32 envvar=value   Set \$envvar to value. Primarily useful for WORKSPACE,
33                *_test, and other examples shown above.
34
35 Assuming --skip-install is not given, all components are installed
36 into \$GOPATH, \$VENDIR, and \$GEMHOME before running any tests. Many
37 test suites depend on other components being installed, and installing
38 everything tends to be quicker than debugging dependencies.
39
40 As a special concession to the current CI server config, CONFIGSRC
41 defaults to $HOME/arvados-api-server if that directory exists.
42
43 More information and background:
44
45 https://arvados.org/projects/arvados/wiki/Running_tests
46 EOF
47
48 # First make sure to remove any ARVADOS_ variables from the calling
49 # environment that could interfere with the tests.
50 unset $(env | cut -d= -f1 | grep \^ARVADOS_)
51
52 # Reset other variables that could affect our [tests'] behavior by
53 # accident.
54 GITDIR=
55 GOPATH=
56 VENVDIR=
57 PYTHONPATH=
58 GEMHOME=
59
60 COLUMNS=80
61
62 leave_temp=
63 skip_install=
64
65 declare -A leave_temp
66 clear_temp() {
67     leaving=""
68     for var in VENVDIR GOPATH GITDIR GEMHOME
69     do
70         if [[ -z "${leave_temp[$var]}" ]]
71         then
72             if [[ -n "${!var}" ]]
73             then
74                 rm -rf "${!var}"
75             fi
76         else
77             leaving+=" $var=\"${!var}\""
78         fi
79     done
80     if [[ -n "$leaving" ]]; then
81         echo "Leaving behind temp dirs: $leaving"
82     fi
83 }
84
85 fatal() {
86     clear_temp
87     echo >&2 "Fatal: $* in ${FUNCNAME[1]} at ${BASH_SOURCE[1]} line ${BASH_LINENO[0]}"
88     exit 1
89 }
90
91 report_outcomes() {
92     for x in "${successes[@]}"
93     do
94         echo "Pass: $x"
95     done
96
97     if [[ ${#failures[@]} == 0 ]]
98     then
99         echo "All test suites passed."
100     else
101         echo "Failures (${#failures[@]}):"
102         for x in "${failures[@]}"
103         do
104             echo "Fail: $x"
105         done
106     fi
107 }
108 declare -a failures
109 declare -A skip
110 declare -A testargs
111
112 while [[ -n "$1" ]]
113 do
114     arg="$1"; shift
115     case "$arg" in
116         --help)
117             echo >&2 "$helpmessage"
118             echo >&2
119             exit 1
120             ;;
121         --skip)
122             skipwhat="$1"; shift
123             skip[$skipwhat]=1
124             ;;
125         --only)
126             only="$1"; shift
127             ;;
128         --skip-install)
129             skip_install=1
130             ;;
131         --leave-temp)
132             leave_temp[VENVDIR]=1
133             leave_temp[GOPATH]=1
134             leave_temp[GEMHOME]=1
135             ;;
136         *_test=*)
137             suite="${arg%%_test=*}"
138             args="${arg#*=}"
139             testargs["$suite"]="$args"
140             ;;
141         *=*)
142             eval export $(echo $arg | cut -d= -f1)=\"$(echo $arg | cut -d= -f2-)\"
143             ;;
144         *)
145             echo >&2 "$0: Unrecognized option: '$arg'. Try: $0 --help"
146             exit 1
147             ;;
148     esac
149 done
150
151 # Sanity check
152 if ! [[ -n "$WORKSPACE" ]]; then
153   echo >&2 "$helpmessage"
154   echo >&2
155   echo >&2 "Error: WORKSPACE environment variable not set"
156   echo >&2
157   exit 1
158 fi
159
160 echo "WORKSPACE=$WORKSPACE"
161
162 if [[ -z "$CONFIGSRC" ]] && [[ -d "$HOME/arvados-api-server" ]]; then
163     # Jenkins expects us to use this by default.
164     CONFIGSRC="$HOME/arvados-api-server"
165 fi
166
167 # Clean up .pyc files that may exist in the workspace
168 cd "$WORKSPACE"
169 find -name '*.pyc' -delete
170
171 # Set up temporary install dirs (unless existing dirs were supplied)
172 for tmpdir in VENVDIR GOPATH GEMHOME
173 do
174     if [[ -n "${!tmpdir}" ]]; then
175         leave_temp[$tmpdir]=1
176     else
177         eval $tmpdir=$(mktemp -d)
178     fi
179 done
180
181 setup_ruby_environment() {
182     if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
183       source "$HOME/.rvm/scripts/rvm"
184       using_rvm=true
185     elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
186       source "/usr/local/rvm/scripts/rvm"
187       using_rvm=true
188     else
189       using_rvm=false
190     fi
191
192     if [[ "$using_rvm" == true ]]; then
193         # If rvm is in use, we can't just put separate "dependencies"
194         # and "gems-under-test" paths to GEM_PATH: passenger resets
195         # the environment to the "current gemset", which would lose
196         # our GEM_PATH and prevent our test suites from running ruby
197         # programs (for example, the Workbench test suite could not
198         # boot an API server or run arv). Instead, we have to make an
199         # rvm gemset and use it for everything.
200
201         [[ `type rvm | head -n1` == "rvm is a function" ]] \
202             || fatal 'rvm check'
203
204         # Put rvm's favorite path back in first place (overriding
205         # virtualenv, which just put itself there). Ignore rvm's
206         # complaint about not being in first place already.
207         rvm use @default 2>/dev/null
208
209         # Create (if needed) and switch to an @arvados-tests
210         # gemset. (Leave the choice of ruby to the caller.)
211         rvm use @arvados-tests --create \
212             || fatal 'rvm gemset setup'
213
214         rvm env
215     else
216         # When our "bundle install"s need to install new gems to
217         # satisfy dependencies, we want them to go where "gem install
218         # --user-install" would put them. (However, if the caller has
219         # already set GEM_HOME, we assume that's where dependencies
220         # should be installed, and we should leave it alone.)
221
222         if [ -z "$GEM_HOME" ]; then
223             user_gempath="$(gem env gempath)"
224             export GEM_HOME="${user_gempath%%:*}"
225         fi
226         PATH="$(gem env gemdir)/bin:$PATH"
227
228         # When we build and install our own gems, we install them in our
229         # $GEMHOME tmpdir, and we want them to be at the front of GEM_PATH and
230         # PATH so integration tests prefer them over other versions that
231         # happen to be installed in $user_gempath, system dirs, etc.
232
233         tmpdir_gem_home="$(env - PATH="$PATH" HOME="$GEMHOME" gem env gempath | cut -f1 -d:)"
234         PATH="$tmpdir_gem_home/bin:$PATH"
235         export GEM_PATH="$tmpdir_gem_home:$(gem env gempath)"
236
237         echo "Will install dependencies to $(gem env gemdir)"
238         echo "Will install arvados gems to $tmpdir_gem_home"
239         echo "Gem search path is GEM_PATH=$GEM_PATH"
240     fi
241 }
242
243 with_test_gemset() {
244     if [[ "$using_rvm" == true ]]; then
245         "$@"
246     else
247         GEM_HOME="$tmpdir_gem_home" "$@"
248     fi
249 }
250
251 export GOPATH
252 mkdir -p "$GOPATH/src/git.curoverse.com"
253 ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
254     || fatal "symlink failed"
255
256 virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed"
257 . "$VENVDIR/bin/activate"
258
259 # Note: this must be the last time we change PATH, otherwise rvm will
260 # whine a lot.
261 setup_ruby_environment
262
263 echo "PATH is $PATH"
264
265 if ! which bundler >/dev/null
266 then
267     gem install --user-install bundler || fatal 'Could not install bundler'
268 fi
269
270 # Needed for run_test_server.py which is used by certain (non-Python) tests.
271 pip install PyYAML
272
273 checkexit() {
274     if [[ "$?" != "0" ]]; then
275         title "!!!!!! $1 FAILED !!!!!!"
276         failures+=("$1 (`timer`)")
277     else
278         successes+=("$1 (`timer`)")
279     fi
280 }
281
282 timer_reset() {
283     t0=$SECONDS
284 }
285
286 timer() {
287     echo -n "$(($SECONDS - $t0))s"
288 }
289
290 do_test() {
291     if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$1" ]] )
292     then
293         title "Running $1 tests"
294         timer_reset
295         if [[ "$2" == "go" ]]
296         then
297             go test "git.curoverse.com/arvados.git/$1"
298         elif [[ "$2" == "pip" ]]
299         then
300            # Other test suites can depend on tests_require
301            # dependencies of this package. For example, keepproxy runs
302            # run_test_server.py, which depends on the yaml package,
303            # which is in sdk/python's tests_require but not
304            # install_requires, and therefore does not get installed by
305            # setuptools until we run "setup.py test" *and* install the
306            # .egg files that setup.py downloads.
307            cd "$WORKSPACE/$1" \
308                 && python setup.py test ${testargs[$1]} \
309                 && (easy_install *.egg || true)
310         else
311             "test_$1"
312         fi
313         checkexit "$1 tests"
314         title "End of $1 tests (`timer`)"
315     else
316         title "Skipping $1 tests"
317     fi
318 }
319
320 do_install() {
321     if [[ -z "$skip_install" ]]
322     then
323         title "Running $1 install"
324         timer_reset
325         if [[ "$2" == "go" ]]
326         then
327             go get -t "git.curoverse.com/arvados.git/$1"
328         elif [[ "$2" == "pip" ]]
329         then
330             cd "$WORKSPACE/$1" \
331                 && python setup.py sdist rotate --keep=1 --match .tar.gz \
332                 && pip install --upgrade dist/*.tar.gz
333         else
334             "install_$1"
335         fi
336         checkexit "$1 install"
337         title "End of $1 install (`timer`)"
338     else
339         title "Skipping $1 install"
340     fi
341 }
342
343 title () {
344     txt="********** $1 **********"
345     printf "\n%*s%s\n\n" $((($COLUMNS-${#txt})/2)) "" "$txt"
346 }
347
348 install_docs() {
349     cd "$WORKSPACE/doc"
350     bundle install --no-deployment
351     rm -rf .site
352     # Make sure python-epydoc is installed or the next line won't do much good!
353     ARVADOS_API_HOST=qr1hi.arvadosapi.com
354     PYTHONPATH=$WORKSPACE/sdk/python/ bundle exec rake generate baseurl=file://$WORKSPACE/doc/.site/ arvados_workbench_host=workbench.$ARVADOS_API_HOST arvados_api_host=$ARVADOS_API_HOST
355     unset ARVADOS_API_HOST
356 }
357 do_install docs
358
359 install_ruby_sdk() {
360     with_test_gemset gem uninstall --force --all --executables arvados \
361         && cd "$WORKSPACE/sdk/ruby" \
362         && bundle install --no-deployment \
363         && gem build arvados.gemspec \
364         && with_test_gemset gem install --no-ri --no-rdoc `ls -t arvados-*.gem|head -n1`
365 }
366 do_install ruby_sdk
367
368 install_cli() {
369     with_test_gemset gem uninstall --force --all --executables arvados-cli \
370         && cd "$WORKSPACE/sdk/cli" \
371         && bundle install --no-deployment \
372         && gem build arvados-cli.gemspec \
373         && with_test_gemset gem install --no-ri --no-rdoc `ls -t arvados-cli-*.gem|head -n1`
374 }
375 do_install cli
376
377 # Install the Python SDK early. Various other test suites (like
378 # keepproxy) bring up run_test_server.py, which imports the arvados
379 # module. We can't actually *test* the Python SDK yet though, because
380 # its own test suite brings up some of those other programs (like
381 # keepproxy).
382 declare -a pythonstuff
383 pythonstuff=(
384     sdk/python
385     services/fuse
386     services/nodemanager
387     )
388 for p in "${pythonstuff[@]}"
389 do
390     do_install "$p" pip
391 done
392
393 install_apiserver() {
394     cd "$WORKSPACE/services/api"
395     export RAILS_ENV=test
396     bundle install --no-deployment
397
398     rm -f config/environments/test.rb
399     cp config/environments/test.rb.example config/environments/test.rb
400
401     if [ -n "$CONFIGSRC" ]
402     then
403         for f in database.yml application.yml
404         do
405             cp "$CONFIGSRC/$f" config/ || fatal "$f"
406         done
407     fi
408
409     # Fill in a random secret_token and blob_signing_key for testing
410     SECRET_TOKEN=`echo 'puts rand(2**512).to_s(36)' |ruby`
411     BLOB_SIGNING_KEY=`echo 'puts rand(2**512).to_s(36)' |ruby`
412
413     sed -i'' -e "s:SECRET_TOKEN:$SECRET_TOKEN:" config/application.yml
414     sed -i'' -e "s:BLOB_SIGNING_KEY:$BLOB_SIGNING_KEY:" config/application.yml
415
416     # Set up empty git repo (for git tests)
417     GITDIR=$(mktemp -d)
418     sed -i'' -e "s:/var/cache/git:$GITDIR:" config/application.default.yml
419
420     rm -rf $GITDIR
421     mkdir -p $GITDIR/test
422     cd $GITDIR/test \
423         && git init \
424         && git config user.email "jenkins@ci.curoverse.com" \
425         && git config user.name "Jenkins, CI" \
426         && touch tmp \
427         && git add tmp \
428         && git commit -m 'initial commit'
429
430     # Clear out any lingering postgresql connections to arvados_test, so that we can drop it
431     # This assumes the current user is a postgresql superuser
432     psql arvados_test -c "SELECT pg_terminate_backend (pg_stat_activity.procpid::int) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'arvados_test';" 2>/dev/null
433
434     cd "$WORKSPACE/services/api" \
435         && bundle exec rake db:drop \
436         && bundle exec rake db:create \
437         && bundle exec rake db:setup
438 }
439 do_install apiserver
440
441 declare -a gostuff
442 gostuff=(
443     services/crunchstat
444     services/keepstore
445     services/keepproxy
446     sdk/go/arvadosclient
447     sdk/go/keepclient
448     sdk/go/streamer
449     )
450 for g in "${gostuff[@]}"
451 do
452     do_install "$g" go
453 done
454
455 install_workbench() {
456     cd "$WORKSPACE/apps/workbench" \
457         && RAILS_ENV=test bundle install --no-deployment
458 }
459 do_install workbench
460
461 test_doclinkchecker() {
462     cd "$WORKSPACE/doc"
463     bundle exec rake linkchecker baseurl=file://$WORKSPACE/doc/.site/
464 }
465 do_test doclinkchecker
466
467 test_ruby_sdk() {
468     cd "$WORKSPACE/sdk/ruby" \
469         && bundle install --no-deployment \
470         && bundle exec rake test ${testargs[sdk/ruby]}
471 }
472 do_test ruby_sdk
473
474 test_cli() {
475     title "Starting SDK CLI tests"
476     cd "$WORKSPACE/sdk/cli" \
477         && bundle install --no-deployment \
478         && mkdir -p /tmp/keep \
479         && KEEP_LOCAL_STORE=/tmp/keep bundle exec rake test ${testargs[sdk/cli]}
480 }
481 do_test cli
482
483 test_apiserver() {
484     cd "$WORKSPACE/services/api"
485     bundle exec rake test ${testargs[apiserver]}
486 }
487 do_test apiserver
488
489 # We must test sdk/python before testing services/keepproxy, because
490 # keepproxy depends on sdk/python's test dependencies.
491 for p in "${pythonstuff[@]}"
492 do
493     do_test "$p" pip
494 done
495
496 for g in "${gostuff[@]}"
497 do
498     do_test "$g" go
499 done
500
501 test_workbench() {
502     cd "$WORKSPACE/apps/workbench" \
503         && bundle exec rake test ${testargs[workbench]}
504 }
505 do_test workbench
506
507 test_workbench_performance() {
508     cd "$WORKSPACE/apps/workbench" \
509         && bundle exec rake test:benchmark
510 }
511 do_test workbench_performance
512
513 report_outcomes
514 clear_temp
515
516 exit ${#failures}