##// END OF EJS Templates
Refactor TestController API to allow it to display extra info....
Thomas Kluyver -
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 launch(self):
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 self.buffer_output else None
72 output = subprocess.PIPE if buffer_output else None
67 stdout = subprocess.STDOUT if self.buffer_output else None
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,14 +78,17 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
75 def dump_failure(self):
81 def print_extra_info(self):
76 """Print buffered results of a test failure.
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.
77
87
78 Called after tests fail while running in parallel. The base
88 The base implementation does nothing, but it can be overridden by
79 implementation just prints the output from the test subprocess, but
89 subclasses.
80 subclasses can override it to add extra information.
81 """
90 """
82 print(self.stdout)
91 return
83
92
84 def cleanup_process(self):
93 def cleanup_process(self):
85 """Cleanup on exit by killing any leftover processes."""
94 """Cleanup on exit by killing any leftover processes."""
@@ -125,6 +134,8 b' class PyTestController(TestController):'
125 # pycmd is put into cmd[2] in PyTestController.launch()
134 # pycmd is put into cmd[2] in PyTestController.launch()
126 self.cmd = [sys.executable, '-c', None, section]
135 self.cmd = [sys.executable, '-c', None, section]
127 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):
128 ipydir = TemporaryDirectory()
139 ipydir = TemporaryDirectory()
129 self.dirs.append(ipydir)
140 self.dirs.append(ipydir)
130 self.env['IPYTHONDIR'] = ipydir.name
141 self.env['IPYTHONDIR'] = ipydir.name
@@ -164,9 +175,9 b' class PyTestController(TestController):'
164 self.env['COVERAGE_PROCESS_START'] = config_file
175 self.env['COVERAGE_PROCESS_START'] = config_file
165 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
176 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
166
177
167 def launch(self):
178 def launch(self, buffer_output=False):
168 self.cmd[2] = self.pycmd
179 self.cmd[2] = self.pycmd
169 super(PyTestController, self).launch()
180 super(PyTestController, self).launch(buffer_output=buffer_output)
170
181
171 js_prefix = 'js/'
182 js_prefix = 'js/'
172
183
@@ -187,14 +198,13 b' class JSController(TestController):'
187 TestController.__init__(self)
198 TestController.__init__(self)
188 self.section = section
199 self.section = section
189
200
190
201 def setup(self):
191 def launch(self):
192 self.ipydir = TemporaryDirectory()
202 self.ipydir = TemporaryDirectory()
193 self.nbdir = TemporaryDirectory()
203 self.nbdir = TemporaryDirectory()
194 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir1', u'sub βˆ‚ir 1a')))
195 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir2', u'sub βˆ‚ir 1b')))
196 self.dirs.append(self.ipydir)
204 self.dirs.append(self.ipydir)
197 self.dirs.append(self.nbdir)
205 self.dirs.append(self.nbdir)
206 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir1', u'sub βˆ‚ir 1a')))
207 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir2', u'sub βˆ‚ir 1b')))
198
208
199 # start the ipython notebook, so we get the port number
209 # start the ipython notebook, so we get the port number
200 self._init_server()
210 self._init_server()
@@ -203,7 +213,9 b' class JSController(TestController):'
203 test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):])
213 test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):])
204 port = '--port=' + str(self.server_port)
214 port = '--port=' + str(self.server_port)
205 self.cmd = ['casperjs', 'test', port, includes, test_cases]
215 self.cmd = ['casperjs', 'test', port, includes, test_cases]
206 super(JSController, self).launch()
216
217 def print_extra_info(self):
218 print("Running tests with notebook directory %r" % self.nbdir.name)
207
219
208 @property
220 @property
209 def will_run(self):
221 def will_run(self):
@@ -216,10 +228,6 b' class JSController(TestController):'
216 self.server.start()
228 self.server.start()
217 self.server_port = q.get()
229 self.server_port = q.get()
218
230
219 def dump_failure(self):
220 print("Ran tests with notebook directory %r" % self.nbdir.name)
221 super(JSController, self).dump_failure()
222
223 def cleanup(self):
231 def cleanup(self):
224 self.server.terminate()
232 self.server.terminate()
225 self.server.join()
233 self.server.join()
@@ -287,10 +295,27 b' def configure_py_controllers(controllers, xunit=False, coverage=False,'
287 controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams
295 controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams
288 controller.cmd.extend(extra_args)
296 controller.cmd.extend(extra_args)
289
297
290 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 """
291 try:
313 try:
292 try:
314 try:
293 controller.launch()
315 controller.setup()
316 if not buffer_output:
317 controller.print_extra_info()
318 controller.launch(buffer_output=buffer_output)
294 except Exception:
319 except Exception:
295 import traceback
320 import traceback
296 traceback.print_exc()
321 traceback.print_exc()
@@ -377,10 +402,6 b' def run_iptestall(options):'
377 extra_args : list
402 extra_args : list
378 Extra arguments to pass to the test subprocesses, e.g. '-v'
403 Extra arguments to pass to the test subprocesses, e.g. '-v'
379 """
404 """
380 if options.fast != 1:
381 # If running in parallel, capture output so it doesn't get interleaved
382 TestController.buffer_output = True
383
384 to_run, not_run = prepare_controllers(options)
405 to_run, not_run = prepare_controllers(options)
385
406
386 def justify(ltext, rtext, width=70, fill='-'):
407 def justify(ltext, rtext, width=70, fill='-'):
@@ -398,7 +419,7 b' def run_iptestall(options):'
398 for controller in to_run:
419 for controller in to_run:
399 print('IPython test group:', controller.section)
420 print('IPython test group:', controller.section)
400 sys.stdout.flush() # Show in correct order when output is piped
421 sys.stdout.flush() # Show in correct order when output is piped
401 controller, res = do_run(controller)
422 controller, res = do_run(controller, buffer_output=False)
402 if res:
423 if res:
403 failed.append(controller)
424 failed.append(controller)
404 if res == -signal.SIGINT:
425 if res == -signal.SIGINT:
@@ -414,7 +435,8 b' def run_iptestall(options):'
414 res_string = 'OK' if res == 0 else 'FAILED'
435 res_string = 'OK' if res == 0 else 'FAILED'
415 print(justify('Test group: ' + controller.section, res_string))
436 print(justify('Test group: ' + controller.section, res_string))
416 if res:
437 if res:
417 controller.dump_failure()
438 controller.print_extra_info()
439 print(bytes_to_str(controller.stdout))
418 failed.append(controller)
440 failed.append(controller)
419 if res == -signal.SIGINT:
441 if res == -signal.SIGINT:
420 print("Interrupted")
442 print("Interrupted")
General Comments 0
You need to be logged in to leave comments. Login now