4156: Merge branch 'master' into 4156-bundle-install-user
[arvados-dev.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 if [[ -f /etc/profile.d/rvm.sh ]]
66 then
67     source /etc/profile.d/rvm.sh
68 fi
69
70 declare -A leave_temp
71 clear_temp() {
72     leaving=""
73     for var in VENVDIR GOPATH GITDIR GEMHOME
74     do
75         if [[ -z "${leave_temp[$var]}" ]]
76         then
77             if [[ -n "${!var}" ]]
78             then
79                 rm -rf "${!var}"
80             fi
81         else
82             leaving+=" $var=\"${!var}\""
83         fi
84     done
85     if [[ -n "$leaving" ]]; then
86         echo "Leaving behind temp dirs: $leaving"
87     fi
88 }
89
90 fatal() {
91     clear_temp
92     echo >&2 "Fatal: $* in ${FUNCNAME[1]} at ${BASH_SOURCE[1]} line ${BASH_LINENO[0]}"
93     exit 1
94 }
95
96 report_outcomes() {
97     for x in "${successes[@]}"
98     do
99         echo "Pass: $x"
100     done
101
102     if [[ ${#failures[@]} == 0 ]]
103     then
104         echo "All test suites passed."
105     else
106         echo "Failures (${#failures[@]}):"
107         for x in "${failures[@]}"
108         do
109             echo "Fail: $x"
110         done
111     fi
112 }
113 declare -a failures
114 declare -A skip
115 declare -A testargs
116
117 while [[ -n "$1" ]]
118 do
119     arg="$1"; shift
120     case "$arg" in
121         --help)
122             echo >&2 "$helpmessage"
123             echo >&2
124             exit 1
125             ;;
126         --skip)
127             skipwhat="$1"; shift
128             skip[$skipwhat]=1
129             ;;
130         --only)
131             only="$1"; shift
132             ;;
133         --skip-install)
134             skip_install=1
135             ;;
136         --leave-temp)
137             leave_temp[VENVDIR]=1
138             leave_temp[GOPATH]=1
139             leave_temp[GEMHOME]=1
140             ;;
141         *_test=*)
142             suite="${arg%%_test=*}"
143             args="${arg#*=}"
144             testargs["$suite"]="$args"
145             ;;
146         *=*)
147             eval export $(echo $arg | cut -d= -f1)=\"$(echo $arg | cut -d= -f2-)\"
148             ;;
149         *)
150             echo >&2 "$0: Unrecognized option: '$arg'. Try: $0 --help"
151             exit 1
152             ;;
153     esac
154 done
155
156 # Sanity check
157 if ! [[ -n "$WORKSPACE" ]]; then
158   echo >&2 "$helpmessage"
159   echo >&2
160   echo >&2 "Error: WORKSPACE environment variable not set"
161   echo >&2
162   exit 1
163 fi
164
165 echo "WORKSPACE=$WORKSPACE"
166
167 if [[ -z "$CONFIGSRC" ]] && [[ -d "$HOME/arvados-api-server" ]]; then
168     # Jenkins expects us to use this by default.
169     CONFIGSRC="$HOME/arvados-api-server"
170 fi
171
172 # Clean up .pyc files that may exist in the workspace
173 cd "$WORKSPACE"
174 find -name '*.pyc' -delete
175
176 # Set up temporary install dirs (unless existing dirs were supplied)
177 for tmpdir in VENVDIR GOPATH GEMHOME
178 do
179     if [[ -n "${!tmpdir}" ]]; then
180         leave_temp[$tmpdir]=1
181     else
182         eval $tmpdir=$(mktemp -d)
183     fi
184 done
185
186 # When our "bundle install"s need to install new gems to satisfy
187 # dependencies, we want them to go where "gem install --user-install"
188 # would put them. This could be ~/.gem/..., or something rvm has set
189 # up. We don't want to install them to our GEMHOME tmpdir, though:
190 # that would mean re-downloading all dependencies each time we run
191 # tests with clean tmpdirs. The first dir in `gem env gempath` seems
192 # to give us this dir. (Note: this is a no-op if rvm is in use.)
193 user_gempath="$(gem env gempath)"
194 export GEM_HOME="${user_gempath%%:*}"
195 PATH="$(gem env gemdir)/bin:$PATH"
196
197 # Wherever "HOME=$GEMHOME gem install --user-install" installs stuff
198 # to, we want its bin to be in our PATH. (Normally, this gempath is
199 # inside our nice clean $GEMHOME, which means we can install the
200 # current version there and expect integration tests to find it before
201 # finding any other versions that happen to be installed
202 # somewhere. But if rvm is enforcing its own idea where gempath should
203 # go, we'll just assume rvm has been set up correctly rather than
204 # fight it.)
205 tmpdir_gempath="$(HOME="$GEMHOME" gem env gempath)"
206 PATH="${tmpdir_gempath%%:*}/bin:$PATH"
207
208 if ! which bundler >/dev/null
209 then
210     gem install --user-install bundler || fatal 'Could not install bundler'
211 fi
212
213 export GOPATH
214 mkdir -p "$GOPATH/src/git.curoverse.com"
215 ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
216     || fatal "symlink failed"
217
218 virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed"
219 . "$VENVDIR/bin/activate"
220
221 # Needed for run_test_server.py which is used by certain (non-Python) tests.
222 pip install PyYAML
223
224 checkexit() {
225     if [[ "$?" != "0" ]]; then
226         title "!!!!!! $1 FAILED !!!!!!"
227         failures+=("$1 (`timer`)")
228     else
229         successes+=("$1 (`timer`)")
230     fi
231 }
232
233 timer_reset() {
234     t0=$SECONDS
235 }
236
237 timer() {
238     echo -n "$(($SECONDS - $t0))s"
239 }
240
241 do_test() {
242     if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$1" ]] )
243     then
244         title "Running $1 tests"
245         timer_reset
246         if [[ "$2" == "go" ]]
247         then
248             go test "git.curoverse.com/arvados.git/$1"
249         elif [[ "$2" == "pip" ]]
250         then
251            # Other test suites can depend on tests_require
252            # dependencies of this package. For example, keepproxy runs
253            # run_test_server.py, which depends on the yaml package,
254            # which is in sdk/python's tests_require but not
255            # install_requires, and therefore does not get installed by
256            # setuptools until we run "setup.py test" *and* install the
257            # .egg files that setup.py downloads.
258            cd "$WORKSPACE/$1" \
259                 && HOME="$GEMHOME" python setup.py test ${testargs[$1]} \
260                 && (easy_install *.egg || true)
261         else
262             "test_$1"
263         fi
264         checkexit "$1 tests"
265         title "End of $1 tests (`timer`)"
266     else
267         title "Skipping $1 tests"
268     fi
269 }
270
271 do_install() {
272     if [[ -z "$skip_install" ]]
273     then
274         title "Running $1 install"
275         timer_reset
276         if [[ "$2" == "go" ]]
277         then
278             go get -t "git.curoverse.com/arvados.git/$1"
279         elif [[ "$2" == "pip" ]]
280         then
281             cd "$WORKSPACE/$1" \
282                 && python setup.py sdist rotate --keep=1 --match .tar.gz \
283                 && pip install --upgrade dist/*.tar.gz
284         else
285             "install_$1"
286         fi
287         checkexit "$1 install"
288         title "End of $1 install (`timer`)"
289     else
290         title "Skipping $1 install"
291     fi
292 }
293
294 title () {
295     txt="********** $1 **********"
296     printf "\n%*s%s\n\n" $((($COLUMNS-${#txt})/2)) "" "$txt"
297 }
298
299 install_docs() {
300     cd "$WORKSPACE/doc"
301     HOME="$GEMHOME" bundle install --no-deployment
302     rm -rf .site
303     # Make sure python-epydoc is installed or the next line won't do much good!
304     ARVADOS_API_HOST=qr1hi.arvadosapi.com
305     PYTHONPATH=$WORKSPACE/sdk/python/ HOME="$GEMHOME" bundle exec rake generate baseurl=file://$WORKSPACE/doc/.site/ arvados_workbench_host=workbench.$ARVADOS_API_HOST arvados_api_host=$ARVADOS_API_HOST
306     unset ARVADOS_API_HOST
307 }
308 do_install docs
309
310 install_ruby_sdk() {
311     cd "$WORKSPACE/sdk/ruby" \
312         && HOME="$GEMHOME" bundle install --no-deployment \
313         && HOME="$GEMHOME" gem build arvados.gemspec \
314         && HOME="$GEMHOME" gem install --user-install --no-ri --no-rdoc `ls -t arvados-*.gem|head -n1`
315 }
316 do_install ruby_sdk
317
318 install_cli() {
319     cd "$WORKSPACE/sdk/cli" \
320         && HOME="$GEMHOME" bundle install --no-deployment \
321         && HOME="$GEMHOME" gem build arvados-cli.gemspec \
322         && HOME="$GEMHOME" gem install --user-install --no-ri --no-rdoc `ls -t arvados-cli-*.gem|head -n1`
323 }
324 do_install cli
325
326 # Install the Python SDK early. Various other test suites (like
327 # keepproxy) bring up run_test_server.py, which imports the arvados
328 # module. We can't actually *test* the Python SDK yet though, because
329 # its own test suite brings up some of those other programs (like
330 # keepproxy).
331 declare -a pythonstuff
332 pythonstuff=(
333     sdk/python
334     services/fuse
335     services/nodemanager
336     )
337 for p in "${pythonstuff[@]}"
338 do
339     do_install "$p" pip
340 done
341
342 install_apiserver() {
343     cd "$WORKSPACE/services/api"
344     export RAILS_ENV=test
345     HOME="$GEMHOME" bundle install --no-deployment
346
347     rm -f config/environments/test.rb
348     cp config/environments/test.rb.example config/environments/test.rb
349
350     if [ -n "$CONFIGSRC" ]
351     then
352         for f in database.yml application.yml
353         do
354             cp "$CONFIGSRC/$f" config/ || fatal "$f"
355         done
356     fi
357
358     # Fill in a random secret_token and blob_signing_key for testing
359     SECRET_TOKEN=`echo 'puts rand(2**512).to_s(36)' |ruby`
360     BLOB_SIGNING_KEY=`echo 'puts rand(2**512).to_s(36)' |ruby`
361
362     sed -i'' -e "s:SECRET_TOKEN:$SECRET_TOKEN:" config/application.yml
363     sed -i'' -e "s:BLOB_SIGNING_KEY:$BLOB_SIGNING_KEY:" config/application.yml
364
365     # Set up empty git repo (for git tests)
366     GITDIR=$(mktemp -d)
367     sed -i'' -e "s:/var/cache/git:$GITDIR:" config/application.default.yml
368
369     rm -rf $GITDIR
370     mkdir -p $GITDIR/test
371     cd $GITDIR/test \
372         && git init \
373         && git config user.email "jenkins@ci.curoverse.com" \
374         && git config user.name "Jenkins, CI" \
375         && touch tmp \
376         && git add tmp \
377         && git commit -m 'initial commit'
378
379     # Clear out any lingering postgresql connections to arvados_test, so that we can drop it
380     # This assumes the current user is a postgresql superuser
381     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
382
383     cd "$WORKSPACE/services/api" \
384         && HOME="$GEMHOME" bundle exec rake db:drop \
385         && HOME="$GEMHOME" bundle exec rake db:create \
386         && HOME="$GEMHOME" bundle exec rake db:setup
387 }
388 do_install apiserver
389
390 declare -a gostuff
391 gostuff=(
392     services/crunchstat
393     services/keepstore
394     services/keepproxy
395     sdk/go/arvadosclient
396     sdk/go/keepclient
397     sdk/go/streamer
398     )
399 for g in "${gostuff[@]}"
400 do
401     do_install "$g" go
402 done
403
404 test_doclinkchecker() {
405     cd "$WORKSPACE/doc"
406     HOME="$GEMHOME" bundle exec rake linkchecker baseurl=file://$WORKSPACE/doc/.site/
407 }
408 do_test doclinkchecker
409
410 test_ruby_sdk() {
411     cd "$WORKSPACE/sdk/ruby" \
412         && HOME="$GEMHOME" bundle install --no-deployment \
413         && HOME="$GEMHOME" bundle exec rake test ${testargs[sdk/ruby]}
414 }
415 do_test ruby_sdk
416
417 test_cli() {
418     title "Starting SDK CLI tests"
419     cd "$WORKSPACE/sdk/cli" \
420         && HOME="$GEMHOME" bundle install --no-deployment \
421         && mkdir -p /tmp/keep \
422         && KEEP_LOCAL_STORE=/tmp/keep HOME="$GEMHOME" bundle exec rake test ${testargs[sdk/cli]}
423 }
424 do_test cli
425
426 test_apiserver() {
427     cd "$WORKSPACE/services/api"
428     HOME="$GEMHOME" bundle exec rake test ${testargs[apiserver]}
429 }
430 do_test apiserver
431
432 # We must test sdk/python before testing services/keepproxy, because
433 # keepproxy depends on sdk/python's test dependencies.
434 for p in "${pythonstuff[@]}"
435 do
436     do_test "$p" pip
437 done
438
439 for g in "${gostuff[@]}"
440 do
441     do_test "$g" go
442 done
443
444 test_workbench() {
445     cd "$WORKSPACE/apps/workbench" \
446         && HOME="$GEMHOME" bundle install --no-deployment \
447         && HOME="$GEMHOME" bundle exec rake test ${testargs[workbench]}
448 }
449 do_test workbench
450
451 report_outcomes
452 clear_temp
453
454 exit ${#failures}