mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-18 11:55:46 +08:00
Don't use fork to start the notebook in js tests
It can encounter a weird segfault on OS X with sqlite when Qt is present (?!) The main reason to use the fork was to get the port number, but this is easy now that notebooks write a server-info file. Further advantage is that the symptom of a failed server start is no longer silence and hanging tests, but an actual failure with the server's log output.
This commit is contained in:
parent
fa44edcb47
commit
386b08634c
@ -19,8 +19,8 @@ test suite.
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import multiprocessing.pool
|
||||
from multiprocessing import Process, Queue
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
@ -28,7 +28,7 @@ import sys
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from .iptest import have, test_group_names as py_test_group_names, test_sections
|
||||
from .iptest import have, test_group_names as py_test_group_names, test_sections, StreamCapturer
|
||||
from IPython.utils.path import compress_user
|
||||
from IPython.utils.py3compat import bytes_to_str
|
||||
from IPython.utils.sysinfo import get_sys_info
|
||||
@ -211,8 +211,10 @@ class JSController(TestController):
|
||||
os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir2', u'sub ∂ir 1b')))
|
||||
|
||||
# start the ipython notebook, so we get the port number
|
||||
self.server_port = 0
|
||||
self._init_server()
|
||||
self.cmd.append('--port=%s' % self.server_port)
|
||||
if self.server_port:
|
||||
self.cmd.append("--port=%i" % self.server_port)
|
||||
|
||||
def print_extra_info(self):
|
||||
print("Running tests with notebook directory %r" % self.nbdir.name)
|
||||
@ -223,36 +225,60 @@ class JSController(TestController):
|
||||
|
||||
def _init_server(self):
|
||||
"Start the notebook server in a separate process"
|
||||
self.queue = q = Queue()
|
||||
self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name))
|
||||
self.server.start()
|
||||
self.server_port = q.get()
|
||||
self.server_command = command = [sys.executable,
|
||||
'-m', 'IPython.html',
|
||||
'--no-browser',
|
||||
'--ipython-dir', self.ipydir.name,
|
||||
'--notebook-dir', self.nbdir.name,
|
||||
]
|
||||
# ipc doesn't work on Windows, and darwin has crazy-long temp paths,
|
||||
# which run afoul of ipc's maximum path length.
|
||||
if sys.platform.startswith('linux'):
|
||||
command.append('--KernelManager.transport=ipc')
|
||||
self.stream_capturer = c = StreamCapturer()
|
||||
c.start()
|
||||
self.server = subprocess.Popen(command, stdout=c.writefd, stderr=subprocess.STDOUT)
|
||||
self.server_info_file = os.path.join(self.ipydir.name,
|
||||
'profile_default', 'security', 'nbserver-%i.json' % self.server.pid
|
||||
)
|
||||
self._wait_for_server()
|
||||
|
||||
def _wait_for_server(self):
|
||||
"""Wait 30 seconds for the notebook server to start"""
|
||||
for i in range(300):
|
||||
if self.server.poll() is not None:
|
||||
return self._failed_to_start()
|
||||
if os.path.exists(self.server_info_file):
|
||||
self._load_server_info()
|
||||
return
|
||||
time.sleep(0.1)
|
||||
print("Notebook server-info file never arrived: %s" % self.server_info_file,
|
||||
file=sys.stderr
|
||||
)
|
||||
|
||||
def _failed_to_start(self):
|
||||
"""Notebook server exited prematurely"""
|
||||
captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
|
||||
print("Notebook failed to start: ", file=sys.stderr)
|
||||
print(self.server_command)
|
||||
print(captured, file=sys.stderr)
|
||||
|
||||
def _load_server_info(self):
|
||||
"""Notebook server started, load connection info from JSON"""
|
||||
with open(self.server_info_file) as f:
|
||||
info = json.load(f)
|
||||
self.server_port = info['port']
|
||||
|
||||
def cleanup(self):
|
||||
self.server.terminate()
|
||||
self.server.join()
|
||||
self.stream_capturer.halt()
|
||||
try:
|
||||
self.server.terminate()
|
||||
except OSError:
|
||||
# already dead
|
||||
pass
|
||||
self.server.wait()
|
||||
TestController.cleanup(self)
|
||||
|
||||
def run_webapp(q, ipydir, nbdir, loglevel=0):
|
||||
"""start the IPython Notebook, and pass port back to the queue"""
|
||||
import os
|
||||
import IPython.html.notebookapp as nbapp
|
||||
import sys
|
||||
sys.stderr = open(os.devnull, 'w')
|
||||
server = nbapp.NotebookApp()
|
||||
args = ['--no-browser']
|
||||
args.extend(['--ipython-dir', ipydir,
|
||||
'--notebook-dir', nbdir,
|
||||
'--log-level', str(loglevel),
|
||||
])
|
||||
# ipc doesn't work on Windows, and darwin has crazy-long temp paths,
|
||||
# which run afoul of ipc's maximum path length.
|
||||
if sys.platform.startswith('linux'):
|
||||
args.append('--KernelManager.transport=ipc')
|
||||
server.initialize(args)
|
||||
# communicate the port number to the parent process
|
||||
q.put(server.port)
|
||||
server.start()
|
||||
|
||||
def prepare_controllers(options):
|
||||
"""Returns two lists of TestController instances, those to run, and those
|
||||
|
Loading…
Reference in New Issue
Block a user