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