~vishvananda/nova/fix-run-tests

« back to all changes in this revision

Viewing changes to run_tests.py

  • Committer: Tarmac
  • Author(s): Vishvananda Ishaya
  • Date: 2011-02-24 00:05:44 UTC
  • mfrom: (706.5.9 lc)
  • Revision ID: tarmac-20110224000544-0usvlmcngf10fmx1
Adds colors to output of tests and cleans up run_tests.py

* sets working directory for nose to nose/tests so it loads faster
* moves db into nova/tests/test.sqlite
* deletes the db in run_tests.py instead of run_tests.sh before running tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#    See the License for the specific language governing permissions and
18
18
#    limitations under the License.
19
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.
20
41
"""Unittest runner for Nova.
21
42
 
22
43
To run all tests
47
68
from nova.tests import fake_flags
48
69
 
49
70
 
 
71
class _AnsiColorizer(object):
 
72
    """
 
73
    A colorizer is an object that loosely wraps around a stream, allowing
 
74
    callers to write text to the stream in a particular color.
 
75
 
 
76
    Colorizer classes must implement C{supported()} and C{write(text, color)}.
 
77
    """
 
78
    _colors = dict(black=30, red=31, green=32, yellow=33,
 
79
                   blue=34, magenta=35, cyan=36, white=37)
 
80
 
 
81
    def __init__(self, stream):
 
82
        self.stream = stream
 
83
 
 
84
    def supported(cls, stream=sys.stdout):
 
85
        """
 
86
        A class method that returns True if the current platform supports
 
87
        coloring terminal output using this method. Returns False otherwise.
 
88
        """
 
89
        if not stream.isatty():
 
90
            return False  # auto color only on TTYs
 
91
        try:
 
92
            import curses
 
93
        except ImportError:
 
94
            return False
 
95
        else:
 
96
            try:
 
97
                try:
 
98
                    return curses.tigetnum("colors") > 2
 
99
                except curses.error:
 
100
                    curses.setupterm()
 
101
                    return curses.tigetnum("colors") > 2
 
102
            except:
 
103
                raise
 
104
                # guess false in case of error
 
105
                return False
 
106
    supported = classmethod(supported)
 
107
 
 
108
    def write(self, text, color):
 
109
        """
 
110
        Write the given text to the stream in the given color.
 
111
 
 
112
        @param text: Text to be written to the stream.
 
113
 
 
114
        @param color: A string label for a color. e.g. 'red', 'white'.
 
115
        """
 
116
        color = self._colors[color]
 
117
        self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
 
118
 
 
119
 
 
120
class _Win32Colorizer(object):
 
121
    """
 
122
    See _AnsiColorizer docstring.
 
123
    """
 
124
    def __init__(self, stream):
 
125
        from win32console import GetStdHandle, STD_OUT_HANDLE, \
 
126
             FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
 
127
             FOREGROUND_INTENSITY
 
128
        red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
 
129
                                  FOREGROUND_BLUE, FOREGROUND_INTENSITY)
 
130
        self.stream = stream
 
131
        self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
 
132
        self._colors = {
 
133
            'normal': red | green | blue,
 
134
            'red': red | bold,
 
135
            'green': green | bold,
 
136
            'blue': blue | bold,
 
137
            'yellow': red | green | bold,
 
138
            'magenta': red | blue | bold,
 
139
            'cyan': green | blue | bold,
 
140
            'white': red | green | blue | bold
 
141
            }
 
142
 
 
143
    def supported(cls, stream=sys.stdout):
 
144
        try:
 
145
            import win32console
 
146
            screenBuffer = win32console.GetStdHandle(
 
147
                win32console.STD_OUT_HANDLE)
 
148
        except ImportError:
 
149
            return False
 
150
        import pywintypes
 
151
        try:
 
152
            screenBuffer.SetConsoleTextAttribute(
 
153
                win32console.FOREGROUND_RED |
 
154
                win32console.FOREGROUND_GREEN |
 
155
                win32console.FOREGROUND_BLUE)
 
156
        except pywintypes.error:
 
157
            return False
 
158
        else:
 
159
            return True
 
160
    supported = classmethod(supported)
 
161
 
 
162
    def write(self, text, color):
 
163
        color = self._colors[color]
 
164
        self.screenBuffer.SetConsoleTextAttribute(color)
 
165
        self.stream.write(text)
 
166
        self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
 
167
 
 
168
 
 
169
class _NullColorizer(object):
 
170
    """
 
171
    See _AnsiColorizer docstring.
 
172
    """
 
173
    def __init__(self, stream):
 
174
        self.stream = stream
 
175
 
 
176
    def supported(cls, stream=sys.stdout):
 
177
        return True
 
178
    supported = classmethod(supported)
 
179
 
 
180
    def write(self, text, color):
 
181
        self.stream.write(text)
 
182
 
 
183
 
50
184
class NovaTestResult(result.TextTestResult):
51
185
    def __init__(self, *args, **kw):
52
186
        result.TextTestResult.__init__(self, *args, **kw)
53
187
        self._last_case = None
 
188
        self.colorizer = None
 
189
        # NOTE(vish): reset stdout for the terminal check
 
190
        stdout = sys.stdout
 
191
        sys.stdout = sys.__stdout__
 
192
        for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
 
193
            if colorizer.supported():
 
194
                self.colorizer = colorizer(self.stream)
 
195
                break
 
196
        sys.stdout = stdout
54
197
 
55
198
    def getDescription(self, test):
56
199
        return str(test)
57
200
 
 
201
    # NOTE(vish): copied from unittest with edit to add color
 
202
    def addSuccess(self, test):
 
203
        unittest.TestResult.addSuccess(self, test)
 
204
        if self.showAll:
 
205
            self.colorizer.write("OK", 'green')
 
206
            self.stream.writeln()
 
207
        elif self.dots:
 
208
            self.stream.write('.')
 
209
            self.stream.flush()
 
210
 
 
211
    # NOTE(vish): copied from unittest with edit to add color
 
212
    def addFailure(self, test, err):
 
213
        unittest.TestResult.addFailure(self, test, err)
 
214
        if self.showAll:
 
215
            self.colorizer.write("FAIL", 'red')
 
216
            self.stream.writeln()
 
217
        elif self.dots:
 
218
            self.stream.write('F')
 
219
            self.stream.flush()
 
220
 
 
221
    # NOTE(vish): copied from nose with edit to add color
 
222
    def addError(self, test, err):
 
223
        """Overrides normal addError to add support for
 
224
        errorClasses. If the exception is a registered class, the
 
225
        error will be added to the list for that class, not errors.
 
226
        """
 
227
        stream = getattr(self, 'stream', None)
 
228
        ec, ev, tb = err
 
229
        try:
 
230
            exc_info = self._exc_info_to_string(err, test)
 
231
        except TypeError:
 
232
            # 2.3 compat
 
233
            exc_info = self._exc_info_to_string(err)
 
234
        for cls, (storage, label, isfail) in self.errorClasses.items():
 
235
            if result.isclass(ec) and issubclass(ec, cls):
 
236
                if isfail:
 
237
                    test.passed = False
 
238
                storage.append((test, exc_info))
 
239
                # Might get patched into a streamless result
 
240
                if stream is not None:
 
241
                    if self.showAll:
 
242
                        message = [label]
 
243
                        detail = result._exception_detail(err[1])
 
244
                        if detail:
 
245
                            message.append(detail)
 
246
                        stream.writeln(": ".join(message))
 
247
                    elif self.dots:
 
248
                        stream.write(label[:1])
 
249
                return
 
250
        self.errors.append((test, exc_info))
 
251
        test.passed = False
 
252
        if stream is not None:
 
253
            if self.showAll:
 
254
                self.colorizer.write("ERROR", 'red')
 
255
                self.stream.writeln()
 
256
            elif self.dots:
 
257
                stream.write('E')
 
258
 
58
259
    def startTest(self, test):
59
260
        unittest.TestResult.startTest(self, test)
60
261
        current_case = test.test.__class__.__name__
79
280
 
80
281
if __name__ == '__main__':
81
282
    logging.setup()
 
283
    testdir = os.path.abspath(os.path.join("nova", "tests"))
 
284
    testdb = os.path.join(testdir, "tests.sqlite")
 
285
    if os.path.exists(testdb):
 
286
        os.unlink(testdb)
82
287
    # If any argument looks like a test name but doesn't have "nova.tests" in
83
288
    # front of it, automatically add that so we don't have to type as much
84
289
    argv = []
91
296
    c = config.Config(stream=sys.stdout,
92
297
                      env=os.environ,
93
298
                      verbosity=3,
 
299
                      workingDir=testdir,
94
300
                      plugins=core.DefaultPluginManager())
95
301
 
96
302
    runner = NovaTestRunner(stream=c.stream,