Skip to content

Commit b26ed5c

Browse files
committed
Add some tests for handling SIGINT in the PDB client
1 parent 14aa8e7 commit b26ed5c

File tree

1 file changed

+67
-5
lines changed

1 file changed

+67
-5
lines changed

Lib/test/test_remote_pdb.py

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ def do_test(
8787
*,
8888
incoming,
8989
simulate_send_failure=False,
90+
simulate_sigint_during_stdout_write=False,
9091
expected_outgoing=None,
92+
expected_outgoing_signals=None,
9193
expected_completions=None,
9294
expected_exception=None,
9395
expected_stdout="",
@@ -96,6 +98,8 @@ def do_test(
9698
):
9799
if expected_outgoing is None:
98100
expected_outgoing = []
101+
if expected_outgoing_signals is None:
102+
expected_outgoing_signals = []
99103
if expected_completions is None:
100104
expected_completions = []
101105
if expected_state is None:
@@ -130,7 +134,9 @@ def mock_input(prompt):
130134
reply = message["input"]
131135
if isinstance(reply, BaseException):
132136
raise reply
133-
return reply
137+
if isinstance(reply, str):
138+
return reply
139+
return reply()
134140

135141
with ExitStack() as stack:
136142
client_sock, server_sock = socket.socketpair()
@@ -155,15 +161,25 @@ def mock_input(prompt):
155161

156162
stdout = io.StringIO()
157163

164+
if simulate_sigint_during_stdout_write:
165+
orig_stdout_write = stdout.write
166+
167+
def sigint_stdout_write(s):
168+
signal.raise_signal(signal.SIGINT)
169+
return orig_stdout_write(s)
170+
171+
stdout.write = sigint_stdout_write
172+
158173
input_mock = stack.enter_context(
159174
unittest.mock.patch("pdb.input", side_effect=mock_input)
160175
)
161176
stack.enter_context(redirect_stdout(stdout))
162177

178+
interrupt_sock = unittest.mock.Mock(spec=socket.socket)
163179
client = _PdbClient(
164180
pid=0,
165181
server_socket=server_sock,
166-
interrupt_sock=unittest.mock.Mock(spec=socket.socket),
182+
interrupt_sock=interrupt_sock,
167183
)
168184

169185
if expected_exception is not None:
@@ -188,6 +204,12 @@ def mock_input(prompt):
188204
actual_state = {k: getattr(client, k) for k in expected_state}
189205
self.assertEqual(actual_state, expected_state)
190206

207+
outgoing_signals = [
208+
signal.Signals(int.from_bytes(call.args[0]))
209+
for call in interrupt_sock.sendall.call_args_list
210+
]
211+
self.assertEqual(outgoing_signals, expected_outgoing_signals)
212+
191213
def test_remote_immediately_closing_the_connection(self):
192214
"""Test the behavior when the remote closes the connection immediately."""
193215
incoming = []
@@ -382,11 +404,17 @@ def test_handling_unrecognized_prompt_type(self):
382404
expected_state={"state": "dumb"},
383405
)
384406

385-
def test_keyboard_interrupt_at_prompt(self):
386-
"""Test signaling when a prompt gets a KeyboardInterrupt."""
407+
def test_sigint_at_prompt(self):
408+
"""Test signaling when a prompt gets interrupted."""
387409
incoming = [
388410
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
389-
("user", {"prompt": "(Pdb) ", "input": KeyboardInterrupt()}),
411+
(
412+
"user",
413+
{
414+
"prompt": "(Pdb) ",
415+
"input": lambda: signal.raise_signal(signal.SIGINT),
416+
},
417+
),
390418
]
391419
self.do_test(
392420
incoming=incoming,
@@ -396,6 +424,40 @@ def test_keyboard_interrupt_at_prompt(self):
396424
expected_state={"state": "pdb"},
397425
)
398426

427+
def test_sigint_at_continuation_prompt(self):
428+
"""Test signaling when a continuation prompt gets interrupted."""
429+
incoming = [
430+
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
431+
("user", {"prompt": "(Pdb) ", "input": "if True:"}),
432+
(
433+
"user",
434+
{
435+
"prompt": "... ",
436+
"input": lambda: signal.raise_signal(signal.SIGINT),
437+
},
438+
),
439+
]
440+
self.do_test(
441+
incoming=incoming,
442+
expected_outgoing=[
443+
{"signal": "INT"},
444+
],
445+
expected_state={"state": "pdb"},
446+
)
447+
448+
def test_sigint_when_writing(self):
449+
"""Test siginaling when sys.stdout.write() gets interrupted."""
450+
incoming = [
451+
("server", {"message": "Some message or other\n", "type": "info"}),
452+
]
453+
self.do_test(
454+
incoming=incoming,
455+
simulate_sigint_during_stdout_write=True,
456+
expected_outgoing=[],
457+
expected_outgoing_signals=[signal.SIGINT],
458+
expected_stdout="Some message or other\n",
459+
)
460+
399461
def test_eof_at_prompt(self):
400462
"""Test signaling when a prompt gets an EOFError."""
401463
incoming = [

0 commit comments

Comments
 (0)