Skip to content

Commit 03a29e4

Browse files
committed
Add test_fork()
1 parent 0422bfa commit 03a29e4

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

ipykernel/tests/test_kernel.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
from IPython.paths import locate_profile
1818
from ipython_genutils.tempdir import TemporaryDirectory
1919

20+
from ipykernel.tests.test_message_spec import validate_message
2021
from .utils import (
2122
new_kernel, kernel, TIMEOUT, assemble_output, execute,
2223
flush_channels, wait_for_idle,
23-
)
24+
connect_to_kernel)
2425

2526

2627
def _check_master(kc, expected=True, stream="stdout"):
@@ -326,3 +327,43 @@ def test_shutdown():
326327
else:
327328
break
328329
assert not km.is_alive()
330+
331+
def test_fork_metadata():
332+
with kernel() as kc:
333+
km = kc.parent
334+
fork_msg_id = kc.fork()
335+
fork_reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
336+
# validate_message(fork_reply, "execute_reply", fork_msg_id) # TODO: Make it work (need the `fork_reply`)
337+
assert fork_msg_id == fork_reply['parent_header']['msg_id'] == fork_msg_id
338+
assert fork_reply['content']['conn']['key'] != kc.session.key.decode()
339+
fork_pid = fork_reply['content']['pid']
340+
_check_status(fork_reply['content'])
341+
wait_for_idle(kc)
342+
343+
assert fork_pid != km.kernel.pid
344+
#TODO: Inspect if `fork_pid` is running? Might need to use `psutil` for this in order to be cross platform
345+
346+
with connect_to_kernel(fork_reply['content']['conn'], TIMEOUT) as kc_fork:
347+
assert fork_reply['content']['conn']['key'] == kc_fork.session.key.decode()
348+
kc_fork.shutdown()
349+
350+
def test_fork():
351+
def execute_with_user_expression(kc, code, user_expression):
352+
_, reply = execute(code, kc=kc, user_expressions={"my-user-expression": user_expression})
353+
content = reply["user_expressions"]["my-user-expression"]["data"]["text/plain"]
354+
wait_for_idle(kc)
355+
return content
356+
357+
"""Kernel forks after fork_request"""
358+
with kernel() as kc:
359+
assert execute_with_user_expression(kc, u'a = 1', "a") == "1"
360+
assert execute_with_user_expression(kc, u'b = 2', "b") == "2"
361+
kc.fork()
362+
fork_reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
363+
wait_for_idle(kc)
364+
365+
with connect_to_kernel(fork_reply['content']['conn'], TIMEOUT) as kc_fork:
366+
assert execute_with_user_expression(kc_fork, 'a = 11', "a, b") == str((11, 2))
367+
assert execute_with_user_expression(kc_fork, 'b = 12', "a, b") == str((11, 12))
368+
assert execute_with_user_expression(kc, 'z = 20', "a, b") == str((1, 2))
369+
kc_fork.shutdown()

ipykernel/tests/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,14 @@ def wait_for_idle(kc):
170170
content = msg['content']
171171
if msg_type == 'status' and content['execution_state'] == 'idle':
172172
break
173+
174+
@contextmanager
175+
def connect_to_kernel(connection_info, timeout):
176+
from jupyter_client import BlockingKernelClient
177+
kc = BlockingKernelClient()
178+
kc.log.setLevel('DEBUG')
179+
kc.load_connection_info(connection_info)
180+
kc.start_channels()
181+
kc.wait_for_ready(timeout)
182+
yield kc
183+
kc.stop_channels()

0 commit comments

Comments
 (0)