[Lldb-commits] [lldb] [lldb] Implement JSON RPC (newline delimited) Transport (PR #143946)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 12 13:25:02 PDT 2025
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/143946
>From 9ebb3986e008cec978c0111557a02a9a8d720838 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 12 Jun 2025 11:19:15 -0700
Subject: [PATCH 1/3] [lldb] Implement JSON RPC (newline delimited) Transport
This PR implements JSON RPC-style (i.e. newline delimited) JSON
transport. I moved the existing transport tests from DAP to Host and
moved the PipeTest base class into TestingSupport so it can be shared by
both.
---
lldb/include/lldb/Host/JSONTransport.h | 15 ++
lldb/source/Host/common/JSONTransport.cpp | 31 +++-
lldb/unittests/DAP/CMakeLists.txt | 1 -
lldb/unittests/DAP/TestBase.cpp | 7 +-
lldb/unittests/DAP/TestBase.h | 13 +-
lldb/unittests/DAP/TransportTest.cpp | 98 ------------
lldb/unittests/Host/CMakeLists.txt | 1 +
lldb/unittests/Host/JSONTransportTest.cpp | 146 ++++++++++++++++++
.../TestingSupport/Host/PipeTestUtilities.h | 28 ++++
9 files changed, 223 insertions(+), 117 deletions(-)
delete mode 100644 lldb/unittests/DAP/TransportTest.cpp
create mode 100644 lldb/unittests/Host/JSONTransportTest.cpp
create mode 100644 lldb/unittests/TestingSupport/Host/PipeTestUtilities.h
diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h
index 4db5e417ea852..f7593750669e1 100644
--- a/lldb/include/lldb/Host/JSONTransport.h
+++ b/lldb/include/lldb/Host/JSONTransport.h
@@ -121,6 +121,21 @@ class HTTPDelimitedJSONTransport : public JSONTransport {
static constexpr llvm::StringLiteral kHeaderSeparator = "\r\n\r\n";
};
+/// A transport class for JSON RPC.
+class JSONRPCTransport : public JSONTransport {
+public:
+ JSONRPCTransport(lldb::IOObjectSP input, lldb::IOObjectSP output)
+ : JSONTransport(input, output) {}
+ virtual ~JSONRPCTransport() = default;
+
+protected:
+ virtual llvm::Error WriteImpl(const std::string &message) override;
+ virtual llvm::Expected<std::string>
+ ReadImpl(const std::chrono::microseconds &timeout) override;
+
+ static constexpr llvm::StringLiteral kMessageSeparator = "\n";
+};
+
} // namespace lldb_private
#endif
diff --git a/lldb/source/Host/common/JSONTransport.cpp b/lldb/source/Host/common/JSONTransport.cpp
index 103c76d25daf7..7b925372e0b74 100644
--- a/lldb/source/Host/common/JSONTransport.cpp
+++ b/lldb/source/Host/common/JSONTransport.cpp
@@ -92,7 +92,7 @@ void JSONTransport::Log(llvm::StringRef message) {
Expected<std::string>
HTTPDelimitedJSONTransport::ReadImpl(const std::chrono::microseconds &timeout) {
if (!m_input || !m_input->IsValid())
- return createStringError("transport output is closed");
+ return llvm::make_error<TransportClosedError>();
IOObject *input = m_input.get();
Expected<std::string> message_header =
@@ -142,6 +142,35 @@ Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
return m_output->Write(Output.data(), num_bytes).takeError();
}
+Expected<std::string>
+JSONRPCTransport::ReadImpl(const std::chrono::microseconds &timeout) {
+ if (!m_input || !m_input->IsValid())
+ return make_error<TransportClosedError>();
+
+ IOObject *input = m_input.get();
+ Expected<std::string> raw_json =
+ ReadUntil(*input, kMessageSeparator, timeout);
+ if (!raw_json)
+ return raw_json.takeError();
+
+ Log(llvm::formatv("--> {0}", *raw_json).str());
+
+ return *raw_json;
+}
+
+Error JSONRPCTransport::WriteImpl(const std::string &message) {
+ if (!m_output || !m_output->IsValid())
+ return llvm::make_error<TransportClosedError>();
+
+ Log(llvm::formatv("<-- {0}", message).str());
+
+ std::string Output;
+ llvm::raw_string_ostream OS(Output);
+ OS << message << kMessageSeparator;
+ size_t num_bytes = Output.size();
+ return m_output->Write(Output.data(), num_bytes).takeError();
+}
+
char TransportEOFError::ID;
char TransportTimeoutError::ID;
char TransportClosedError::ID;
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index 37a6a81ad12a0..ee623d341ec69 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -7,7 +7,6 @@ add_lldb_unittest(DAPTests
LLDBUtilsTest.cpp
ProtocolTypesTest.cpp
TestBase.cpp
- TransportTest.cpp
VariablesTest.cpp
LINK_COMPONENTS
diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp
index 4063b34250312..27ad42686fbbf 100644
--- a/lldb/unittests/DAP/TestBase.cpp
+++ b/lldb/unittests/DAP/TestBase.cpp
@@ -28,13 +28,8 @@ using lldb_private::File;
using lldb_private::NativeFile;
using lldb_private::Pipe;
-void PipeBase::SetUp() {
- ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded());
- ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded());
-}
-
void TransportBase::SetUp() {
- PipeBase::SetUp();
+ PipeTest::SetUp();
to_dap = std::make_unique<Transport>(
"to_dap", nullptr,
std::make_shared<NativeFile>(input.GetReadFileDescriptor(),
diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h
index 70b3985271a92..25d37013954d5 100644
--- a/lldb/unittests/DAP/TestBase.h
+++ b/lldb/unittests/DAP/TestBase.h
@@ -8,26 +8,17 @@
#include "DAP.h"
#include "Protocol/ProtocolBase.h"
+#include "TestingSupport/Host/PipeTestUtilities.h"
#include "Transport.h"
-#include "lldb/Host/Pipe.h"
#include "llvm/ADT/StringRef.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace lldb_dap_tests {
-/// A base class for tests that need a pair of pipes for communication.
-class PipeBase : public testing::Test {
-protected:
- lldb_private::Pipe input;
- lldb_private::Pipe output;
-
- void SetUp() override;
-};
-
/// A base class for tests that need transport configured for communicating DAP
/// messages.
-class TransportBase : public PipeBase {
+class TransportBase : public PipeTest {
protected:
std::unique_ptr<lldb_dap::Transport> to_dap;
std::unique_ptr<lldb_dap::Transport> from_dap;
diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp
deleted file mode 100644
index aaf257993af23..0000000000000
--- a/lldb/unittests/DAP/TransportTest.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//===-- TransportTest.cpp -------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Transport.h"
-#include "Protocol/ProtocolBase.h"
-#include "TestBase.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/Pipe.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-#include <chrono>
-#include <memory>
-#include <optional>
-
-using namespace llvm;
-using namespace lldb;
-using namespace lldb_dap;
-using namespace lldb_dap_tests;
-using namespace lldb_dap::protocol;
-using lldb_private::File;
-using lldb_private::NativeFile;
-using lldb_private::Pipe;
-using lldb_private::TransportEOFError;
-using lldb_private::TransportTimeoutError;
-
-class TransportTest : public PipeBase {
-protected:
- std::unique_ptr<Transport> transport;
-
- void SetUp() override {
- PipeBase::SetUp();
- transport = std::make_unique<Transport>(
- "stdio", nullptr,
- std::make_shared<NativeFile>(input.GetReadFileDescriptor(),
- File::eOpenOptionReadOnly,
- NativeFile::Unowned),
- std::make_shared<NativeFile>(output.GetWriteFileDescriptor(),
- File::eOpenOptionWriteOnly,
- NativeFile::Unowned));
- }
-};
-
-TEST_F(TransportTest, MalformedRequests) {
- std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn";
- ASSERT_THAT_EXPECTED(
- input.Write(malformed_header.data(), malformed_header.size()),
- Succeeded());
- ASSERT_THAT_EXPECTED(
- transport->Read<protocol::Message>(std::chrono::milliseconds(1)),
- FailedWithMessage(
- "expected 'Content-Length: ' and got 'COnTent-LenGth: '"));
-}
-
-TEST_F(TransportTest, Read) {
- std::string json =
- R"json({"seq": 1, "type": "request", "command": "abc"})json";
- std::string message =
- formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str();
- ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()),
- Succeeded());
- ASSERT_THAT_EXPECTED(
- transport->Read<protocol::Message>(std::chrono::milliseconds(1)),
- HasValue(testing::VariantWith<Request>(testing::FieldsAre(
- /*seq=*/1, /*command=*/"abc", /*arguments=*/std::nullopt))));
-}
-
-TEST_F(TransportTest, ReadWithTimeout) {
- ASSERT_THAT_EXPECTED(
- transport->Read<protocol::Message>(std::chrono::milliseconds(1)),
- Failed<TransportTimeoutError>());
-}
-
-TEST_F(TransportTest, ReadWithEOF) {
- input.CloseWriteFileDescriptor();
- ASSERT_THAT_EXPECTED(
- transport->Read<protocol::Message>(std::chrono::milliseconds(1)),
- Failed<TransportEOFError>());
-}
-
-TEST_F(TransportTest, Write) {
- ASSERT_THAT_ERROR(transport->Write(Event{"my-event", std::nullopt}),
- Succeeded());
- output.CloseWriteFileDescriptor();
- char buf[1024];
- Expected<size_t> bytes_read =
- output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));
- ASSERT_THAT_EXPECTED(bytes_read, Succeeded());
- ASSERT_EQ(
- StringRef(buf, *bytes_read),
- StringRef("Content-Length: 43\r\n\r\n"
- R"json({"event":"my-event","seq":0,"type":"event"})json"));
-}
diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt
index 5b8deed00af88..3b20f1d723d18 100644
--- a/lldb/unittests/Host/CMakeLists.txt
+++ b/lldb/unittests/Host/CMakeLists.txt
@@ -6,6 +6,7 @@ set (FILES
HostInfoTest.cpp
HostTest.cpp
MainLoopTest.cpp
+ JSONTransportTest.cpp
NativeProcessProtocolTest.cpp
PipeTest.cpp
ProcessLaunchInfoTest.cpp
diff --git a/lldb/unittests/Host/JSONTransportTest.cpp b/lldb/unittests/Host/JSONTransportTest.cpp
new file mode 100644
index 0000000000000..bb7958b4e95b5
--- /dev/null
+++ b/lldb/unittests/Host/JSONTransportTest.cpp
@@ -0,0 +1,146 @@
+//===-- JSONTransportTest.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/JSONTransport.h"
+#include "TestingSupport/Host/PipeTestUtilities.h"
+#include "lldb/Host/File.h"
+
+using namespace llvm;
+using namespace lldb_private;
+
+namespace {
+template <typename T> class JSONTransportTest : public PipeTest {
+protected:
+ std::unique_ptr<JSONTransport> transport;
+
+ void SetUp() override {
+ PipeTest::SetUp();
+ transport = std::make_unique<T>(
+ std::make_shared<NativeFile>(input.GetReadFileDescriptor(),
+ File::eOpenOptionReadOnly,
+ NativeFile::Unowned),
+ std::make_shared<NativeFile>(output.GetWriteFileDescriptor(),
+ File::eOpenOptionWriteOnly,
+ NativeFile::Unowned));
+ }
+};
+
+class HTTPDelimitedJSONTransportTest
+ : public JSONTransportTest<HTTPDelimitedJSONTransport> {
+public:
+ using JSONTransportTest::JSONTransportTest;
+};
+
+class JSONRPCTransportTest : public JSONTransportTest<JSONRPCTransport> {
+public:
+ using JSONTransportTest::JSONTransportTest;
+};
+
+struct JSONTestType {
+ std::string str;
+};
+
+llvm::json::Value toJSON(const JSONTestType &T) {
+ return llvm::json::Object{{"str", T.str}};
+}
+
+bool fromJSON(const llvm::json::Value &V, JSONTestType &T, llvm::json::Path P) {
+ llvm::json::ObjectMapper O(V, P);
+ return O && O.map("str", T.str);
+}
+} // namespace
+
+TEST_F(HTTPDelimitedJSONTransportTest, MalformedRequests) {
+ std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn";
+ ASSERT_THAT_EXPECTED(
+ input.Write(malformed_header.data(), malformed_header.size()),
+ Succeeded());
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ FailedWithMessage(
+ "expected 'Content-Length: ' and got 'COnTent-LenGth: '"));
+}
+
+TEST_F(HTTPDelimitedJSONTransportTest, Read) {
+ std::string json = R"json({"str": "foo"})json";
+ std::string message =
+ formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str();
+ ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()),
+ Succeeded());
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ HasValue(testing::FieldsAre(/*str=*/"foo")));
+}
+
+TEST_F(HTTPDelimitedJSONTransportTest, ReadWithTimeout) {
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportTimeoutError>());
+}
+
+TEST_F(HTTPDelimitedJSONTransportTest, ReadWithEOF) {
+ input.CloseWriteFileDescriptor();
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportEOFError>());
+}
+
+TEST_F(HTTPDelimitedJSONTransportTest, Write) {
+ ASSERT_THAT_ERROR(transport->Write(JSONTestType{"foo"}), Succeeded());
+ output.CloseWriteFileDescriptor();
+ char buf[1024];
+ Expected<size_t> bytes_read =
+ output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));
+ ASSERT_THAT_EXPECTED(bytes_read, Succeeded());
+ ASSERT_EQ(StringRef(buf, *bytes_read), StringRef("Content-Length: 13\r\n\r\n"
+ R"json({"str":"foo"})json"));
+}
+
+TEST_F(JSONRPCTransportTest, MalformedRequests) {
+ std::string malformed_header = "notjson\n";
+ ASSERT_THAT_EXPECTED(
+ input.Write(malformed_header.data(), malformed_header.size()),
+ Succeeded());
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ llvm::Failed());
+}
+
+TEST_F(JSONRPCTransportTest, Read) {
+ std::string json = R"json({"str": "foo"})json";
+ std::string message = formatv("{0}\n", json).str();
+ ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()),
+ Succeeded());
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ HasValue(testing::FieldsAre(/*str=*/"foo")));
+}
+
+TEST_F(JSONRPCTransportTest, ReadWithTimeout) {
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportTimeoutError>());
+}
+
+TEST_F(JSONRPCTransportTest, ReadWithEOF) {
+ input.CloseWriteFileDescriptor();
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportEOFError>());
+}
+
+TEST_F(JSONRPCTransportTest, Write) {
+ ASSERT_THAT_ERROR(transport->Write(JSONTestType{"foo"}), Succeeded());
+ output.CloseWriteFileDescriptor();
+ char buf[1024];
+ Expected<size_t> bytes_read =
+ output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));
+ ASSERT_THAT_EXPECTED(bytes_read, Succeeded());
+ ASSERT_EQ(StringRef(buf, *bytes_read), StringRef(R"json({"str":"foo"})json"
+ "\n"));
+}
diff --git a/lldb/unittests/TestingSupport/Host/PipeTestUtilities.h b/lldb/unittests/TestingSupport/Host/PipeTestUtilities.h
new file mode 100644
index 0000000000000..50d5d4117c898
--- /dev/null
+++ b/lldb/unittests/TestingSupport/Host/PipeTestUtilities.h
@@ -0,0 +1,28 @@
+//===-- PipeTestUtilities.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_PIPETESTUTILITIES_H
+#define LLDB_UNITTESTS_TESTINGSUPPORT_PIPETESTUTILITIES_H
+
+#include "lldb/Host/Pipe.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+/// A base class for tests that need a pair of pipes for communication.
+class PipeTest : public testing::Test {
+protected:
+ lldb_private::Pipe input;
+ lldb_private::Pipe output;
+
+ void SetUp() override {
+ ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded());
+ ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded());
+ }
+};
+
+#endif
>From 5e62a8abc21e2ab1f60937d1158b95c5962e34d9 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 12 Jun 2025 12:58:33 -0700
Subject: [PATCH 2/3] Rename error, add more tests
---
lldb/include/lldb/Host/JSONTransport.h | 8 +++----
lldb/source/Host/common/JSONTransport.cpp | 12 +++++-----
lldb/unittests/Host/JSONTransportTest.cpp | 28 +++++++++++++++++++++++
3 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h
index f7593750669e1..4087cdf2b42f7 100644
--- a/lldb/include/lldb/Host/JSONTransport.h
+++ b/lldb/include/lldb/Host/JSONTransport.h
@@ -51,17 +51,17 @@ class TransportTimeoutError : public llvm::ErrorInfo<TransportTimeoutError> {
}
};
-class TransportClosedError : public llvm::ErrorInfo<TransportClosedError> {
+class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> {
public:
static char ID;
- TransportClosedError() = default;
+ TransportInvalidError() = default;
void log(llvm::raw_ostream &OS) const override {
- OS << "transport is closed";
+ OS << "transport IO object invalid";
}
std::error_code convertToErrorCode() const override {
- return llvm::inconvertibleErrorCode();
+ return std::make_error_code(std::errc::not_connected);
}
};
diff --git a/lldb/source/Host/common/JSONTransport.cpp b/lldb/source/Host/common/JSONTransport.cpp
index 7b925372e0b74..1a0851d5c4365 100644
--- a/lldb/source/Host/common/JSONTransport.cpp
+++ b/lldb/source/Host/common/JSONTransport.cpp
@@ -31,7 +31,7 @@ static Expected<std::string>
ReadFull(IOObject &descriptor, size_t length,
std::optional<std::chrono::microseconds> timeout = std::nullopt) {
if (!descriptor.IsValid())
- return llvm::make_error<TransportClosedError>();
+ return llvm::make_error<TransportInvalidError>();
bool timeout_supported = true;
// FIXME: SelectHelper does not work with NativeFile on Win32.
@@ -92,7 +92,7 @@ void JSONTransport::Log(llvm::StringRef message) {
Expected<std::string>
HTTPDelimitedJSONTransport::ReadImpl(const std::chrono::microseconds &timeout) {
if (!m_input || !m_input->IsValid())
- return llvm::make_error<TransportClosedError>();
+ return llvm::make_error<TransportInvalidError>();
IOObject *input = m_input.get();
Expected<std::string> message_header =
@@ -131,7 +131,7 @@ HTTPDelimitedJSONTransport::ReadImpl(const std::chrono::microseconds &timeout) {
Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
if (!m_output || !m_output->IsValid())
- return llvm::make_error<TransportClosedError>();
+ return llvm::make_error<TransportInvalidError>();
Log(llvm::formatv("<-- {0}", message).str());
@@ -145,7 +145,7 @@ Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
Expected<std::string>
JSONRPCTransport::ReadImpl(const std::chrono::microseconds &timeout) {
if (!m_input || !m_input->IsValid())
- return make_error<TransportClosedError>();
+ return make_error<TransportInvalidError>();
IOObject *input = m_input.get();
Expected<std::string> raw_json =
@@ -160,7 +160,7 @@ JSONRPCTransport::ReadImpl(const std::chrono::microseconds &timeout) {
Error JSONRPCTransport::WriteImpl(const std::string &message) {
if (!m_output || !m_output->IsValid())
- return llvm::make_error<TransportClosedError>();
+ return llvm::make_error<TransportInvalidError>();
Log(llvm::formatv("<-- {0}", message).str());
@@ -173,4 +173,4 @@ Error JSONRPCTransport::WriteImpl(const std::string &message) {
char TransportEOFError::ID;
char TransportTimeoutError::ID;
-char TransportClosedError::ID;
+char TransportInvalidError::ID;
diff --git a/lldb/unittests/Host/JSONTransportTest.cpp b/lldb/unittests/Host/JSONTransportTest.cpp
index bb7958b4e95b5..90e0c504e6720 100644
--- a/lldb/unittests/Host/JSONTransportTest.cpp
+++ b/lldb/unittests/Host/JSONTransportTest.cpp
@@ -90,6 +90,20 @@ TEST_F(HTTPDelimitedJSONTransportTest, ReadWithEOF) {
Failed<TransportEOFError>());
}
+TEST_F(HTTPDelimitedJSONTransportTest, ReadAfterClosed) {
+ input.CloseReadFileDescriptor();
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ llvm::Failed());
+}
+
+TEST_F(HTTPDelimitedJSONTransportTest, InvalidTransport) {
+ transport = std::make_unique<HTTPDelimitedJSONTransport>(nullptr, nullptr);
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportInvalidError>());
+}
+
TEST_F(HTTPDelimitedJSONTransportTest, Write) {
ASSERT_THAT_ERROR(transport->Write(JSONTestType{"foo"}), Succeeded());
output.CloseWriteFileDescriptor();
@@ -134,6 +148,13 @@ TEST_F(JSONRPCTransportTest, ReadWithEOF) {
Failed<TransportEOFError>());
}
+TEST_F(JSONRPCTransportTest, ReadAfterClosed) {
+ input.CloseReadFileDescriptor();
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ llvm::Failed());
+}
+
TEST_F(JSONRPCTransportTest, Write) {
ASSERT_THAT_ERROR(transport->Write(JSONTestType{"foo"}), Succeeded());
output.CloseWriteFileDescriptor();
@@ -144,3 +165,10 @@ TEST_F(JSONRPCTransportTest, Write) {
ASSERT_EQ(StringRef(buf, *bytes_read), StringRef(R"json({"str":"foo"})json"
"\n"));
}
+
+TEST_F(JSONRPCTransportTest, InvalidTransport) {
+ transport = std::make_unique<JSONRPCTransport>(nullptr, nullptr);
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportInvalidError>());
+}
>From e48ac8217037cd90f16b7cb314fbee097d67b566 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 12 Jun 2025 13:24:49 -0700
Subject: [PATCH 3/3] Guard timeout tests on Windows
---
lldb/unittests/Host/JSONTransportTest.cpp | 26 ++++++++++++-----------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/lldb/unittests/Host/JSONTransportTest.cpp b/lldb/unittests/Host/JSONTransportTest.cpp
index 90e0c504e6720..f1ec5e03bbeca 100644
--- a/lldb/unittests/Host/JSONTransportTest.cpp
+++ b/lldb/unittests/Host/JSONTransportTest.cpp
@@ -77,12 +77,6 @@ TEST_F(HTTPDelimitedJSONTransportTest, Read) {
HasValue(testing::FieldsAre(/*str=*/"foo")));
}
-TEST_F(HTTPDelimitedJSONTransportTest, ReadWithTimeout) {
- ASSERT_THAT_EXPECTED(
- transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
- Failed<TransportTimeoutError>());
-}
-
TEST_F(HTTPDelimitedJSONTransportTest, ReadWithEOF) {
input.CloseWriteFileDescriptor();
ASSERT_THAT_EXPECTED(
@@ -135,12 +129,6 @@ TEST_F(JSONRPCTransportTest, Read) {
HasValue(testing::FieldsAre(/*str=*/"foo")));
}
-TEST_F(JSONRPCTransportTest, ReadWithTimeout) {
- ASSERT_THAT_EXPECTED(
- transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
- Failed<TransportTimeoutError>());
-}
-
TEST_F(JSONRPCTransportTest, ReadWithEOF) {
input.CloseWriteFileDescriptor();
ASSERT_THAT_EXPECTED(
@@ -172,3 +160,17 @@ TEST_F(JSONRPCTransportTest, InvalidTransport) {
transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
Failed<TransportInvalidError>());
}
+
+#ifndef _WIN32
+TEST_F(HTTPDelimitedJSONTransportTest, ReadWithTimeout) {
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportTimeoutError>());
+}
+
+TEST_F(JSONRPCTransportTest, ReadWithTimeout) {
+ ASSERT_THAT_EXPECTED(
+ transport->Read<JSONTestType>(std::chrono::milliseconds(1)),
+ Failed<TransportTimeoutError>());
+}
+#endif
More information about the lldb-commits
mailing list