Skip to content

Commit e9735fc

Browse files
authored
Add more tests (#1092)
1 parent 2206a47 commit e9735fc

File tree

5 files changed

+174
-3
lines changed

5 files changed

+174
-3
lines changed

jupyter_server/pytest_plugin.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,10 @@ def inner(nbpath):
523523
def jp_server_cleanup(asyncio_loop):
524524
yield
525525
app: ServerApp = ServerApp.instance()
526-
asyncio_loop.run_until_complete(app._cleanup())
526+
try:
527+
asyncio_loop.run_until_complete(app._cleanup())
528+
except (RuntimeError, SystemExit) as e:
529+
print("ignoring cleanup error", e)
527530
ServerApp.clear_instance()
528531

529532

File renamed without changes.

tests/base/test_websocket.py

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Test Base Websocket classes"""
2+
import logging
3+
import time
4+
from unittest.mock import MagicMock
5+
6+
import pytest
7+
from tornado.httpserver import HTTPRequest
8+
from tornado.httputil import HTTPHeaders
9+
from tornado.websocket import WebSocketClosedError, WebSocketHandler
10+
11+
from jupyter_server.base.websocket import WebSocketMixin
12+
from jupyter_server.serverapp import ServerApp
13+
14+
15+
class MockHandler(WebSocketMixin, WebSocketHandler):
16+
allow_origin = "*"
17+
allow_origin_pat = ""
18+
log = logging.getLogger()
19+
20+
21+
@pytest.fixture
22+
def mixin(jp_serverapp):
23+
app: ServerApp = jp_serverapp
24+
headers = HTTPHeaders({"Host": "foo"})
25+
request = HTTPRequest("GET", headers=headers)
26+
request.connection = MagicMock()
27+
return MockHandler(app.web_app, request)
28+
29+
30+
def test_web_socket_mixin(mixin):
31+
assert mixin.check_origin("foo") is True
32+
mixin.allow_origin = ""
33+
assert mixin.check_origin("") is False
34+
mixin.allow_origin_pat = "foo"
35+
assert mixin.check_origin("foo") is True
36+
mixin.clear_cookie()
37+
assert mixin.get_status() == 200
38+
39+
40+
def test_web_socket_mixin_ping(mixin):
41+
mixin.ws_connection = MagicMock()
42+
mixin.ws_connection.is_closing = lambda: False
43+
mixin.send_ping()
44+
45+
46+
def test_ping_client_terminated(mixin):
47+
mixin.ws_connection = MagicMock()
48+
mixin.ws_connection.client_terminated = True
49+
mixin.send_ping()
50+
with pytest.raises(WebSocketClosedError):
51+
mixin.write_message("hello")
52+
53+
54+
async def test_ping_client_timeout(mixin):
55+
mixin.on_pong("foo")
56+
mixin.settings["ws_ping_timeout"] = 0.1
57+
time.sleep(0.3)
58+
mixin.ws_connection = MagicMock()
59+
mixin.ws_connection.is_closing = lambda: False
60+
mixin.send_ping()
61+
with pytest.raises(WebSocketClosedError):
62+
mixin.write_message("hello")

tests/services/contents/test_fileio.py

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
import json
2+
import logging
13
import os
24
import stat
35
import sys
46

57
import pytest
6-
7-
from jupyter_server.services.contents.fileio import atomic_writing
8+
from nbformat import validate
9+
from nbformat.v4 import new_notebook
10+
from tornado.web import HTTPError
11+
12+
from jupyter_server.services.contents.fileio import (
13+
AsyncFileManagerMixin,
14+
FileManagerMixin,
15+
atomic_writing,
16+
path_to_intermediate,
17+
path_to_invalid,
18+
)
819

920
umask = 0
1021

@@ -121,3 +132,51 @@ def test_atomic_writing_newlines(tmp_path):
121132
with open(path, newline="") as f:
122133
read = f.read()
123134
assert read == text
135+
136+
137+
def test_path_to_invalid(tmpdir):
138+
assert path_to_invalid(tmpdir) == str(tmpdir) + ".invalid"
139+
140+
141+
@pytest.mark.skipif(os.name == "nt", reason="test fails on Windows")
142+
def test_file_manager_mixin(tmpdir):
143+
mixin = FileManagerMixin()
144+
mixin.log = logging.getLogger()
145+
bad_content = tmpdir / "bad_content.ipynb"
146+
bad_content.write_text("{}", "utf8")
147+
with pytest.raises(HTTPError):
148+
mixin._read_notebook(bad_content)
149+
other = path_to_intermediate(bad_content)
150+
with open(other, "w") as fid:
151+
json.dump(new_notebook(), fid)
152+
mixin.use_atomic_writing = True
153+
nb = mixin._read_notebook(bad_content)
154+
validate(nb)
155+
156+
with pytest.raises(HTTPError):
157+
mixin._read_file(tmpdir, "text")
158+
159+
with pytest.raises(HTTPError):
160+
mixin._save_file(tmpdir / "foo", "foo", "bar")
161+
162+
163+
@pytest.mark.skipif(os.name == "nt", reason="test fails on Windows")
164+
async def test_async_file_manager_mixin(tmpdir):
165+
mixin = AsyncFileManagerMixin()
166+
mixin.log = logging.getLogger()
167+
bad_content = tmpdir / "bad_content.ipynb"
168+
bad_content.write_text("{}", "utf8")
169+
with pytest.raises(HTTPError):
170+
await mixin._read_notebook(bad_content)
171+
other = path_to_intermediate(bad_content)
172+
with open(other, "w") as fid:
173+
json.dump(new_notebook(), fid)
174+
mixin.use_atomic_writing = True
175+
nb = await mixin._read_notebook(bad_content)
176+
validate(nb)
177+
178+
with pytest.raises(HTTPError):
179+
await mixin._read_file(tmpdir, "text")
180+
181+
with pytest.raises(HTTPError):
182+
await mixin._save_file(tmpdir / "foo", "foo", "bar")

tests/test_serverapp.py

+47
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,50 @@ def test_server_web_application(jp_serverapp):
437437
{},
438438
)
439439
app.init_handlers([], app.settings)
440+
441+
442+
def test_misc(jp_serverapp, tmp_path):
443+
app: ServerApp = jp_serverapp
444+
assert app.terminals_enabled is True
445+
app.extra_args = [str(tmp_path)]
446+
app.parse_command_line([])
447+
448+
449+
def test_deprecated_props(jp_serverapp):
450+
app: ServerApp = jp_serverapp
451+
with warnings.catch_warnings():
452+
warnings.simplefilter("ignore")
453+
app.cookie_options = dict(foo=1)
454+
app.get_secure_cookie_kwargs = dict(bar=1)
455+
app.notebook_dir = "foo"
456+
app.server_extensions = dict(foo=True)
457+
app.kernel_ws_protocol = "foo"
458+
app.limit_rate = True
459+
app.iopub_msg_rate_limit = 10
460+
app.iopub_data_rate_limit = 10
461+
app.rate_limit_window = 10
462+
with pytest.raises(SystemExit):
463+
app.pylab = "foo"
464+
465+
466+
def test_signals(jp_serverapp):
467+
app: ServerApp = jp_serverapp
468+
app.answer_yes = True
469+
app._restore_sigint_handler()
470+
app._handle_sigint(None, None)
471+
app._confirm_exit()
472+
app._signal_info(None, None)
473+
474+
475+
async def test_shutdown_no_activity(jp_serverapp):
476+
app: ServerApp = jp_serverapp
477+
app.extension_manager.extensions = {}
478+
app.exit = lambda _: None
479+
app.shutdown_no_activity()
480+
app.shutdown_no_activity_timeout = 1
481+
app.init_shutdown_no_activity()
482+
483+
484+
def test_running_server_info(jp_serverapp):
485+
app: ServerApp = jp_serverapp
486+
app.running_server_info(True)

0 commit comments

Comments
 (0)