summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-03-20 20:05:35 +0000
committerGerrit Code Review <review@openstack.org>2019-03-20 20:05:35 +0000
commit0920f60bc994372840fa97e8014acaab619e5c7e (patch)
tree369bb660b5dcc57b06ee2f02456d1f94c8fd731e
parent15878d96f3145fc8baf4df3aa02c1f0b963a4336 (diff)
parent551e92f21666b7d5a3cdc116cc41f6fb2798707d (diff)
Merge "Drop run_tests.sh and tools/colorizer.py"HEADmaster
-rwxr-xr-xrun_tests.sh237
-rwxr-xr-xtools/colorizer.py333
2 files changed, 0 insertions, 570 deletions
diff --git a/run_tests.sh b/run_tests.sh
deleted file mode 100755
index 8164b66..0000000
--- a/run_tests.sh
+++ /dev/null
@@ -1,237 +0,0 @@
1#!/bin/bash
2
3set -eu
4
5function usage {
6 echo "Usage: $0 [OPTION]..."
7 echo "Run Manila'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 " -P, --no-pep8 Don't run static code checks"
18 echo " -c, --coverage Generate coverage report"
19 echo " -d, --debug Run tests with testtools instead of testr. This allows you to use the debugger."
20 echo " -h, --help Print this usage message"
21 echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
22 echo " --virtual-env-path <path> Location of the virtualenv directory."
23 echo " Default: \$(pwd)"
24 echo " --virtual-env-name <name> Name of the virtualenv directory."
25 echo " Default: .venv"
26 echo " --tools-path <dir> Location of the tools directory."
27 echo " Default: \$(pwd)"
28 echo " --concurrency <concurrency> How many processes to use when running the tests."
29 echo " A value of 0 autodetects concurrency from your CPU count."
30 echo " Default: 1"
31 echo ""
32 echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
33 echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
34 echo " prefer to run tests NOT in a virtual environment, simply pass the -N option."
35 exit
36}
37
38function process_options {
39 i=1
40 while [ $i -le $# ]; do
41 case "${!i}" in
42 -h|--help) usage;;
43 -V|--virtual-env) always_venv=1; never_venv=0;;
44 -N|--no-virtual-env) always_venv=0; never_venv=1;;
45 -s|--no-site-packages) no_site_packages=1;;
46 -r|--recreate-db) recreate_db=1;;
47 -n|--no-recreate-db) recreate_db=0;;
48 -f|--force) force=1;;
49 -u|--update) update=1;;
50 -p|--pep8) just_pep8=1;;
51 -P|--no-pep8) no_pep8=1;;
52 -c|--coverage) coverage=1;;
53 -d|--debug) debug=1;;
54 --virtual-env-path)
55 (( i++ ))
56 venv_path=${!i}
57 ;;
58 --virtual-env-name)
59 (( i++ ))
60 venv_dir=${!i}
61 ;;
62 --tools-path)
63 (( i++ ))
64 tools_path=${!i}
65 ;;
66 --concurrency)
67 (( i++ ))
68 concurrency=${!i}
69 ;;
70 -*) testropts="$testropts ${!i}";;
71 *) testrargs="$testrargs ${!i}"
72 esac
73 (( i++ ))
74 done
75}
76
77tool_path=${tools_path:-$(pwd)}
78venv_path=${venv_path:-$(pwd)}
79venv_dir=${venv_name:-.venv}
80with_venv=tools/with_venv.sh
81always_venv=0
82never_venv=0
83force=0
84no_site_packages=0
85installvenvopts=
86testrargs=
87testropts=
88wrapper=""
89just_pep8=0
90no_pep8=0
91coverage=0
92debug=0
93recreate_db=1
94update=0
95concurrency=1
96
97process_options $@
98# Make our paths available to other scripts we call
99export venv_path
100export venv_dir
101export venv_name
102export tools_dir
103export venv=${venv_path}/${venv_dir}
104
105if [ $no_site_packages -eq 1 ]; then
106 installvenvopts="--no-site-packages"
107fi
108
109function init_testr {
110 if [ ! -d .testrepository ]; then
111 ${wrapper} testr init
112 fi
113}
114
115function run_tests {
116 # Cleanup *pyc
117 ${wrapper} find . -type f -name "*.pyc" -delete
118
119 if [ $debug -eq 1 ]; then
120 if [ "$testropts" = "" ] && [ "$testrargs" = "" ]; then
121 # Default to running all tests if specific test is not
122 # provided.
123 testrargs="discover ./manila/tests"
124 fi
125 ${wrapper} python -m testtools.run $testropts $testrargs
126
127 # Short circuit because all of the testr and coverage stuff
128 # below does not make sense when running testtools.run for
129 # debugging purposes.
130 return $?
131 fi
132
133 if [ $coverage -eq 1 ]; then
134 TESTRTESTS="$TESTRTESTS --coverage"
135 else
136 TESTRTESTS="$TESTRTESTS"
137 fi
138
139 # Just run the test suites in current environment
140 set +e
141 testrargs=`echo "$testrargs" | sed -e's/^\s*\(.*\)\s*$/\1/'`
142 TESTRTESTS="$TESTRTESTS --testr-args='--subunit --concurrency $concurrency $testropts $testrargs'"
143 if [ setup.cfg -nt manila.egg-info/entry_points.txt ]; then
144 ${wrapper} python setup.py egg_info
145 fi
146 echo "Running \`${wrapper} $TESTRTESTS\`"
147 if ${wrapper} which subunit-2to1 2>&1 > /dev/null; then
148 # subunit-2to1 is present, testr subunit stream should be in version 2
149 # format. Convert to version one before colorizing.
150 bash -c "${wrapper} $TESTRTESTS | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py"
151 else
152 bash -c "${wrapper} $TESTRTESTS | ${wrapper} tools/colorizer.py"
153 fi
154 RESULT=$?
155 set -e
156
157 copy_subunit_log
158
159 if [ $coverage -eq 1 ]; then
160 echo "Generating coverage report in covhtml/"
161 # Don't compute coverage for common code, which is tested elsewhere
162 ${wrapper} coverage combine
163 ${wrapper} coverage html --include='manila/*' -d covhtml -i
164 fi
165
166 return $RESULT
167}
168
169function copy_subunit_log {
170 LOGNAME=`cat .testrepository/next-stream`
171 LOGNAME=$(($LOGNAME - 1))
172 LOGNAME=".testrepository/${LOGNAME}"
173 cp $LOGNAME subunit.log
174}
175
176function run_pep8 {
177 echo "Running flake8..."
178 bash -c "${wrapper} flake8"
179}
180
181TESTRTESTS="python setup.py testr"
182
183if [ $never_venv -eq 0 ]; then
184 # Remove the virtual environment if --force used
185 if [ $force -eq 1 ]; then
186 echo "Cleaning virtualenv..."
187 rm -rf ${venv}
188 fi
189 if [ $update -eq 1 ]; then
190 echo "Updating virtualenv..."
191 python tools/install_venv.py $installvenvopts
192 fi
193 if [ -e ${venv} ]; then
194 wrapper="${with_venv}"
195 else
196 if [ $always_venv -eq 1 ]; then
197 # Automatically install the virtualenv
198 python tools/install_venv.py $installvenvopts
199 wrapper="${with_venv}"
200 else
201 echo -e "No virtual environment found...create one? (Y/n) \c"
202 read use_ve
203 if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
204 # Install the virtualenv and run the test suite in it
205 python tools/install_venv.py $installvenvopts
206 wrapper=${with_venv}
207 fi
208 fi
209 fi
210fi
211
212# Delete old coverage data from previous runs
213if [ $coverage -eq 1 ]; then
214 ${wrapper} coverage erase
215fi
216
217if [ $just_pep8 -eq 1 ]; then
218 run_pep8
219 exit
220fi
221
222if [ $recreate_db -eq 1 ]; then
223 rm -f tests.sqlite
224fi
225
226init_testr
227run_tests
228
229# NOTE(sirp): we only want to run pep8 when we're running the full-test suite,
230# not when we're running tests individually. To handle this, we need to
231# distinguish between options (testropts), which begin with a '-', and
232# arguments (testrargs).
233if [ -z "$testrargs" ]; then
234 if [ $no_pep8 -eq 0 ]; then
235 run_pep8
236 fi
237fi
diff --git a/tools/colorizer.py b/tools/colorizer.py
deleted file mode 100755
index a16c620..0000000
--- a/tools/colorizer.py
+++ /dev/null
@@ -1,333 +0,0 @@
1#!/usr/bin/env python
2
3# Copyright (c) 2013, Nebula, Inc.
4# Copyright 2010 United States Government as represented by the
5# Administrator of the National Aeronautics and Space Administration.
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20# Colorizer Code is borrowed from Twisted:
21# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
22#
23# Permission is hereby granted, free of charge, to any person obtaining
24# a copy of this software and associated documentation files (the
25# "Software"), to deal in the Software without restriction, including
26# without limitation the rights to use, copy, modify, merge, publish,
27# distribute, sublicense, and/or sell copies of the Software, and to
28# permit persons to whom the Software is furnished to do so, subject to
29# the following conditions:
30#
31# The above copyright notice and this permission notice shall be
32# included in all copies or substantial portions of the Software.
33#
34# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
38# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
39# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
40# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41
42"""Display a subunit stream through a colorized unittest test runner."""
43
44import heapq
45import sys
46import unittest
47
48import six
49import subunit
50import testtools
51
52
53class _AnsiColorizer(object):
54 """Colorizer allows callers to write text in a particular color.
55
56 A colorizer is an object that loosely wraps around a stream, allowing
57 callers to write text to the stream in a particular color.
58
59 Colorizer classes must implement C{supported()} and C{write(text, color)}.
60 """
61 _colors = dict(black=30, red=31, green=32, yellow=33,
62 blue=34, magenta=35, cyan=36, white=37)
63
64 def __init__(self, stream):
65 self.stream = stream
66
67 def supported(cls, stream=sys.stdout):
68 """Check is the current platform supports coloring terminal output.
69
70 A class method that returns True if the current platform supports
71 coloring terminal output using this method. Returns False otherwise.
72 """
73 if not stream.isatty():
74 return False # auto color only on TTYs
75 try:
76 import curses
77 except ImportError:
78 return False
79 else:
80 try:
81 try:
82 return curses.tigetnum("colors") > 2
83 except curses.error:
84 curses.setupterm()
85 return curses.tigetnum("colors") > 2
86 except Exception:
87 # guess false in case of error
88 return False
89 supported = classmethod(supported)
90
91 def write(self, text, color):
92 """Write the given text to the stream in the given color.
93
94 @param text: Text to be written to the stream.
95
96 @param color: A string label for a color. e.g. 'red', 'white'.
97 """
98 color = self._colors[color]
99 self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
100
101
102class _Win32Colorizer(object):
103 """See _AnsiColorizer docstring."""
104 def __init__(self, stream):
105 import win32console
106 red, green, blue, bold = (win32console.FOREGROUND_RED,
107 win32console.FOREGROUND_GREEN,
108 win32console.FOREGROUND_BLUE,
109 win32console.FOREGROUND_INTENSITY)
110 self.stream = stream
111 self.screenBuffer = win32console.GetStdHandle(
112 win32console.STD_OUT_HANDLE)
113 self._colors = {
114 'normal': red | green | blue,
115 'red': red | bold,
116 'green': green | bold,
117 'blue': blue | bold,
118 'yellow': red | green | bold,
119 'magenta': red | blue | bold,
120 'cyan': green | blue | bold,
121 'white': red | green | blue | bold,
122 }
123
124 def supported(cls, stream=sys.stdout):
125 try:
126 import win32console
127 screenBuffer = win32console.GetStdHandle(
128 win32console.STD_OUT_HANDLE)
129 except ImportError:
130 return False
131 import pywintypes
132 try:
133 screenBuffer.SetConsoleTextAttribute(
134 win32console.FOREGROUND_RED |
135 win32console.FOREGROUND_GREEN |
136 win32console.FOREGROUND_BLUE)
137 except pywintypes.error:
138 return False
139 else:
140 return True
141 supported = classmethod(supported)
142
143 def write(self, text, color):
144 color = self._colors[color]
145 self.screenBuffer.SetConsoleTextAttribute(color)
146 self.stream.write(text)
147 self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
148
149
150class _NullColorizer(object):
151 """See _AnsiColorizer docstring."""
152 def __init__(self, stream):
153 self.stream = stream
154
155 def supported(cls, stream=sys.stdout):
156 return True
157 supported = classmethod(supported)
158
159 def write(self, text, color):
160 self.stream.write(text)
161
162
163def get_elapsed_time_color(elapsed_time):
164 if elapsed_time > 1.0:
165 return 'red'
166 elif elapsed_time > 0.25:
167 return 'yellow'
168 else:
169 return 'green'
170
171
172class OpenStackTestResult(testtools.TestResult):
173 def __init__(self, stream, descriptions, verbosity):
174 super(OpenStackTestResult, self).__init__()
175 self.stream = stream
176 self.showAll = verbosity > 1
177 self.num_slow_tests = 10
178 self.slow_tests = [] # this is a fixed-sized heap
179 self.colorizer = None
180 # NOTE(vish): reset stdout for the terminal check
181 stdout = sys.stdout
182 sys.stdout = sys.__stdout__
183 for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
184 if colorizer.supported():
185 self.colorizer = colorizer(self.stream)
186 break
187 sys.stdout = stdout
188 self.start_time = None
189 self.last_time = {}
190 self.results = {}
191 self.last_written = None
192
193 def _writeElapsedTime(self, elapsed):
194 color = get_elapsed_time_color(elapsed)
195 self.colorizer.write(" %.2f" % elapsed, color)
196
197 def _addResult(self, test, *args):
198 try:
199 name = test.id()
200 except AttributeError:
201 name = 'Unknown.unknown'
202 test_class, test_name = name.rsplit('.', 1)
203
204 elapsed = (self._now() - self.start_time).total_seconds()
205 item = (elapsed, test_class, test_name)
206 if len(self.slow_tests) >= self.num_slow_tests:
207 heapq.heappushpop(self.slow_tests, item)
208 else:
209 heapq.heappush(self.slow_tests, item)
210
211 self.results.setdefault(test_class, [])
212 self.results[test_class].append((test_name, elapsed) + args)
213 self.last_time[test_class] = self._now()
214 self.writeTests()
215
216 def _writeResult(self, test_name, elapsed, long_result, color,
217 short_result, success):
218 if self.showAll:
219 self.stream.write(' %s' % str(test_name).ljust(66))
220 self.colorizer.write(long_result, color)
221 if success:
222 self._writeElapsedTime(elapsed)
223 self.stream.writeln()
224 else:
225 self.colorizer.write(short_result, color)
226
227 def addSuccess(self, test):
228 super(OpenStackTestResult, self).addSuccess(test)
229 self._addResult(test, 'OK', 'green', '.', True)
230
231 def addFailure(self, test, err):
232 if test.id() == 'process-returncode':
233 return
234 super(OpenStackTestResult, self).addFailure(test, err)
235 self._addResult(test, 'FAIL', 'red', 'F', False)
236
237 def addError(self, test, err):
238 super(OpenStackTestResult, self).addFailure(test, err)
239 self._addResult(test, 'ERROR', 'red', 'E', False)
240
241 def addSkip(self, test, reason=None, details=None):
242 super(OpenStackTestResult, self).addSkip(test, reason, details)
243 self._addResult(test, 'SKIP', 'blue', 'S', True)
244
245 def startTest(self, test):
246 self.start_time = self._now()
247 super(OpenStackTestResult, self).startTest(test)
248
249 def writeTestCase(self, cls):
250 if not self.results.get(cls):
251 return
252 if cls != self.last_written:
253 self.colorizer.write(cls, 'white')
254 self.stream.writeln()
255 for result in self.results[cls]:
256 self._writeResult(*result)
257 del self.results[cls]
258 self.stream.flush()
259 self.last_written = cls
260
261 def writeTests(self):
262 time = self.last_time.get(self.last_written, self._now())
263 if not self.last_written or (self._now() - time).total_seconds() > 2.0:
264 diff = 3.0
265 while diff > 2.0:
266 classes = self.results.keys()
267 oldest = min(classes, key=lambda x: self.last_time[x])
268 diff = (self._now() - self.last_time[oldest]).total_seconds()
269 self.writeTestCase(oldest)
270 else:
271 self.writeTestCase(self.last_written)
272
273 def done(self):
274 self.stopTestRun()
275
276 def stopTestRun(self):
277 for cls in list(six.iterkeys(self.results)):
278 self.writeTestCase(cls)
279 self.stream.writeln()
280 self.writeSlowTests()
281
282 def writeSlowTests(self):
283 # Pare out 'fast' tests
284 slow_tests = [item for item in self.slow_tests
285 if get_elapsed_time_color(item[0]) != 'green']
286 if slow_tests:
287 slow_total_time = sum(item[0] for item in slow_tests)
288 slow = ("Slowest %i tests took %.2f secs:"
289 % (len(slow_tests), slow_total_time))
290 self.colorizer.write(slow, 'yellow')
291 self.stream.writeln()
292 last_cls = None
293 # sort by name
294 for elapsed, cls, name in sorted(slow_tests,
295 key=lambda x: x[1] + x[2]):
296 if cls != last_cls:
297 self.colorizer.write(cls, 'white')
298 self.stream.writeln()
299 last_cls = cls
300 self.stream.write(' %s' % str(name).ljust(68))
301 self._writeElapsedTime(elapsed)
302 self.stream.writeln()
303
304 def printErrors(self):
305 if self.showAll:
306 self.stream.writeln()
307 self.printErrorList('ERROR', self.errors)
308 self.printErrorList('FAIL', self.failures)
309
310 def printErrorList(self, flavor, errors):
311 for test, err in errors:
312 self.colorizer.write("=" * 70, 'red')
313 self.stream.writeln()
314 self.colorizer.write(flavor, 'red')
315 self.stream.writeln(": %s" % test.id())
316 self.colorizer.write("-" * 70, 'red')
317 self.stream.writeln()
318 self.stream.writeln("%s" % err)
319
320
321test = subunit.ProtocolTestCase(sys.stdin, passthrough=None)
322
323if sys.version_info[0:2] <= (2, 6):
324 runner = unittest.TextTestRunner(verbosity=2)
325else:
326 runner = unittest.TextTestRunner(verbosity=2,
327 resultclass=OpenStackTestResult)
328
329if runner.run(test).wasSuccessful():
330 exit_code = 0
331else:
332 exit_code = 1
333sys.exit(exit_code)