Show More
@@ -35,6 +35,7 b' from nose.plugins import Plugin' | |||||
35 | from nose.util import safe_str |
|
35 | from nose.util import safe_str | |
36 |
|
36 | |||
37 | from IPython.utils.process import is_cmd_found |
|
37 | from IPython.utils.process import is_cmd_found | |
|
38 | from IPython.utils.py3compat import bytes_to_str | |||
38 | from IPython.utils.importstring import import_item |
|
39 | from IPython.utils.importstring import import_item | |
39 | from IPython.testing.plugin.ipdoctest import IPythonDoctest |
|
40 | from IPython.testing.plugin.ipdoctest import IPythonDoctest | |
40 | from IPython.external.decorators import KnownFailure, knownfailureif |
|
41 | from IPython.external.decorators import KnownFailure, knownfailureif | |
@@ -345,8 +346,9 b' class ExclusionPlugin(Plugin):' | |||||
345 | class StreamCapturer(Thread): |
|
346 | class StreamCapturer(Thread): | |
346 | daemon = True # Don't hang if main thread crashes |
|
347 | daemon = True # Don't hang if main thread crashes | |
347 | started = False |
|
348 | started = False | |
348 | def __init__(self): |
|
349 | def __init__(self, echo=False): | |
349 | super(StreamCapturer, self).__init__() |
|
350 | super(StreamCapturer, self).__init__() | |
|
351 | self.echo = echo | |||
350 | self.streams = [] |
|
352 | self.streams = [] | |
351 | self.buffer = BytesIO() |
|
353 | self.buffer = BytesIO() | |
352 | self.readfd, self.writefd = os.pipe() |
|
354 | self.readfd, self.writefd = os.pipe() | |
@@ -361,6 +363,8 b' class StreamCapturer(Thread):' | |||||
361 |
|
363 | |||
362 | with self.buffer_lock: |
|
364 | with self.buffer_lock: | |
363 | self.buffer.write(chunk) |
|
365 | self.buffer.write(chunk) | |
|
366 | if self.echo: | |||
|
367 | sys.stdout.write(bytes_to_str(chunk)) | |||
364 |
|
368 | |||
365 | os.close(self.readfd) |
|
369 | os.close(self.readfd) | |
366 | os.close(self.writefd) |
|
370 | os.close(self.writefd) |
@@ -81,18 +81,24 b' class TestController(object):' | |||||
81 | """ |
|
81 | """ | |
82 | pass |
|
82 | pass | |
83 |
|
83 | |||
84 | def launch(self, buffer_output=False): |
|
84 | def launch(self, buffer_output=False, capture_output=False): | |
85 | # print('*** ENV:', self.env) # dbg |
|
85 | # print('*** ENV:', self.env) # dbg | |
86 | # print('*** CMD:', self.cmd) # dbg |
|
86 | # print('*** CMD:', self.cmd) # dbg | |
87 | env = os.environ.copy() |
|
87 | env = os.environ.copy() | |
88 | env.update(self.env) |
|
88 | env.update(self.env) | |
89 | output = subprocess.PIPE if buffer_output else None |
|
89 | if buffer_output: | |
90 | stdout = subprocess.STDOUT if buffer_output else None |
|
90 | capture_output = True | |
91 | self.process = subprocess.Popen(self.cmd, stdout=output, |
|
91 | self.stdout_capturer = c = StreamCapturer(echo=not buffer_output) | |
92 | stderr=stdout, env=env) |
|
92 | c.start() | |
|
93 | stdout = c.writefd if capture_output else None | |||
|
94 | stderr = subprocess.STDOUT if capture_output else None | |||
|
95 | self.process = subprocess.Popen(self.cmd, stdout=stdout, | |||
|
96 | stderr=stderr, env=env) | |||
93 |
|
97 | |||
94 | def wait(self): |
|
98 | def wait(self): | |
95 |
self. |
|
99 | self.process.wait() | |
|
100 | self.stdout_capturer.halt() | |||
|
101 | self.stdout = self.stdout_capturer.get_buffer() | |||
96 | return self.process.returncode |
|
102 | return self.process.returncode | |
97 |
|
103 | |||
98 | def print_extra_info(self): |
|
104 | def print_extra_info(self): | |
@@ -224,7 +230,6 b' class JSController(TestController):' | |||||
224 |
|
230 | |||
225 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', |
|
231 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', | |
226 | 'jsonschema'] |
|
232 | 'jsonschema'] | |
227 | display_slimer_output = False |
|
|||
228 |
|
233 | |||
229 | def __init__(self, section, xunit=True, engine='phantomjs', url=None): |
|
234 | def __init__(self, section, xunit=True, engine='phantomjs', url=None): | |
230 | """Create new test runner.""" |
|
235 | """Create new test runner.""" | |
@@ -279,8 +284,7 b' class JSController(TestController):' | |||||
279 | # If the engine is SlimerJS, we need to buffer the output because |
|
284 | # If the engine is SlimerJS, we need to buffer the output because | |
280 | # SlimerJS does not support exit codes, so CasperJS always returns 0. |
|
285 | # SlimerJS does not support exit codes, so CasperJS always returns 0. | |
281 | if self.engine == 'slimerjs' and not buffer_output: |
|
286 | if self.engine == 'slimerjs' and not buffer_output: | |
282 | self.display_slimer_output = True |
|
287 | return super(JSController, self).launch(capture_output=True) | |
283 | return super(JSController, self).launch(buffer_output=True) |
|
|||
284 |
|
288 | |||
285 | else: |
|
289 | else: | |
286 | return super(JSController, self).launch(buffer_output=buffer_output) |
|
290 | return super(JSController, self).launch(buffer_output=buffer_output) | |
@@ -292,8 +296,6 b' class JSController(TestController):' | |||||
292 | # errors. Otherwise, just return the return code. |
|
296 | # errors. Otherwise, just return the return code. | |
293 | if self.engine == 'slimerjs': |
|
297 | if self.engine == 'slimerjs': | |
294 | stdout = bytes_to_str(self.stdout) |
|
298 | stdout = bytes_to_str(self.stdout) | |
295 | if self.display_slimer_output: |
|
|||
296 | print(stdout) |
|
|||
297 | if ret != 0: |
|
299 | if ret != 0: | |
298 | # This could still happen e.g. if it's stopped by SIGINT |
|
300 | # This could still happen e.g. if it's stopped by SIGINT | |
299 | return ret |
|
301 | return ret |
General Comments 0
You need to be logged in to leave comments.
Login now