Skip to content

Commit 2a8cd60

Browse files
committed
Add unit and integration tests for the kernel API
1 parent c8e91cf commit 2a8cd60

File tree

11 files changed

+1061
-3
lines changed

11 files changed

+1061
-3
lines changed

conftest.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import pytest
22

3-
pytest_plugins = ("pytest_jupyter.jupyter_server", "jupyter_server.pytest_plugin")
3+
pytest_plugins = ("pytest_jupyter.jupyter_server", "jupyter_server.pytest_plugin", "pytest_asyncio")
4+
5+
6+
def pytest_configure(config):
7+
"""Configure pytest settings."""
8+
# Set asyncio fixture loop scope to function to avoid warnings
9+
config.option.asyncio_default_fixture_loop_scope = "function"
410

511

612
@pytest.fixture

jupyter_server_documents/tests/kernels/__init__.py

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Configuration for kernel tests."""
2+
3+
import pytest
4+
from unittest.mock import MagicMock
5+
6+
7+
@pytest.fixture
8+
def mock_logger():
9+
"""Create a mock logger for testing."""
10+
return MagicMock()
11+
12+
13+
@pytest.fixture
14+
def mock_session():
15+
"""Create a mock session for testing."""
16+
session = MagicMock()
17+
session.msg_header.return_value = {"msg_id": "test-msg-id"}
18+
session.msg.return_value = {"test": "message"}
19+
session.serialize.return_value = ["", "serialized", "msg"]
20+
session.deserialize.return_value = {"msg_type": "test", "content": b"test"}
21+
session.unpack.return_value = {"test": "data"}
22+
session.feed_identities.return_value = ([], [b"test", b"message"])
23+
return session
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import pytest
2+
from unittest.mock import MagicMock, patch
3+
4+
from jupyter_server_documents.kernels.kernel_client import DocumentAwareKernelClient
5+
from jupyter_server_documents.kernels.message_cache import KernelMessageCache
6+
from jupyter_server_documents.outputs import OutputProcessor
7+
8+
9+
class TestDocumentAwareKernelClient:
10+
"""Test cases for DocumentAwareKernelClient."""
11+
12+
def test_default_message_cache(self):
13+
"""Test that message cache is created by default."""
14+
client = DocumentAwareKernelClient()
15+
assert isinstance(client.message_cache, KernelMessageCache)
16+
17+
def test_default_output_processor(self):
18+
"""Test that output processor is created by default."""
19+
client = DocumentAwareKernelClient()
20+
assert isinstance(client.output_processor, OutputProcessor)
21+
22+
@pytest.mark.asyncio
23+
async def test_stop_listening_no_task(self):
24+
"""Test that stop_listening does nothing when no task exists."""
25+
client = DocumentAwareKernelClient()
26+
client._listening_task = None
27+
28+
# Should not raise an exception
29+
await client.stop_listening()
30+
31+
def test_add_listener(self):
32+
"""Test adding a listener."""
33+
client = DocumentAwareKernelClient()
34+
35+
def test_listener(channel, msg):
36+
pass
37+
38+
client.add_listener(test_listener)
39+
40+
assert test_listener in client._listeners
41+
42+
def test_remove_listener(self):
43+
"""Test removing a listener."""
44+
client = DocumentAwareKernelClient()
45+
46+
def test_listener(channel, msg):
47+
pass
48+
49+
client.add_listener(test_listener)
50+
client.remove_listener(test_listener)
51+
52+
assert test_listener not in client._listeners
53+
54+
@pytest.mark.asyncio
55+
async def test_add_yroom(self):
56+
"""Test adding a YRoom."""
57+
client = DocumentAwareKernelClient()
58+
59+
mock_yroom = MagicMock()
60+
await client.add_yroom(mock_yroom)
61+
62+
assert mock_yroom in client._yrooms
63+
64+
@pytest.mark.asyncio
65+
async def test_remove_yroom(self):
66+
"""Test removing a YRoom."""
67+
client = DocumentAwareKernelClient()
68+
69+
mock_yroom = MagicMock()
70+
client._yrooms.add(mock_yroom)
71+
72+
await client.remove_yroom(mock_yroom)
73+
74+
assert mock_yroom not in client._yrooms
75+
76+
def test_send_kernel_info_creates_message(self):
77+
"""Test that send_kernel_info creates a kernel info message."""
78+
client = DocumentAwareKernelClient()
79+
80+
# Mock session
81+
from jupyter_client.session import Session
82+
client.session = Session()
83+
84+
with patch.object(client, 'handle_incoming_message') as mock_handle:
85+
client.send_kernel_info()
86+
87+
# Verify that handle_incoming_message was called with shell channel
88+
mock_handle.assert_called_once()
89+
args, kwargs = mock_handle.call_args
90+
assert args[0] == "shell" # Channel name
91+
assert isinstance(args[1], list) # Message list
92+
93+
@pytest.mark.asyncio
94+
async def test_handle_outgoing_message_control_channel(self):
95+
"""Test that control channel messages bypass document handling."""
96+
client = DocumentAwareKernelClient()
97+
98+
msg = [b"test", b"message"]
99+
100+
with patch.object(client, 'handle_document_related_message') as mock_handle_doc:
101+
with patch.object(client, 'send_message_to_listeners') as mock_send:
102+
await client.handle_outgoing_message("control", msg)
103+
104+
mock_handle_doc.assert_not_called()
105+
mock_send.assert_called_once_with("control", msg)

0 commit comments

Comments
 (0)