Show More
@@ -268,7 +268,7 b" test_sections['qt'].requires('zmq', 'qt', 'pygments')" | |||||
268 |
|
268 | |||
269 | # html: |
|
269 | # html: | |
270 | sec = test_sections['html'] |
|
270 | sec = test_sections['html'] | |
271 | sec.requires('zmq', 'tornado', 'requests') |
|
271 | sec.requires('zmq', 'tornado', 'requests', 'sqlite3') | |
272 | # The notebook 'static' directory contains JS, css and other |
|
272 | # The notebook 'static' directory contains JS, css and other | |
273 | # files for web serving. Occasionally projects may put a .py |
|
273 | # files for web serving. Occasionally projects may put a .py | |
274 | # file in there (MathJax ships a conf.py), so we might as |
|
274 | # file in there (MathJax ships a conf.py), so we might as |
@@ -19,8 +19,8 b' test suite.' | |||||
19 | from __future__ import print_function |
|
19 | from __future__ import print_function | |
20 |
|
20 | |||
21 | import argparse |
|
21 | import argparse | |
|
22 | import json | |||
22 | import multiprocessing.pool |
|
23 | import multiprocessing.pool | |
23 | from multiprocessing import Process, Queue |
|
|||
24 | import os |
|
24 | import os | |
25 | import shutil |
|
25 | import shutil | |
26 | import signal |
|
26 | import signal | |
@@ -28,7 +28,7 b' import sys' | |||||
28 | import subprocess |
|
28 | import subprocess | |
29 | import time |
|
29 | import time | |
30 |
|
30 | |||
31 | from .iptest import have, test_group_names as py_test_group_names, test_sections |
|
31 | from .iptest import have, test_group_names as py_test_group_names, test_sections, StreamCapturer | |
32 | from IPython.utils.path import compress_user |
|
32 | from IPython.utils.path import compress_user | |
33 | from IPython.utils.py3compat import bytes_to_str |
|
33 | from IPython.utils.py3compat import bytes_to_str | |
34 | from IPython.utils.sysinfo import get_sys_info |
|
34 | from IPython.utils.sysinfo import get_sys_info | |
@@ -220,48 +220,77 b' class JSController(TestController):' | |||||
220 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir2', u'sub βir 1b'))) |
|
220 | os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βir2', u'sub βir 1b'))) | |
221 |
|
221 | |||
222 | # start the ipython notebook, so we get the port number |
|
222 | # start the ipython notebook, so we get the port number | |
|
223 | self.server_port = 0 | |||
223 | self._init_server() |
|
224 | self._init_server() | |
224 |
|
|
225 | if self.server_port: | |
225 |
|
226 | self.cmd.append("--port=%i" % self.server_port) | ||
|
227 | else: | |||
|
228 | # don't launch tests if the server didn't start | |||
|
229 | self.cmd = [sys.executable, '-c', 'raise SystemExit(1)'] | |||
|
230 | ||||
226 | def print_extra_info(self): |
|
231 | def print_extra_info(self): | |
227 | print("Running tests with notebook directory %r" % self.nbdir.name) |
|
232 | print("Running tests with notebook directory %r" % self.nbdir.name) | |
228 |
|
233 | |||
229 | @property |
|
234 | @property | |
230 | def will_run(self): |
|
235 | def will_run(self): | |
231 | return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs']) |
|
236 | return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3']) | |
232 |
|
237 | |||
233 | def _init_server(self): |
|
238 | def _init_server(self): | |
234 | "Start the notebook server in a separate process" |
|
239 | "Start the notebook server in a separate process" | |
235 | self.queue = q = Queue() |
|
240 | self.server_command = command = [sys.executable, | |
236 | self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name)) |
|
241 | '-m', 'IPython.html', | |
237 | self.server.start() |
|
242 | '--no-browser', | |
238 | self.server_port = q.get() |
|
243 | '--ipython-dir', self.ipydir.name, | |
|
244 | '--notebook-dir', self.nbdir.name, | |||
|
245 | ] | |||
|
246 | # ipc doesn't work on Windows, and darwin has crazy-long temp paths, | |||
|
247 | # which run afoul of ipc's maximum path length. | |||
|
248 | if sys.platform.startswith('linux'): | |||
|
249 | command.append('--KernelManager.transport=ipc') | |||
|
250 | self.stream_capturer = c = StreamCapturer() | |||
|
251 | c.start() | |||
|
252 | self.server = subprocess.Popen(command, stdout=c.writefd, stderr=subprocess.STDOUT) | |||
|
253 | self.server_info_file = os.path.join(self.ipydir.name, | |||
|
254 | 'profile_default', 'security', 'nbserver-%i.json' % self.server.pid | |||
|
255 | ) | |||
|
256 | self._wait_for_server() | |||
|
257 | ||||
|
258 | def _wait_for_server(self): | |||
|
259 | """Wait 30 seconds for the notebook server to start""" | |||
|
260 | for i in range(300): | |||
|
261 | if self.server.poll() is not None: | |||
|
262 | return self._failed_to_start() | |||
|
263 | if os.path.exists(self.server_info_file): | |||
|
264 | self._load_server_info() | |||
|
265 | return | |||
|
266 | time.sleep(0.1) | |||
|
267 | print("Notebook server-info file never arrived: %s" % self.server_info_file, | |||
|
268 | file=sys.stderr | |||
|
269 | ) | |||
|
270 | ||||
|
271 | def _failed_to_start(self): | |||
|
272 | """Notebook server exited prematurely""" | |||
|
273 | captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace') | |||
|
274 | print("Notebook failed to start: ", file=sys.stderr) | |||
|
275 | print(self.server_command) | |||
|
276 | print(captured, file=sys.stderr) | |||
|
277 | ||||
|
278 | def _load_server_info(self): | |||
|
279 | """Notebook server started, load connection info from JSON""" | |||
|
280 | with open(self.server_info_file) as f: | |||
|
281 | info = json.load(f) | |||
|
282 | self.server_port = info['port'] | |||
239 |
|
283 | |||
240 | def cleanup(self): |
|
284 | def cleanup(self): | |
241 | self.server.terminate() |
|
285 | try: | |
242 |
self.server. |
|
286 | self.server.terminate() | |
|
287 | except OSError: | |||
|
288 | # already dead | |||
|
289 | pass | |||
|
290 | self.server.wait() | |||
|
291 | self.stream_capturer.halt() | |||
243 | TestController.cleanup(self) |
|
292 | TestController.cleanup(self) | |
244 |
|
293 | |||
245 | def run_webapp(q, ipydir, nbdir, loglevel=0): |
|
|||
246 | """start the IPython Notebook, and pass port back to the queue""" |
|
|||
247 | import os |
|
|||
248 | import IPython.html.notebookapp as nbapp |
|
|||
249 | import sys |
|
|||
250 | sys.stderr = open(os.devnull, 'w') |
|
|||
251 | server = nbapp.NotebookApp() |
|
|||
252 | args = ['--no-browser'] |
|
|||
253 | args.extend(['--ipython-dir', ipydir, |
|
|||
254 | '--notebook-dir', nbdir, |
|
|||
255 | '--log-level', str(loglevel), |
|
|||
256 | ]) |
|
|||
257 | # ipc doesn't work on Windows, and darwin has crazy-long temp paths, |
|
|||
258 | # which run afoul of ipc's maximum path length. |
|
|||
259 | if sys.platform.startswith('linux'): |
|
|||
260 | args.append('--KernelManager.transport=ipc') |
|
|||
261 | server.initialize(args) |
|
|||
262 | # communicate the port number to the parent process |
|
|||
263 | q.put(server.port) |
|
|||
264 | server.start() |
|
|||
265 |
|
294 | |||
266 | def prepare_controllers(options): |
|
295 | def prepare_controllers(options): | |
267 | """Returns two lists of TestController instances, those to run, and those |
|
296 | """Returns two lists of TestController instances, those to run, and those |
General Comments 0
You need to be logged in to leave comments.
Login now