Skip to content

Commit 72f4576

Browse files
author
bneradt
committed
Use temp socket path in JSONRPC test
Docker bind mounts can reject Unix-domain socket connects even after the socket inode is created. The JSONRPC Catch test hit that behavior in the Fedora 44 container when its socket was under the bind-mounted tree. This moves the socket and lock into a per-run temporary directory and defers setup to Catch startup so failures are reported by the test framework. This also falls back to a short /tmp path when the temp path would exceed Unix socket limits.
1 parent c0afcac commit 72f4576

1 file changed

Lines changed: 84 additions & 6 deletions

File tree

‎src/mgmt/rpc/server/unit_tests/test_rpcserver.cc‎

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@
2828
#include <sys/socket.h>
2929
#include <sys/un.h>
3030
#include <stdio.h>
31+
#include <unistd.h>
3132

3233
#include <thread>
3334
#include <future>
3435
#include <chrono>
3536
#include <fstream>
37+
#include <cerrno>
38+
#include <cstring>
39+
#include <cstdlib>
40+
#include <vector>
3641

3742
#include "swoc/swoc_file.h"
3843

@@ -71,12 +76,75 @@ add_method_handler(const std::string &name, Func &&call)
7176

7277
namespace
7378
{
74-
const std::string sockPath{"tests/var/jsonrpc20_test.sock"};
75-
const std::string lockPath{"tests/var/jsonrpc20_test.lock"};
76-
constexpr int default_backlog{5};
77-
constexpr int default_maxRetriesOnTransientErrors{64};
78-
constexpr size_t default_incoming_req_max_size{32000 * 3};
79-
DbgCtl dbg_ctl{"rpc.test.client"};
79+
constexpr std::string_view rpc_test_dir_template{"ats_rpc_XXXXXX"};
80+
constexpr std::string_view rpc_test_socket_name{"s"};
81+
constexpr std::string_view rpc_test_lock_name{"l"};
82+
constexpr size_t max_rpc_socket_path_size{sizeof(sockaddr_un::sun_path) - 1};
83+
84+
fs::path rpcTestDir;
85+
std::string sockPath;
86+
std::string lockPath;
87+
constexpr int default_backlog{5};
88+
constexpr int default_maxRetriesOnTransientErrors{64};
89+
constexpr size_t default_incoming_req_max_size{32000 * 3};
90+
DbgCtl dbg_ctl{"rpc.test.client"};
91+
92+
/** Prepare JSONRPC socket paths beneath @a base.
93+
*
94+
* This owns creation of the per-run test directory and publishes the socket
95+
* and lock paths shared by the JSONRPC test server and clients.
96+
*
97+
* @param[in] base Candidate parent directory for the test directory.
98+
* @param[out] error Reason setup failed, if a usable directory was not created.
99+
* @return @c true if the socket and lock paths are ready for this test run.
100+
*/
101+
bool
102+
try_setup_rpc_test_paths(fs::path const &base, std::string &error)
103+
{
104+
auto const dir_template = (base / rpc_test_dir_template).string();
105+
auto const socket_path = (fs::path{dir_template} / rpc_test_socket_name).string();
106+
107+
if (socket_path.size() > max_rpc_socket_path_size) {
108+
error = "JSONRPC test socket path is too long under " + base.string() + ": " + socket_path;
109+
return false;
110+
}
111+
112+
std::vector<char> mutable_template{dir_template.begin(), dir_template.end()};
113+
mutable_template.push_back('\0');
114+
115+
char *created_dir = mkdtemp(mutable_template.data());
116+
if (created_dir == nullptr) {
117+
error = "Failed to create JSONRPC test directory under " + base.string() + ": " + std::strerror(errno);
118+
return false;
119+
}
120+
121+
rpcTestDir = fs::path{created_dir};
122+
sockPath = (rpcTestDir / rpc_test_socket_name).string();
123+
lockPath = (rpcTestDir / rpc_test_lock_name).string();
124+
return true;
125+
}
126+
127+
/** Prepare JSONRPC socket paths for the test run.
128+
*
129+
* This prefers the environment temporary directory, then falls back to @c /tmp
130+
* when the generated Unix-domain socket path would be too long or setup fails.
131+
*
132+
* @param[out] error Reason setup failed, if no candidate directory works.
133+
* @return @c true if the socket and lock paths are ready for this test run.
134+
*/
135+
bool
136+
setup_rpc_test_paths(std::string &error)
137+
{
138+
if (try_setup_rpc_test_paths(fs::temp_directory_path(), error)) {
139+
error.clear();
140+
return true;
141+
}
142+
if (try_setup_rpc_test_paths(fs::path{"/tmp"}, error)) {
143+
error.clear();
144+
return true;
145+
}
146+
return false;
147+
}
80148

81149
} // end anonymous namespace
82150

@@ -88,6 +156,11 @@ struct RPCServerTestListener : Catch::EventListenerBase {
88156
void
89157
testRunStarting(Catch::TestRunInfo const & /* testRunInfo ATS_UNUSED */) override
90158
{
159+
std::string setup_error;
160+
bool const setup_ok = setup_rpc_test_paths(setup_error);
161+
INFO(setup_error);
162+
REQUIRE(setup_ok);
163+
91164
Layout::create();
92165
init_diags("rpc", nullptr);
93166
RecProcessInit();
@@ -123,6 +196,11 @@ struct RPCServerTestListener : Catch::EventListenerBase {
123196
if (jsonrpcServer) {
124197
delete jsonrpcServer; // will stop the thread
125198
}
199+
200+
std::error_code ec;
201+
if (!rpcTestDir.empty()) {
202+
fs::remove_all(rpcTestDir, ec);
203+
}
126204
}
127205

128206
private:

0 commit comments

Comments
 (0)