97cb27b21d8f360a228931fe046685e74875fcdf
[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 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 PATH="$GEMHOME/.gem/ruby/2.1.0/bin:$PATH"
186 export GOPATH
187 mkdir -p "$GOPATH/src/git.curoverse.com"
188 ln -sfn "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
189     || fatal "symlink failed"
190
191 virtualenv --setuptools "$VENVDIR" || fatal "virtualenv $VENVDIR failed"
192 . "$VENVDIR/bin/activate"
193
194 # Needed for run_test_server.py which is used by certain (non-Python) tests.
195 pip install PyYAML
196
197 checkexit() {
198     if [[ "$?" != "0" ]]; then
199         title "!!!!!! $1 FAILED !!!!!!"
200         failures+=("$1 (`timer`)")
201     else
202         successes+=("$1 (`timer`)")
203     fi
204 }
205
206 timer_reset() {
207     t0=$SECONDS
208 }
209
210 timer() {
211     echo -n "$(($SECONDS - $t0))s"
212 }
213
214 do_test() {
215     if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$1" ]] )
216     then
217         title "Running $1 tests"
218         timer_reset
219         if [[ "$2" == "go" ]]
220         then
221             go test "git.curoverse.com/arvados.git/$1"
222         elif [[ "$2" == "pip" ]]
223         then
224            # Other test suites can depend on tests_require
225            # dependencies of this package. For example, keepproxy runs
226            # run_test_server.py, which depends on the yaml package,
227            # which is in sdk/python's tests_require but not
228            # install_requires, and therefore does not get installed by
229            # setuptools until we run "setup.py test" *and* install the
230            # .egg files that setup.py downloads.
231            cd "$WORKSPACE/$1" \
232                 && HOME="$GEMHOME" python setup.py test ${testargs[$1]} \
233                 && (easy_install *.egg || true)
234         else
235             "test_$1"
236         fi
237         checkexit "$1 tests"
238         title "End of $1 tests (`timer`)"
239     else
240         title "Skipping $1 tests"
241     fi
242 }
243
244 do_install() {
245     if [[ -z "$skip_install" ]]
246     then
247         title "Running $1 install"
248         timer_reset
249         if [[ "$2" == "go" ]]
250         then
251             go get -t "git.curoverse.com/arvados.git/$1"
252         elif [[ "$2" == "pip" ]]
253         then
254             cd "$WORKSPACE/$1" \
255                 && python setup.py sdist rotate --keep=1 --match .tar.gz \
256                 && pip install --upgrade dist/*.tar.gz
257         else
258             "install_$1"
259         fi
260         checkexit "$1 install"
261         title "End of $1 install (`timer`)"
262     else
263         title "Skipping $1 install"
264     fi
265 }
266
267 title () {
268     txt="********** $1 **********"
269     printf "\n%*s%s\n\n" $((($COLUMNS-${#txt})/2)) "" "$txt"
270 }
271
272 install_docs() {
273     cd "$WORKSPACE/doc"
274     HOME="$GEMHOME" bundle install --no-deployment
275     rm -rf .site
276     # Make sure python-epydoc is installed or the next line won't do much good!
277     ARVADOS_API_HOST=qr1hi.arvadosapi.com
278     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
279     unset ARVADOS_API_HOST
280 }
281 do_install docs
282
283 install_ruby_sdk() {
284     cd "$WORKSPACE/sdk/ruby" \
285         && HOME="$GEMHOME" bundle install --no-deployment \
286         && gem build arvados.gemspec \
287         && HOME="$GEMHOME" gem install --user-install --no-ri --no-rdoc `ls -t arvados-*.gem|head -n1`
288 }
289 do_install ruby_sdk
290
291 install_cli() {
292     cd "$WORKSPACE/sdk/cli" \
293         && gem build arvados-cli.gemspec \
294         && HOME="$GEMHOME" gem install --user-install --no-ri --no-rdoc `ls -t arvados-cli-*.gem|head -n1`
295 }
296 do_install cli
297
298 # Install the Python SDK early. Various other test suites (like
299 # keepproxy) bring up run_test_server.py, which imports the arvados
300 # module. We can't actually *test* the Python SDK yet though, because
301 # its own test suite brings up some of those other programs (like
302 # keepproxy).
303 declare -a pythonstuff
304 pythonstuff=(
305     sdk/python
306     services/fuse
307     services/nodemanager
308     )
309 for p in "${pythonstuff[@]}"
310 do
311     do_install "$p" pip
312 done
313
314 install_apiserver() {
315     cd "$WORKSPACE/services/api"
316     export RAILS_ENV=test
317     HOME="$GEMHOME" bundle install --no-deployment
318
319     rm -f config/environments/test.rb
320     cp config/environments/test.rb.example config/environments/test.rb
321
322     if [ -n "$CONFIGSRC" ]
323     then
324         for f in database.yml application.yml
325         do
326             cp "$CONFIGSRC/$f" config/ || fatal "$f"
327         done
328     fi
329
330     # Fill in a random secret_token and blob_signing_key for testing
331     SECRET_TOKEN=`echo 'puts rand(2**512).to_s(36)' |ruby`
332     BLOB_SIGNING_KEY=`echo 'puts rand(2**512).to_s(36)' |ruby`
333
334     sed -i'' -e "s:SECRET_TOKEN:$SECRET_TOKEN:" config/application.yml
335     sed -i'' -e "s:BLOB_SIGNING_KEY:$BLOB_SIGNING_KEY:" config/application.yml
336
337     # Set up empty git repo (for git tests)
338     GITDIR=$(mktemp -d)
339     sed -i'' -e "s:/var/cache/git:$GITDIR:" config/application.default.yml
340
341     rm -rf $GITDIR
342     mkdir -p $GITDIR/test
343     cd $GITDIR/test \
344         && git init \
345         && git config user.email "jenkins@ci.curoverse.com" \
346         && git config user.name "Jenkins, CI" \
347         && touch tmp \
348         && git add tmp \
349         && git commit -m 'initial commit'
350
351     # Clear out any lingering postgresql connections to arvados_test, so that we can drop it
352     # This assumes the current user is a postgresql superuser
353     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
354
355     cd "$WORKSPACE/services/api" \
356         && HOME="$GEMHOME" bundle exec rake db:drop \
357         && HOME="$GEMHOME" bundle exec rake db:create \
358         && HOME="$GEMHOME" bundle exec rake db:setup
359 }
360 do_install apiserver
361
362 declare -a gostuff
363 gostuff=(
364     services/crunchstat
365     services/keepstore
366     services/keepproxy
367     sdk/go/arvadosclient
368     sdk/go/keepclient
369     sdk/go/streamer
370     )
371 for g in "${gostuff[@]}"
372 do
373     do_install "$g" go
374 done
375
376 test_doclinkchecker() {
377     cd "$WORKSPACE/doc"
378     HOME="$GEMHOME" bundle exec rake linkchecker baseurl=file://$WORKSPACE/doc/.site/
379 }
380 do_test doclinkchecker
381
382 test_ruby_sdk() {
383     cd "$WORKSPACE/sdk/ruby" \
384         && HOME="$GEMHOME" bundle install --no-deployment \
385         && HOME="$GEMHOME" bundle exec rake test ${testargs[sdk/ruby]}
386 }
387 do_test ruby_sdk
388
389 test_cli() {
390     title "Starting SDK CLI tests"
391     cd "$WORKSPACE/sdk/cli" \
392         && HOME="$GEMHOME" bundle install --no-deployment \
393         && mkdir -p /tmp/keep \
394         && KEEP_LOCAL_STORE=/tmp/keep HOME="$GEMHOME" bundle exec rake test ${testargs[sdk/cli]}
395 }
396 do_test cli
397
398 test_apiserver() {
399     cd "$WORKSPACE/services/api"
400     HOME="$GEMHOME" bundle exec rake test ${testargs[apiserver]}
401 }
402 do_test apiserver
403
404 # We must test sdk/python before testing services/keepproxy, because
405 # keepproxy depends on sdk/python's test dependencies.
406 for p in "${pythonstuff[@]}"
407 do
408     do_test "$p" pip
409 done
410
411 for g in "${gostuff[@]}"
412 do
413     do_test "$g" go
414 done
415
416 test_workbench() {
417     cd "$WORKSPACE/apps/workbench" \
418         && HOME="$GEMHOME" bundle install --no-deployment \
419         && HOME="$GEMHOME" bundle exec rake test ${testargs[workbench]}
420 }
421 do_test workbench
422
423 report_outcomes
424 clear_temp
425
426 exit ${#failures}