Show More
@@ -34,7 +34,6 b' from nose.core import TestProgram' | |||||
34 | from nose.plugins import Plugin |
|
34 | 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 |
|
|||
38 | from IPython.utils.py3compat import bytes_to_str |
|
37 | from IPython.utils.py3compat import bytes_to_str | |
39 | from IPython.utils.importstring import import_item |
|
38 | from IPython.utils.importstring import import_item | |
40 | from IPython.testing.plugin.ipdoctest import IPythonDoctest |
|
39 | from IPython.testing.plugin.ipdoctest import IPythonDoctest | |
@@ -132,9 +131,6 b" have['requests'] = test_for('requests')" | |||||
132 | have['sphinx'] = test_for('sphinx') |
|
131 | have['sphinx'] = test_for('sphinx') | |
133 | have['jsonschema'] = test_for('jsonschema') |
|
132 | have['jsonschema'] = test_for('jsonschema') | |
134 | have['terminado'] = test_for('terminado') |
|
133 | have['terminado'] = test_for('terminado') | |
135 | have['casperjs'] = is_cmd_found('casperjs') |
|
|||
136 | have['phantomjs'] = is_cmd_found('phantomjs') |
|
|||
137 | have['slimerjs'] = is_cmd_found('slimerjs') |
|
|||
138 |
|
134 | |||
139 | min_zmq = (13,) |
|
135 | min_zmq = (13,) | |
140 |
|
136 |
@@ -247,218 +247,15 b' class PyTestController(TestController):' | |||||
247 | super(PyTestController, self).launch(buffer_output=buffer_output) |
|
247 | super(PyTestController, self).launch(buffer_output=buffer_output) | |
248 |
|
248 | |||
249 |
|
249 | |||
250 | js_prefix = 'js/' |
|
|||
251 |
|
||||
252 | def get_js_test_dir(): |
|
|||
253 | import IPython.html.tests as t |
|
|||
254 | return os.path.join(os.path.dirname(t.__file__), '') |
|
|||
255 |
|
||||
256 | def all_js_groups(): |
|
|||
257 | import glob |
|
|||
258 | test_dir = get_js_test_dir() |
|
|||
259 | all_subdirs = glob.glob(test_dir + '[!_]*/') |
|
|||
260 | return [js_prefix+os.path.relpath(x, test_dir) for x in all_subdirs] |
|
|||
261 |
|
||||
262 | class JSController(TestController): |
|
|||
263 | """Run CasperJS tests """ |
|
|||
264 |
|
||||
265 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', |
|
|||
266 | 'jsonschema'] |
|
|||
267 |
|
||||
268 | def __init__(self, section, xunit=True, engine='phantomjs', url=None): |
|
|||
269 | """Create new test runner.""" |
|
|||
270 | TestController.__init__(self) |
|
|||
271 | self.engine = engine |
|
|||
272 | self.section = section |
|
|||
273 | self.xunit = xunit |
|
|||
274 | self.url = url |
|
|||
275 | self.slimer_failure = re.compile('^FAIL.*', flags=re.MULTILINE) |
|
|||
276 | js_test_dir = get_js_test_dir() |
|
|||
277 | includes = '--includes=' + os.path.join(js_test_dir,'util.js') |
|
|||
278 | test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):]) |
|
|||
279 | self.cmd = ['casperjs', 'test', includes, test_cases, '--engine=%s' % self.engine] |
|
|||
280 |
|
||||
281 | def setup(self): |
|
|||
282 | self.ipydir = TemporaryDirectory() |
|
|||
283 | self.nbdir = TemporaryDirectory() |
|
|||
284 | self.dirs.append(self.ipydir) |
|
|||
285 | self.dirs.append(self.nbdir) |
|
|||
286 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir1', u'sub βir 1a'))) |
|
|||
287 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir2', u'sub βir 1b'))) |
|
|||
288 |
|
||||
289 | if self.xunit: |
|
|||
290 | self.add_xunit() |
|
|||
291 |
|
||||
292 | # If a url was specified, use that for the testing. |
|
|||
293 | if self.url: |
|
|||
294 | try: |
|
|||
295 | alive = requests.get(self.url).status_code == 200 |
|
|||
296 | except: |
|
|||
297 | alive = False |
|
|||
298 |
|
||||
299 | if alive: |
|
|||
300 | self.cmd.append("--url=%s" % self.url) |
|
|||
301 | else: |
|
|||
302 | raise Exception('Could not reach "%s".' % self.url) |
|
|||
303 | else: |
|
|||
304 | # start the ipython notebook, so we get the port number |
|
|||
305 | self.server_port = 0 |
|
|||
306 | self._init_server() |
|
|||
307 | if self.server_port: |
|
|||
308 | self.cmd.append("--port=%i" % self.server_port) |
|
|||
309 | else: |
|
|||
310 | # don't launch tests if the server didn't start |
|
|||
311 | self.cmd = [sys.executable, '-c', 'raise SystemExit(1)'] |
|
|||
312 |
|
||||
313 | def add_xunit(self): |
|
|||
314 | xunit_file = os.path.abspath(self.section.replace('/','.') + '.xunit.xml') |
|
|||
315 | self.cmd.append('--xunit=%s' % xunit_file) |
|
|||
316 |
|
||||
317 | def launch(self, buffer_output): |
|
|||
318 | # If the engine is SlimerJS, we need to buffer the output because |
|
|||
319 | # SlimerJS does not support exit codes, so CasperJS always returns 0. |
|
|||
320 | if self.engine == 'slimerjs' and not buffer_output: |
|
|||
321 | return super(JSController, self).launch(capture_output=True) |
|
|||
322 |
|
||||
323 | else: |
|
|||
324 | return super(JSController, self).launch(buffer_output=buffer_output) |
|
|||
325 |
|
||||
326 | def wait(self, *pargs, **kwargs): |
|
|||
327 | """Wait for the JSController to finish""" |
|
|||
328 | ret = super(JSController, self).wait(*pargs, **kwargs) |
|
|||
329 | # If this is a SlimerJS controller, check the captured stdout for |
|
|||
330 | # errors. Otherwise, just return the return code. |
|
|||
331 | if self.engine == 'slimerjs': |
|
|||
332 | stdout = bytes_to_str(self.stdout) |
|
|||
333 | if ret != 0: |
|
|||
334 | # This could still happen e.g. if it's stopped by SIGINT |
|
|||
335 | return ret |
|
|||
336 | return bool(self.slimer_failure.search(strip_ansi(stdout))) |
|
|||
337 | else: |
|
|||
338 | return ret |
|
|||
339 |
|
||||
340 | def print_extra_info(self): |
|
|||
341 | print("Running tests with notebook directory %r" % self.nbdir.name) |
|
|||
342 |
|
||||
343 | @property |
|
|||
344 | def will_run(self): |
|
|||
345 | should_run = all(have[a] for a in self.requirements + [self.engine]) |
|
|||
346 | return should_run |
|
|||
347 |
|
||||
348 | def _init_server(self): |
|
|||
349 | "Start the notebook server in a separate process" |
|
|||
350 | self.server_command = command = [sys.executable, |
|
|||
351 | '-m', 'IPython.html', |
|
|||
352 | '--no-browser', |
|
|||
353 | '--ipython-dir', self.ipydir.name, |
|
|||
354 | '--notebook-dir', self.nbdir.name, |
|
|||
355 | ] |
|
|||
356 | # ipc doesn't work on Windows, and darwin has crazy-long temp paths, |
|
|||
357 | # which run afoul of ipc's maximum path length. |
|
|||
358 | if sys.platform.startswith('linux'): |
|
|||
359 | command.append('--KernelManager.transport=ipc') |
|
|||
360 | self.stream_capturer = c = StreamCapturer() |
|
|||
361 | c.start() |
|
|||
362 | env = os.environ.copy() |
|
|||
363 | if self.engine == 'phantomjs': |
|
|||
364 | env['IPYTHON_ALLOW_DRAFT_WEBSOCKETS_FOR_PHANTOMJS'] = '1' |
|
|||
365 | self.server = subprocess.Popen(command, |
|
|||
366 | stdout=c.writefd, |
|
|||
367 | stderr=subprocess.STDOUT, |
|
|||
368 | cwd=self.nbdir.name, |
|
|||
369 | env=env, |
|
|||
370 | ) |
|
|||
371 | self.server_info_file = os.path.join(self.ipydir.name, |
|
|||
372 | 'profile_default', 'security', 'nbserver-%i.json' % self.server.pid |
|
|||
373 | ) |
|
|||
374 | self._wait_for_server() |
|
|||
375 |
|
||||
376 | def _wait_for_server(self): |
|
|||
377 | """Wait 30 seconds for the notebook server to start""" |
|
|||
378 | for i in range(300): |
|
|||
379 | if self.server.poll() is not None: |
|
|||
380 | return self._failed_to_start() |
|
|||
381 | if os.path.exists(self.server_info_file): |
|
|||
382 | try: |
|
|||
383 | self._load_server_info() |
|
|||
384 | except ValueError: |
|
|||
385 | # If the server is halfway through writing the file, we may |
|
|||
386 | # get invalid JSON; it should be ready next iteration. |
|
|||
387 | pass |
|
|||
388 | else: |
|
|||
389 | return |
|
|||
390 | time.sleep(0.1) |
|
|||
391 | print("Notebook server-info file never arrived: %s" % self.server_info_file, |
|
|||
392 | file=sys.stderr |
|
|||
393 | ) |
|
|||
394 |
|
||||
395 | def _failed_to_start(self): |
|
|||
396 | """Notebook server exited prematurely""" |
|
|||
397 | captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace') |
|
|||
398 | print("Notebook failed to start: ", file=sys.stderr) |
|
|||
399 | print(self.server_command) |
|
|||
400 | print(captured, file=sys.stderr) |
|
|||
401 |
|
||||
402 | def _load_server_info(self): |
|
|||
403 | """Notebook server started, load connection info from JSON""" |
|
|||
404 | with open(self.server_info_file) as f: |
|
|||
405 | info = json.load(f) |
|
|||
406 | self.server_port = info['port'] |
|
|||
407 |
|
||||
408 | def cleanup(self): |
|
|||
409 | if hasattr(self, 'server'): |
|
|||
410 | try: |
|
|||
411 | self.server.terminate() |
|
|||
412 | except OSError: |
|
|||
413 | # already dead |
|
|||
414 | pass |
|
|||
415 | # wait 10s for the server to shutdown |
|
|||
416 | try: |
|
|||
417 | popen_wait(self.server, NOTEBOOK_SHUTDOWN_TIMEOUT) |
|
|||
418 | except TimeoutExpired: |
|
|||
419 | # server didn't terminate, kill it |
|
|||
420 | try: |
|
|||
421 | print("Failed to terminate notebook server, killing it.", |
|
|||
422 | file=sys.stderr |
|
|||
423 | ) |
|
|||
424 | self.server.kill() |
|
|||
425 | except OSError: |
|
|||
426 | # already dead |
|
|||
427 | pass |
|
|||
428 | # wait another 10s |
|
|||
429 | try: |
|
|||
430 | popen_wait(self.server, NOTEBOOK_SHUTDOWN_TIMEOUT) |
|
|||
431 | except TimeoutExpired: |
|
|||
432 | print("Notebook server still running (%s)" % self.server_info_file, |
|
|||
433 | file=sys.stderr |
|
|||
434 | ) |
|
|||
435 |
|
||||
436 | self.stream_capturer.halt() |
|
|||
437 | TestController.cleanup(self) |
|
|||
438 |
|
||||
439 |
|
||||
440 | def prepare_controllers(options): |
|
250 | def prepare_controllers(options): | |
441 | """Returns two lists of TestController instances, those to run, and those |
|
251 | """Returns two lists of TestController instances, those to run, and those | |
442 | not to run.""" |
|
252 | not to run.""" | |
443 | testgroups = options.testgroups |
|
253 | testgroups = options.testgroups | |
444 | if testgroups: |
|
254 | if not testgroups: | |
445 | if 'js' in testgroups: |
|
255 | testgroups = py_test_group_names | |
446 | js_testgroups = all_js_groups() |
|
|||
447 | else: |
|
|||
448 | js_testgroups = [g for g in testgroups if g.startswith(js_prefix)] |
|
|||
449 | py_testgroups = [g for g in testgroups if not g.startswith('js')] |
|
|||
450 | else: |
|
|||
451 | py_testgroups = py_test_group_names |
|
|||
452 | if not options.all: |
|
|||
453 | js_testgroups = [] |
|
|||
454 | else: |
|
|||
455 | js_testgroups = all_js_groups() |
|
|||
456 |
|
256 | |||
457 | engine = 'slimerjs' if options.slimerjs else 'phantomjs' |
|
257 | controllers = [PyTestController(name, options) for name in testgroups] | |
458 | c_js = [JSController(name, xunit=options.xunit, engine=engine, url=options.url) for name in js_testgroups] |
|
|||
459 | c_py = [PyTestController(name, options) for name in py_testgroups] |
|
|||
460 |
|
258 | |||
461 | controllers = c_py + c_js |
|
|||
462 | to_run = [c for c in controllers if c.will_run] |
|
259 | to_run = [c for c in controllers if c.will_run] | |
463 | not_run = [c for c in controllers if not c.will_run] |
|
260 | not_run = [c for c in controllers if not c.will_run] | |
464 | return to_run, not_run |
|
261 | return to_run, not_run | |
@@ -559,9 +356,6 b' def run_iptestall(options):' | |||||
559 | inc_slow : bool |
|
356 | inc_slow : bool | |
560 | Include slow tests. By default, these tests aren't run. |
|
357 | Include slow tests. By default, these tests aren't run. | |
561 |
|
358 | |||
562 | slimerjs : bool |
|
|||
563 | Use slimerjs if it's installed instead of phantomjs for casperjs tests. |
|
|||
564 |
|
||||
565 | url : unicode |
|
359 | url : unicode | |
566 | Address:port to use when running the JS tests. |
|
360 | Address:port to use when running the JS tests. | |
567 |
|
361 | |||
@@ -696,8 +490,6 b" argparser.add_argument('testgroups', nargs='*'," | |||||
696 | 'all tests.') |
|
490 | 'all tests.') | |
697 | argparser.add_argument('--all', action='store_true', |
|
491 | argparser.add_argument('--all', action='store_true', | |
698 | help='Include slow tests not run by default.') |
|
492 | help='Include slow tests not run by default.') | |
699 | argparser.add_argument('--slimerjs', action='store_true', |
|
|||
700 | help="Use slimerjs if it's installed instead of phantomjs for casperjs tests.") |
|
|||
701 | argparser.add_argument('--url', help="URL to use for the JS tests.") |
|
493 | argparser.add_argument('--url', help="URL to use for the JS tests.") | |
702 | argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, |
|
494 | argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, | |
703 | help='Run test sections in parallel. This starts as many ' |
|
495 | help='Run test sections in parallel. This starts as many ' |
General Comments 0
You need to be logged in to leave comments.
Login now