##// END OF EJS Templates
Merge pull request #5326 from takluyver/iptest-gardening...
Brian E. Granger -
r15905:fa75ebe3 merge
parent child Browse files
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,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.launch()
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('IPython test group:', controller.section)
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('IPython test group: ' + controller.section, res_string))
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('IPython test group: ' + controller.section, 'NOT RUN'))
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