a32476c5543e25ab1ea44bb19460412b1ac0cd34
[openstack-build/neutron-build.git] / run_tests.sh
1 #!/usr/bin/env bash
2
3 set -eu
4
5 function usage {
6   echo "Usage: $0 [OPTION]..."
7   echo "Run Neutron's test suite(s)"
8   echo ""
9   echo "  -V, --virtual-env           Always use virtualenv.  Install automatically if not present"
10   echo "  -N, --no-virtual-env        Don't use virtualenv.  Run tests in local environment"
11   echo "  -s, --no-site-packages      Isolate the virtualenv from the global Python environment"
12   echo "  -r, --recreate-db           Recreate the test database (deprecated, as this is now the default)."
13   echo "  -n, --no-recreate-db        Don't recreate the test database."
14   echo "  -f, --force                 Force a clean re-build of the virtual environment. Useful when dependencies have been added."
15   echo "  -u, --update                Update the virtual environment with any newer package versions"
16   echo "  -p, --pep8                  Just run PEP8 and HACKING compliance check"
17   echo "  -8, --pep8-only-changed [<basecommit>]"
18   echo "                              Just run PEP8 and HACKING compliance check on files changed since HEAD~1 (or <basecommit>)"
19   echo "  -P, --no-pep8               Don't run static code checks"
20   echo "  -c, --coverage              Generate coverage report"
21   echo "  -d, --debug                 Run tests with testtools instead of testr. This allows you to use the debugger."
22   echo "  -h, --help                  Print this usage message"
23   echo "  --virtual-env-path <path>   Location of the virtualenv directory"
24   echo "                               Default: \$(pwd)"
25   echo "  --virtual-env-name <name>   Name of the virtualenv directory"
26   echo "                               Default: .venv"
27   echo "  --tools-path <dir>          Location of the tools directory"
28   echo "                               Default: \$(pwd)"
29   echo ""
30   echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
31   echo "      If no virtualenv is found, the script will ask if you would like to create one.  If you "
32   echo "      prefer to run tests NOT in a virtual environment, simply pass the -N option."
33   exit
34 }
35
36 function process_options {
37   i=1
38   while [ $i -le $# ]; do
39     case "${!i}" in
40       -h|--help) usage;;
41       -V|--virtual-env) always_venv=1; never_venv=0;;
42       -N|--no-virtual-env) always_venv=0; never_venv=1;;
43       -s|--no-site-packages) no_site_packages=1;;
44       -r|--recreate-db) recreate_db=1;;
45       -n|--no-recreate-db) recreate_db=0;;
46       -f|--force) force=1;;
47       -u|--update) update=1;;
48       -p|--pep8) just_pep8=1;;
49       -8|--pep8-only-changed) just_pep8_changed=1;;
50       -P|--no-pep8) no_pep8=1;;
51       -c|--coverage) coverage=1;;
52       -d|--debug) debug=1;;
53       --virtual-env-path)
54         (( i++ ))
55         venv_path=${!i}
56         ;;
57       --virtual-env-name)
58         (( i++ ))
59         venv_dir=${!i}
60         ;;
61       --tools-path)
62         (( i++ ))
63         tools_path=${!i}
64         ;;
65       -*) testopts="$testopts ${!i}";;
66       *) testargs="$testargs ${!i}"
67     esac
68     (( i++ ))
69   done
70 }
71
72 tool_path=${tools_path:-$(pwd)}
73 venv_path=${venv_path:-$(pwd)}
74 venv_dir=${venv_name:-.venv}
75 with_venv=tools/with_venv.sh
76 always_venv=0
77 never_venv=0
78 force=0
79 no_site_packages=0
80 installvenvopts=
81 testargs=
82 testopts=
83 wrapper=""
84 just_pep8=0
85 just_pep8_changed=0
86 no_pep8=0
87 coverage=0
88 debug=0
89 recreate_db=1
90 update=0
91
92 LANG=en_US.UTF-8
93 LANGUAGE=en_US:en
94 LC_ALL=C
95
96 process_options $@
97 # Make our paths available to other scripts we call
98 export venv_path
99 export venv_dir
100 export venv_name
101 export tools_dir
102 export venv=${venv_path}/${venv_dir}
103
104 if [ $no_site_packages -eq 1 ]; then
105   installvenvopts="--no-site-packages"
106 fi
107
108
109 function run_tests {
110   # Cleanup *pyc
111   ${wrapper} find . -type f -name "*.pyc" -delete
112
113   if [ $debug -eq 1 ]; then
114     if [ "$testopts" = "" ] && [ "$testargs" = "" ]; then
115       # Default to running all tests if specific test is not
116       # provided.
117       testargs="discover ./neutron/tests"
118     fi
119     ${wrapper} python -m testtools.run $testopts $testargs
120
121     # Short circuit because all of the testr and coverage stuff
122     # below does not make sense when running testtools.run for
123     # debugging purposes.
124     return $?
125   fi
126
127   if [ $coverage -eq 1 ]; then
128     TESTRTESTS="$TESTRTESTS --coverage"
129   else
130     TESTRTESTS="$TESTRTESTS --slowest"
131   fi
132
133   # Just run the test suites in current environment
134   set +e
135   testargs=`echo "$testargs" | sed -e's/^\s*\(.*\)\s*$/\1/'`
136   TESTRTESTS="$TESTRTESTS --testr-args='--subunit $testopts $testargs'"
137   OS_TEST_PATH=`echo $testargs|grep -o 'neutron\.tests[^[:space:]:]\+'|tr . /`
138   if [ -n "$OS_TEST_PATH" ]; then
139       os_test_dir=$(dirname "$OS_TEST_PATH")
140   else
141       os_test_dir=''
142   fi
143   if [ -d "$OS_TEST_PATH" ]; then
144       wrapper="OS_TEST_PATH=$OS_TEST_PATH $wrapper"
145   elif [ -d "$os_test_dir" ]; then
146       wrapper="OS_TEST_PATH=$os_test_dir $wrapper"
147   fi
148   echo "Running \`${wrapper} $TESTRTESTS\`"
149   bash -c "${wrapper} $TESTRTESTS | ${wrapper} subunit2pyunit"
150   RESULT=$?
151   set -e
152
153   copy_subunit_log
154
155   if [ $coverage -eq 1 ]; then
156     echo "Generating coverage report in covhtml/"
157     # Don't compute coverage for common code, which is tested elsewhere
158     ${wrapper} coverage combine
159     ${wrapper} coverage html --include='neutron/*' --omit='neutron/openstack/common/*' -d covhtml -i
160   fi
161
162   return $RESULT
163 }
164
165 function copy_subunit_log {
166   LOGNAME=`cat .testrepository/next-stream`
167   LOGNAME=$(($LOGNAME - 1))
168   LOGNAME=".testrepository/${LOGNAME}"
169   cp $LOGNAME subunit.log
170 }
171
172 function warn_on_flake8_without_venv {
173   if [ $never_venv -eq 1 ]; then
174     echo "**WARNING**:"
175     echo "Running flake8 without virtual env may miss OpenStack HACKING detection"
176   fi
177 }
178
179 function run_pep8 {
180   echo "Running flake8 ..."
181   warn_on_flake8_without_venv
182   ${wrapper} flake8
183 }
184
185 function run_pep8_changed {
186     # NOTE(gilliard) We want use flake8 to check the entirety of every file that has
187     # a change in it. Unfortunately the --filenames argument to flake8 only accepts
188     # file *names* and there are no files named (eg) "nova/compute/manager.py".  The
189     # --diff argument behaves surprisingly as well, because although you feed it a
190     # diff, it actually checks the file on disk anyway.
191     local target=${testargs:-HEAD~1}
192     local files=$(git diff --name-only $target | tr '\n' ' ')
193     echo "Running flake8 on ${files}"
194     warn_on_flake8_without_venv
195     diff -u --from-file /dev/null ${files} | ${wrapper} flake8 --diff
196 }
197
198
199 TESTRTESTS="python setup.py testr"
200
201 if [ $never_venv -eq 0 ]
202 then
203   # Remove the virtual environment if --force used
204   if [ $force -eq 1 ]; then
205     echo "Cleaning virtualenv..."
206     rm -rf ${venv}
207   fi
208   if [ $update -eq 1 ]; then
209       echo "Updating virtualenv..."
210       python tools/install_venv.py $installvenvopts
211   fi
212   if [ -e ${venv} ]; then
213     wrapper="${with_venv}"
214   else
215     if [ $always_venv -eq 1 ]; then
216       # Automatically install the virtualenv
217       python tools/install_venv.py $installvenvopts
218       wrapper="${with_venv}"
219     else
220       echo -e "No virtual environment found...create one? (Y/n) \c"
221       read use_ve
222       if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
223         # Install the virtualenv and run the test suite in it
224         python tools/install_venv.py $installvenvopts
225         wrapper=${with_venv}
226       fi
227     fi
228   fi
229 fi
230
231 # Delete old coverage data from previous runs
232 if [ $coverage -eq 1 ]; then
233     ${wrapper} coverage erase
234 fi
235
236 if [ $just_pep8 -eq 1 ]; then
237     run_pep8
238     exit
239 fi
240
241 if [ $just_pep8_changed -eq 1 ]; then
242     run_pep8_changed
243     exit
244 fi
245
246 if [ $recreate_db -eq 1 ]; then
247     rm -f tests.sqlite
248 fi
249
250 run_tests
251
252 # NOTE(sirp): we only want to run pep8 when we're running the full-test suite,
253 # not when we're running tests individually. To handle this, we need to
254 # distinguish between options (testopts), which begin with a '-', and
255 # arguments (testargs).
256 if [ -z "$testargs" ]; then
257   if [ $no_pep8 -eq 0 ]; then
258     run_pep8
259   fi
260 fi