xref: /llvm-project/llvm/unittests/Support/raw_socket_stream_test.cpp (revision 76321b9f08ef31a2b8ca26f7522aee511a05f7a8)
1 #include "llvm/ADT/SmallString.h"
2 #include "llvm/Config/llvm-config.h"
3 #include "llvm/Support/Casting.h"
4 #include "llvm/Support/FileSystem.h"
5 #include "llvm/Support/FileUtilities.h"
6 #include "llvm/Support/raw_socket_stream.h"
7 #include "llvm/Testing/Support/Error.h"
8 #include "gtest/gtest.h"
9 #include <future>
10 #include <stdlib.h>
11 #include <thread>
12 
13 #ifdef _WIN32
14 #include "llvm/Support/Windows/WindowsSupport.h"
15 #endif
16 
17 using namespace llvm;
18 
19 namespace {
20 
21 bool hasUnixSocketSupport() {
22 #ifdef _WIN32
23   VersionTuple Ver = GetWindowsOSVersion();
24   if (Ver < VersionTuple(10, 0, 0, 17063))
25     return false;
26 #endif
27   return true;
28 }
29 
30 TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
31   if (!hasUnixSocketSupport())
32     GTEST_SKIP();
33 
34   SmallString<100> SocketPath;
35   llvm::sys::fs::createUniquePath("client_server_comms.sock", SocketPath, true);
36 
37   // Make sure socket file does not exist. May still be there from the last test
38   std::remove(SocketPath.c_str());
39 
40   Expected<ListeningSocket> MaybeServerListener =
41       ListeningSocket::createUnix(SocketPath);
42   ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
43 
44   ListeningSocket ServerListener = std::move(*MaybeServerListener);
45 
46   Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
47       raw_socket_stream::createConnectedUnix(SocketPath);
48   ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
49 
50   raw_socket_stream &Client = **MaybeClient;
51 
52   Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
53       ServerListener.accept();
54   ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
55 
56   raw_socket_stream &Server = **MaybeServer;
57 
58   Client << "01234567";
59   Client.flush();
60 
61   char Bytes[8];
62   ssize_t BytesRead = Server.read(Bytes, 8);
63 
64   std::string string(Bytes, 8);
65   ASSERT_EQ(Server.has_error(), false);
66 
67   ASSERT_EQ(8, BytesRead);
68   ASSERT_EQ("01234567", string);
69 }
70 
71 TEST(raw_socket_streamTest, READ_WITH_TIMEOUT) {
72   if (!hasUnixSocketSupport())
73     GTEST_SKIP();
74 
75   SmallString<100> SocketPath;
76   llvm::sys::fs::createUniquePath("read_with_timeout.sock", SocketPath, true);
77 
78   // Make sure socket file does not exist. May still be there from the last test
79   std::remove(SocketPath.c_str());
80 
81   Expected<ListeningSocket> MaybeServerListener =
82       ListeningSocket::createUnix(SocketPath);
83   ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
84   ListeningSocket ServerListener = std::move(*MaybeServerListener);
85 
86   Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
87       raw_socket_stream::createConnectedUnix(SocketPath);
88   ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
89 
90   Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
91       ServerListener.accept();
92   ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
93   raw_socket_stream &Server = **MaybeServer;
94 
95   char Bytes[8];
96   ssize_t BytesRead = Server.read(Bytes, 8, std::chrono::milliseconds(100));
97   ASSERT_EQ(BytesRead, -1);
98   ASSERT_EQ(Server.has_error(), true);
99   ASSERT_EQ(Server.error(), std::errc::timed_out);
100   Server.clear_error();
101 }
102 
103 TEST(raw_socket_streamTest, ACCEPT_WITH_TIMEOUT) {
104   if (!hasUnixSocketSupport())
105     GTEST_SKIP();
106 
107   SmallString<100> SocketPath;
108   llvm::sys::fs::createUniquePath("accept_with_timeout.sock", SocketPath, true);
109 
110   // Make sure socket file does not exist. May still be there from the last test
111   std::remove(SocketPath.c_str());
112 
113   Expected<ListeningSocket> MaybeServerListener =
114       ListeningSocket::createUnix(SocketPath);
115   ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
116   ListeningSocket ServerListener = std::move(*MaybeServerListener);
117 
118   Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
119       ServerListener.accept(std::chrono::milliseconds(100));
120   ASSERT_EQ(llvm::errorToErrorCode(MaybeServer.takeError()),
121             std::errc::timed_out);
122 }
123 
124 TEST(raw_socket_streamTest, ACCEPT_WITH_SHUTDOWN) {
125   if (!hasUnixSocketSupport())
126     GTEST_SKIP();
127 
128   SmallString<100> SocketPath;
129   llvm::sys::fs::createUniquePath("accept_with_shutdown.sock", SocketPath,
130                                   true);
131 
132   // Make sure socket file does not exist. May still be there from the last test
133   std::remove(SocketPath.c_str());
134 
135   Expected<ListeningSocket> MaybeServerListener =
136       ListeningSocket::createUnix(SocketPath);
137   ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
138   ListeningSocket ServerListener = std::move(*MaybeServerListener);
139 
140   // Create a separate thread to close the socket after a delay. Simulates a
141   // signal handler calling ServerListener::shutdown
142   std::thread CloseThread([&]() {
143     std::this_thread::sleep_for(std::chrono::milliseconds(500));
144     ServerListener.shutdown();
145   });
146 
147   Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
148       ServerListener.accept();
149 
150   // Wait for the CloseThread to finish
151   CloseThread.join();
152   ASSERT_EQ(llvm::errorToErrorCode(MaybeServer.takeError()),
153             std::errc::operation_canceled);
154 }
155 } // namespace
156