aboutsummaryrefslogtreecommitdiff
path: root/lldb/packages/Python
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/packages/Python')
-rw-r--r--lldb/packages/Python/lldbsuite/test/gdbclientutils.py66
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbgdbclient.py18
-rw-r--r--lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py6
3 files changed, 72 insertions, 18 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 1a2860a..bd2fdc0 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -5,8 +5,9 @@ import io
import threading
import socket
import traceback
+from enum import Enum
from lldbsuite.support import seven
-from typing import Optional, List, Tuple
+from typing import Optional, List, Tuple, Union, Sequence
def checksum(message):
@@ -76,6 +77,35 @@ def hex_decode_bytes(hex_bytes):
return out
+class PacketDirection(Enum):
+ RECV = "recv"
+ SEND = "send"
+
+
+class PacketLog:
+ def __init__(self):
+ self._packets: list[tuple[PacketDirection, str]] = []
+
+ def add_sent(self, packet: str):
+ self._packets.append((PacketDirection.SEND, packet))
+
+ def add_received(self, packet: str):
+ self._packets.append((PacketDirection.RECV, packet))
+
+ def get_sent(self):
+ return [
+ pkt for direction, pkt in self._packets if direction == PacketDirection.SEND
+ ]
+
+ def get_received(self):
+ return [
+ pkt for direction, pkt in self._packets if direction == PacketDirection.RECV
+ ]
+
+ def __iter__(self):
+ return iter(self._packets)
+
+
class MockGDBServerResponder:
"""
A base class for handling client packets and issuing server responses for
@@ -90,21 +120,33 @@ class MockGDBServerResponder:
registerCount: int = 40
- class RESPONSE_DISCONNECT:
- pass
+ class SpecialResponse(Enum):
+ RESPONSE_DISCONNECT = 0
+ RESPONSE_NONE = 1
- class RESPONSE_NONE:
- pass
+ RESPONSE_DISCONNECT = SpecialResponse.RESPONSE_DISCONNECT
+ RESPONSE_NONE = SpecialResponse.RESPONSE_NONE
+ Response = Union[str, SpecialResponse]
def __init__(self):
- self.packetLog: List[str] = []
+ self.packetLog = PacketLog()
- def respond(self, packet):
+ def respond(self, packet: str) -> Sequence[Response]:
"""
Return the unframed packet data that the server should issue in response
to the given packet received from the client.
"""
- self.packetLog.append(packet)
+ self.packetLog.add_received(packet)
+ response = self._respond_impl(packet)
+ if not isinstance(response, list):
+ response = [response]
+ for part in response:
+ if isinstance(part, self.SpecialResponse):
+ continue
+ self.packetLog.add_sent(part)
+ return response
+
+ def _respond_impl(self, packet) -> Union[Response, List[Response]]:
if packet is MockGDBServer.PACKET_INTERRUPT:
return self.interrupt()
if packet == "c":
@@ -664,17 +706,19 @@ class MockGDBServer:
# adding validation code to make sure the client only sends ACKs
# when it's supposed to.
return
- response = ""
+ response = [""]
# We'll handle the ack stuff here since it's not something any of the
# tests will be concerned about, and it'll get turned off quickly anyway.
if self._shouldSendAck:
self._socket.sendall(seven.bitcast_to_bytes("+"))
if packet == "QStartNoAckMode":
self._shouldSendAck = False
- response = "OK"
+ response = ["OK"]
elif self.responder is not None:
# Delegate everything else to our responder
response = self.responder.respond(packet)
+ # MockGDBServerResponder no longer returns non-lists but others like
+ # ReverseTestBase still do
if not isinstance(response, list):
response = [response]
for part in response:
@@ -682,6 +726,8 @@ class MockGDBServer:
continue
if part is MockGDBServerResponder.RESPONSE_DISCONNECT:
raise self.TerminateConnectionException()
+ # Should have handled the non-str's above
+ assert isinstance(part, str)
self._sendPacket(part)
PACKET_ACK = object()
diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
index 599f787..9b2a89e 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
@@ -10,7 +10,7 @@ class GDBRemoteTestBase(TestBase):
Base class for GDB client tests.
This class will setup and start a mock GDB server for the test to use.
- It also provides assertPacketLogContains, which simplifies the checking
+ It also provides assertPacketLogReceived, which simplifies the checking
of packets sent by the client.
"""
@@ -60,30 +60,32 @@ class GDBRemoteTestBase(TestBase):
self.assertTrue(process, PROCESS_IS_VALID)
return process
- def assertPacketLogContains(self, packets, log=None):
+ def assertPacketLogReceived(self, packets, log: PacketLog = None):
"""
- Assert that the mock server's packet log contains the given packets.
+ Assert that the mock server's packet log received the given packets.
The packet log includes all packets sent by the client and received
- by the server. This fuction makes it easy to verify that the client
+ by the server. This function makes it easy to verify that the client
sent the expected packets to the server.
The check does not require that the packets be consecutive, but does
require that they are ordered in the log as they ordered in the arg.
"""
if log is None:
- log = self.server.responder.packetLog
+ received = self.server.responder.packetLog.get_received()
+ else:
+ received = log.get_received()
i = 0
j = 0
- while i < len(packets) and j < len(log):
- if log[j] == packets[i]:
+ while i < len(packets) and j < len(received):
+ if received[j] == packets[i]:
i += 1
j += 1
if i < len(packets):
self.fail(
"Did not receive: %s\nLast 10 packets:\n\t%s"
- % (packets[i], "\n\t".join(log))
+ % (packets[i], "\n\t".join(received))
)
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index a3d924d..d892c01 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -11,6 +11,7 @@ import subprocess
import signal
import sys
import threading
+import warnings
import time
from typing import (
Any,
@@ -383,6 +384,10 @@ class DebugCommunication(object):
"""Process received packets, updating the session state."""
with self._recv_condition:
for packet in self._recv_packets:
+ if packet and ("seq" not in packet or packet["seq"] == 0):
+ warnings.warn(
+ f"received a malformed packet, expected 'seq != 0' for {packet!r}"
+ )
# Handle events that may modify any stateful properties of
# the DAP session.
if packet and packet["type"] == "event":
@@ -576,6 +581,7 @@ class DebugCommunication(object):
# If we exited, then we are done
if stopped_event["event"] == "exited":
break
+
# Otherwise we stopped and there might be one or more 'stopped'
# events for each thread that stopped with a reason, so keep
# checking for more 'stopped' events and return all of them