launchnotebook.py
113 lines
| 3.5 KiB
| text/x-python
|
PythonLexer
Brian E. Granger
|
r13038 | """Base class for notebook tests.""" | |
Brian E. Granger
|
r15080 | from __future__ import print_function | |
Brian E. Granger
|
r13038 | import sys | |
import time | |||
Zachary Sailer
|
r13045 | import requests | |
Thomas Kluyver
|
r13099 | from contextlib import contextmanager | |
Min RK
|
r19348 | from threading import Thread, Event | |
Brian E. Granger
|
r13038 | from unittest import TestCase | |
Min RK
|
r19348 | from tornado.ioloop import IOLoop | |
Thomas Kluyver
|
r13833 | ||
Min RK
|
r19348 | from ..notebookapp import NotebookApp | |
Brian E. Granger
|
r13038 | from IPython.utils.tempdir import TemporaryDirectory | |
Paul Ivanov
|
r14071 | MAX_WAITTIME = 30 # seconds to wait for notebook server to start | |
POLL_INTERVAL = 0.1 # time between attempts | |||
Brian E. Granger
|
r15624 | # TimeoutError is a builtin on Python 3. This can be removed when we stop | |
# supporting Python 2. | |||
Brian E. Granger
|
r15621 | class TimeoutError(Exception): | |
pass | |||
Brian E. Granger
|
r13038 | class NotebookTestBase(TestCase): | |
"""A base class for tests that need a running notebook. | |||
This creates an empty profile in a temp ipython_dir | |||
and then starts the notebook server with a separate temp notebook_dir. | |||
""" | |||
Zachary Sailer
|
r13046 | port = 12341 | |
Brian E. Granger
|
r13038 | ||
MinRK
|
r13049 | @classmethod | |
def wait_until_alive(cls): | |||
"""Wait for the server to be alive""" | |||
MinRK
|
r17524 | url = 'http://localhost:%i/api/contents' % cls.port | |
Paul Ivanov
|
r14071 | for _ in range(int(MAX_WAITTIME/POLL_INTERVAL)): | |
Zachary Sailer
|
r13045 | try: | |
MinRK
|
r13049 | requests.get(url) | |
MinRK
|
r17749 | except Exception as e: | |
Thomas Kluyver
|
r14067 | if cls.notebook.poll() is not None: | |
raise RuntimeError("The notebook server exited with status %s" \ | |||
% cls.notebook.poll()) | |||
Paul Ivanov
|
r14071 | time.sleep(POLL_INTERVAL) | |
MinRK
|
r13049 | else: | |
Thomas Kluyver
|
r14067 | return | |
raise TimeoutError("The notebook server didn't start up correctly.") | |||
MinRK
|
r13049 | ||
@classmethod | |||
def wait_until_dead(cls): | |||
Thomas Kluyver
|
r14068 | """Wait for the server process to terminate after shutdown""" | |
Min RK
|
r19348 | cls.notebook_thread.join(timeout=MAX_WAITTIME) | |
if cls.notebook_thread.is_alive(): | |||
raise TimeoutError("Undead notebook server") | |||
Thomas Kluyver
|
r14067 | ||
MinRK
|
r13049 | @classmethod | |
def setup_class(cls): | |||
cls.ipython_dir = TemporaryDirectory() | |||
cls.notebook_dir = TemporaryDirectory() | |||
Min RK
|
r19348 | app = cls.notebook = NotebookApp( | |
port=cls.port, | |||
port_retries=0, | |||
open_browser=False, | |||
ipython_dir=cls.ipython_dir.name, | |||
notebook_dir=cls.notebook_dir.name, | |||
MinRK
|
r13180 | ) | |
Min RK
|
r19348 | ||
# clear log handlers and propagate to root for nose to capture it | |||
# needs to be redone after initialize, which reconfigures logging | |||
app.log.propagate = True | |||
app.log.handlers = [] | |||
app.initialize(argv=[]) | |||
app.log.propagate = True | |||
app.log.handlers = [] | |||
started = Event() | |||
def start_thread(): | |||
loop = IOLoop.current() | |||
loop.add_callback(started.set) | |||
try: | |||
app.start() | |||
finally: | |||
# set the event, so failure to start doesn't cause a hang | |||
started.set() | |||
cls.notebook_thread = Thread(target=start_thread) | |||
cls.notebook_thread.start() | |||
started.wait() | |||
MinRK
|
r13049 | cls.wait_until_alive() | |
@classmethod | |||
def teardown_class(cls): | |||
Min RK
|
r19348 | cls.notebook.stop() | |
MinRK
|
r16538 | cls.wait_until_dead() | |
MinRK
|
r13049 | cls.ipython_dir.cleanup() | |
cls.notebook_dir.cleanup() | |||
@classmethod | |||
def base_url(cls): | |||
return 'http://localhost:%i/' % cls.port | |||
Thomas Kluyver
|
r13099 | ||
@contextmanager | |||
Thomas Kluyver
|
r13105 | def assert_http_error(status, msg=None): | |
Thomas Kluyver
|
r13099 | try: | |
yield | |||
except requests.HTTPError as e: | |||
real_status = e.response.status_code | |||
assert real_status == status, \ | |||
Thomas Kluyver
|
r17774 | "Expected status %d, got %d" % (status, real_status) | |
Thomas Kluyver
|
r13105 | if msg: | |
assert msg in str(e), e | |||
Thomas Kluyver
|
r13099 | else: | |
assert False, "Expected HTTP error status" |