Show More
@@ -50,21 +50,27 b' class TestController(object):' | |||||
50 | process = None |
|
50 | process = None | |
51 | #: str, process stdout+stderr |
|
51 | #: str, process stdout+stderr | |
52 | stdout = None |
|
52 | stdout = None | |
53 | #: bool, whether to capture process stdout & stderr |
|
|||
54 | buffer_output = False |
|
|||
55 |
|
53 | |||
56 | def __init__(self): |
|
54 | def __init__(self): | |
57 | self.cmd = [] |
|
55 | self.cmd = [] | |
58 | self.env = {} |
|
56 | self.env = {} | |
59 | self.dirs = [] |
|
57 | self.dirs = [] | |
60 |
|
58 | |||
61 |
def |
|
59 | def setup(self): | |
|
60 | """Create temporary directories etc. | |||
|
61 | ||||
|
62 | This is only called when we know the test group will be run. Things | |||
|
63 | created here may be cleaned up by self.cleanup(). | |||
|
64 | """ | |||
|
65 | pass | |||
|
66 | ||||
|
67 | def launch(self, buffer_output=False): | |||
62 | # print('*** ENV:', self.env) # dbg |
|
68 | # print('*** ENV:', self.env) # dbg | |
63 | # print('*** CMD:', self.cmd) # dbg |
|
69 | # print('*** CMD:', self.cmd) # dbg | |
64 | env = os.environ.copy() |
|
70 | env = os.environ.copy() | |
65 | env.update(self.env) |
|
71 | env.update(self.env) | |
66 |
output = subprocess.PIPE if |
|
72 | output = subprocess.PIPE if buffer_output else None | |
67 |
stdout = subprocess.STDOUT if |
|
73 | stdout = subprocess.STDOUT if buffer_output else None | |
68 | self.process = subprocess.Popen(self.cmd, stdout=output, |
|
74 | self.process = subprocess.Popen(self.cmd, stdout=output, | |
69 | stderr=stdout, env=env) |
|
75 | stderr=stdout, env=env) | |
70 |
|
76 | |||
@@ -72,6 +78,18 b' class TestController(object):' | |||||
72 | self.stdout, _ = self.process.communicate() |
|
78 | self.stdout, _ = self.process.communicate() | |
73 | return self.process.returncode |
|
79 | return self.process.returncode | |
74 |
|
80 | |||
|
81 | def print_extra_info(self): | |||
|
82 | """Print extra information about this test run. | |||
|
83 | ||||
|
84 | If we're running in parallel and showing the concise view, this is only | |||
|
85 | called if the test group fails. Otherwise, it's called before the test | |||
|
86 | group is started. | |||
|
87 | ||||
|
88 | The base implementation does nothing, but it can be overridden by | |||
|
89 | subclasses. | |||
|
90 | """ | |||
|
91 | return | |||
|
92 | ||||
75 | def cleanup_process(self): |
|
93 | def cleanup_process(self): | |
76 | """Cleanup on exit by killing any leftover processes.""" |
|
94 | """Cleanup on exit by killing any leftover processes.""" | |
77 | subp = self.process |
|
95 | subp = self.process | |
@@ -116,6 +134,8 b' class PyTestController(TestController):' | |||||
116 | # pycmd is put into cmd[2] in PyTestController.launch() |
|
134 | # pycmd is put into cmd[2] in PyTestController.launch() | |
117 | self.cmd = [sys.executable, '-c', None, section] |
|
135 | self.cmd = [sys.executable, '-c', None, section] | |
118 | self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()" |
|
136 | self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()" | |
|
137 | ||||
|
138 | def setup(self): | |||
119 | ipydir = TemporaryDirectory() |
|
139 | ipydir = TemporaryDirectory() | |
120 | self.dirs.append(ipydir) |
|
140 | self.dirs.append(ipydir) | |
121 | self.env['IPYTHONDIR'] = ipydir.name |
|
141 | self.env['IPYTHONDIR'] = ipydir.name | |
@@ -155,9 +175,9 b' class PyTestController(TestController):' | |||||
155 | self.env['COVERAGE_PROCESS_START'] = config_file |
|
175 | self.env['COVERAGE_PROCESS_START'] = config_file | |
156 | self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd |
|
176 | self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd | |
157 |
|
177 | |||
158 | def launch(self): |
|
178 | def launch(self, buffer_output=False): | |
159 | self.cmd[2] = self.pycmd |
|
179 | self.cmd[2] = self.pycmd | |
160 | super(PyTestController, self).launch() |
|
180 | super(PyTestController, self).launch(buffer_output=buffer_output) | |
161 |
|
181 | |||
162 | js_prefix = 'js/' |
|
182 | js_prefix = 'js/' | |
163 |
|
183 | |||
@@ -177,25 +197,25 b' class JSController(TestController):' | |||||
177 | """Create new test runner.""" |
|
197 | """Create new test runner.""" | |
178 | TestController.__init__(self) |
|
198 | TestController.__init__(self) | |
179 | self.section = section |
|
199 | self.section = section | |
|
200 | js_test_dir = get_js_test_dir() | |||
|
201 | includes = '--includes=' + os.path.join(js_test_dir,'util.js') | |||
|
202 | test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):]) | |||
|
203 | self.cmd = ['casperjs', 'test', includes, test_cases] | |||
180 |
|
204 | |||
181 |
|
205 | def setup(self): | ||
182 | def launch(self): |
|
|||
183 | self.ipydir = TemporaryDirectory() |
|
206 | self.ipydir = TemporaryDirectory() | |
184 | self.nbdir = TemporaryDirectory() |
|
207 | self.nbdir = TemporaryDirectory() | |
185 | print("Running %s tests in directory: %r" % (self.section, self.nbdir.name)) |
|
|||
186 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir1', u'sub βir 1a'))) |
|
|||
187 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir2', u'sub βir 1b'))) |
|
|||
188 | self.dirs.append(self.ipydir) |
|
208 | self.dirs.append(self.ipydir) | |
189 | self.dirs.append(self.nbdir) |
|
209 | self.dirs.append(self.nbdir) | |
|
210 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir1', u'sub βir 1a'))) | |||
|
211 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir2', u'sub βir 1b'))) | |||
190 |
|
212 | |||
191 | # start the ipython notebook, so we get the port number |
|
213 | # start the ipython notebook, so we get the port number | |
192 | self._init_server() |
|
214 | self._init_server() | |
193 | js_test_dir = get_js_test_dir() |
|
215 | self.cmd.append('--port=%s' % self.server_port) | |
194 | includes = '--includes=' + os.path.join(js_test_dir,'util.js') |
|
216 | ||
195 | test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):]) |
|
217 | def print_extra_info(self): | |
196 | port = '--port=' + str(self.server_port) |
|
218 | print("Running tests with notebook directory %r" % self.nbdir.name) | |
197 | self.cmd = ['casperjs', 'test', port, includes, test_cases] |
|
|||
198 | super(JSController, self).launch() |
|
|||
199 |
|
219 | |||
200 | @property |
|
220 | @property | |
201 | def will_run(self): |
|
221 | def will_run(self): | |
@@ -275,10 +295,27 b' def configure_py_controllers(controllers, xunit=False, coverage=False,' | |||||
275 | controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams |
|
295 | controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams | |
276 | controller.cmd.extend(extra_args) |
|
296 | controller.cmd.extend(extra_args) | |
277 |
|
297 | |||
278 | def do_run(controller): |
|
298 | def do_run(controller, buffer_output=True): | |
|
299 | """Setup and run a test controller. | |||
|
300 | ||||
|
301 | If buffer_output is True, no output is displayed, to avoid it appearing | |||
|
302 | interleaved. In this case, the caller is responsible for displaying test | |||
|
303 | output on failure. | |||
|
304 | ||||
|
305 | Returns | |||
|
306 | ------- | |||
|
307 | controller : TestController | |||
|
308 | The same controller as passed in, as a convenience for using map() type | |||
|
309 | APIs. | |||
|
310 | exitcode : int | |||
|
311 | The exit code of the test subprocess. Non-zero indicates failure. | |||
|
312 | """ | |||
279 | try: |
|
313 | try: | |
280 | try: |
|
314 | try: | |
281 |
controller. |
|
315 | controller.setup() | |
|
316 | if not buffer_output: | |||
|
317 | controller.print_extra_info() | |||
|
318 | controller.launch(buffer_output=buffer_output) | |||
282 | except Exception: |
|
319 | except Exception: | |
283 | import traceback |
|
320 | import traceback | |
284 | traceback.print_exc() |
|
321 | traceback.print_exc() | |
@@ -365,10 +402,6 b' def run_iptestall(options):' | |||||
365 | extra_args : list |
|
402 | extra_args : list | |
366 | Extra arguments to pass to the test subprocesses, e.g. '-v' |
|
403 | Extra arguments to pass to the test subprocesses, e.g. '-v' | |
367 | """ |
|
404 | """ | |
368 | if options.fast != 1: |
|
|||
369 | # If running in parallel, capture output so it doesn't get interleaved |
|
|||
370 | TestController.buffer_output = True |
|
|||
371 |
|
||||
372 | to_run, not_run = prepare_controllers(options) |
|
405 | to_run, not_run = prepare_controllers(options) | |
373 |
|
406 | |||
374 | def justify(ltext, rtext, width=70, fill='-'): |
|
407 | def justify(ltext, rtext, width=70, fill='-'): | |
@@ -384,9 +417,9 b' def run_iptestall(options):' | |||||
384 | if options.fast == 1: |
|
417 | if options.fast == 1: | |
385 | # This actually means sequential, i.e. with 1 job |
|
418 | # This actually means sequential, i.e. with 1 job | |
386 | for controller in to_run: |
|
419 | for controller in to_run: | |
387 |
print(' |
|
420 | print('Test group:', controller.section) | |
388 | sys.stdout.flush() # Show in correct order when output is piped |
|
421 | sys.stdout.flush() # Show in correct order when output is piped | |
389 | controller, res = do_run(controller) |
|
422 | controller, res = do_run(controller, buffer_output=False) | |
390 | if res: |
|
423 | if res: | |
391 | failed.append(controller) |
|
424 | failed.append(controller) | |
392 | if res == -signal.SIGINT: |
|
425 | if res == -signal.SIGINT: | |
@@ -400,8 +433,9 b' def run_iptestall(options):' | |||||
400 | pool = multiprocessing.pool.ThreadPool(options.fast) |
|
433 | pool = multiprocessing.pool.ThreadPool(options.fast) | |
401 | for (controller, res) in pool.imap_unordered(do_run, to_run): |
|
434 | for (controller, res) in pool.imap_unordered(do_run, to_run): | |
402 | res_string = 'OK' if res == 0 else 'FAILED' |
|
435 | res_string = 'OK' if res == 0 else 'FAILED' | |
403 |
print(justify(' |
|
436 | print(justify('Test group: ' + controller.section, res_string)) | |
404 | if res: |
|
437 | if res: | |
|
438 | controller.print_extra_info() | |||
405 | print(bytes_to_str(controller.stdout)) |
|
439 | print(bytes_to_str(controller.stdout)) | |
406 | failed.append(controller) |
|
440 | failed.append(controller) | |
407 | if res == -signal.SIGINT: |
|
441 | if res == -signal.SIGINT: | |
@@ -411,7 +445,7 b' def run_iptestall(options):' | |||||
411 | return |
|
445 | return | |
412 |
|
446 | |||
413 | for controller in not_run: |
|
447 | for controller in not_run: | |
414 |
print(justify(' |
|
448 | print(justify('Test group: ' + controller.section, 'NOT RUN')) | |
415 |
|
449 | |||
416 | t_end = time.time() |
|
450 | t_end = time.time() | |
417 | t_tests = t_end - t_start |
|
451 | t_tests = t_end - t_start | |
@@ -485,7 +519,8 b" argparser.add_argument('testgroups', nargs='*'," | |||||
485 | argparser.add_argument('--all', action='store_true', |
|
519 | argparser.add_argument('--all', action='store_true', | |
486 | help='Include slow tests not run by default.') |
|
520 | help='Include slow tests not run by default.') | |
487 | argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, |
|
521 | argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, | |
488 |
help='Run test sections in parallel.' |
|
522 | help='Run test sections in parallel. This starts as many ' | |
|
523 | 'processes as you have cores, or you can specify a number.') | |||
489 | argparser.add_argument('--xunit', action='store_true', |
|
524 | argparser.add_argument('--xunit', action='store_true', | |
490 | help='Produce Xunit XML results') |
|
525 | help='Produce Xunit XML results') | |
491 | argparser.add_argument('--coverage', nargs='?', const=True, default=False, |
|
526 | argparser.add_argument('--coverage', nargs='?', const=True, default=False, |
General Comments 0
You need to be logged in to leave comments.
Login now