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