]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/admin_socket.cc
69bbcedb3cd4af8a2ac52be2c4d965e02f2ddc96
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "common/ceph_mutex.h"
16 #include "common/Cond.h"
17 #include "common/admin_socket.h"
18 #include "common/admin_socket_client.h"
19 #include "common/ceph_argparse.h"
20 #include "gtest/gtest.h"
32 explicit AdminSocketTest(AdminSocket
*asokc
)
36 bool init(const std::string
&uri
) {
37 return m_asokc
->init(uri
);
39 string
bind_and_listen(const std::string
&sock_path
, int *fd
) {
40 return m_asokc
->bind_and_listen(sock_path
, fd
);
49 TEST(AdminSocket
, Teardown
) {
50 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
51 AdminSocketTest
asoct(asokc
.get());
52 ASSERT_EQ(true, asoct
.shutdown());
55 TEST(AdminSocket
, TeardownSetup
) {
56 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
57 AdminSocketTest
asoct(asokc
.get());
58 ASSERT_EQ(true, asoct
.shutdown());
59 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
60 ASSERT_EQ(true, asoct
.shutdown());
63 TEST(AdminSocket
, SendHelp
) {
64 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
65 AdminSocketTest
asoct(asokc
.get());
66 ASSERT_EQ(true, asoct
.shutdown());
67 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
68 AdminSocketClient
client(get_rand_socket_path());
72 ASSERT_EQ("", client
.do_request("{\"prefix\":\"help\"}", &help
));
73 ASSERT_NE(string::npos
, help
.find("\"list available commands\""));
77 ASSERT_EQ("", client
.do_request("{"
78 " \"prefix\":\"help\","
79 " \"format\":\"xml\","
81 ASSERT_NE(string::npos
, help
.find(">list available commands<"));
85 ASSERT_EQ("", client
.do_request("{"
86 " \"prefix\":\"help\","
87 " \"format\":\"UNSUPPORTED\","
89 ASSERT_NE(string::npos
, help
.find("\"list available commands\""));
91 ASSERT_EQ(true, asoct
.shutdown());
94 TEST(AdminSocket
, SendNoOp
) {
95 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
96 AdminSocketTest
asoct(asokc
.get());
97 ASSERT_EQ(true, asoct
.shutdown());
98 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
99 AdminSocketClient
client(get_rand_socket_path());
101 ASSERT_EQ("", client
.do_request("{\"prefix\":\"0\"}", &version
));
102 ASSERT_EQ(CEPH_ADMIN_SOCK_VERSION
, version
);
103 ASSERT_EQ(true, asoct
.shutdown());
106 TEST(AdminSocket
, SendTooLongRequest
) {
107 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
108 AdminSocketTest
asoct(asokc
.get());
109 ASSERT_EQ(true, asoct
.shutdown());
110 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
111 AdminSocketClient
client(get_rand_socket_path());
113 string
request(16384, 'a');
114 //if admin_socket cannot handle it, segfault will happened.
115 ASSERT_NE("", client
.do_request(request
, &version
));
116 ASSERT_EQ(true, asoct
.shutdown());
119 class MyTest
: public AdminSocketHook
{
120 int call(std::string_view command
, const cmdmap_t
& cmdmap
,
123 bufferlist
& result
) override
{
124 std::vector
<std::string
> args
;
125 TOPNSPC::common::cmd_getval(cmdmap
, "args", args
);
126 result
.append(command
);
129 for (std::vector
<std::string
>::iterator it
= args
.begin();
130 it
!= args
.end(); ++it
) {
131 if (it
!= args
.begin())
135 result
.append(resultstr
);
140 TEST(AdminSocket
, RegisterCommand
) {
141 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
142 std::unique_ptr
<AdminSocketHook
> my_test_asok
= std::make_unique
<MyTest
>();
143 AdminSocketTest
asoct(asokc
.get());
144 ASSERT_EQ(true, asoct
.shutdown());
145 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
146 AdminSocketClient
client(get_rand_socket_path());
147 ASSERT_EQ(0, asoct
.m_asokc
->register_command("test", my_test_asok
.get(), ""));
149 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test\"}", &result
));
150 ASSERT_EQ("test|", result
);
151 ASSERT_EQ(true, asoct
.shutdown());
154 class MyTest2
: public AdminSocketHook
{
155 int call(std::string_view command
, const cmdmap_t
& cmdmap
,
158 bufferlist
& result
) override
{
159 std::vector
<std::string
> args
;
160 TOPNSPC::common::cmd_getval(cmdmap
, "args", args
);
161 result
.append(command
);
164 for (std::vector
<std::string
>::iterator it
= args
.begin();
165 it
!= args
.end(); ++it
) {
166 if (it
!= args
.begin())
170 result
.append(resultstr
);
171 ss
<< "error stream";
176 TEST(AdminSocket
, RegisterCommandPrefixes
) {
177 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
178 std::unique_ptr
<AdminSocketHook
> my_test_asok
= std::make_unique
<MyTest
>();
179 std::unique_ptr
<AdminSocketHook
> my_test2_asok
= std::make_unique
<MyTest2
>();
180 AdminSocketTest
asoct(asokc
.get());
181 ASSERT_EQ(true, asoct
.shutdown());
182 ASSERT_EQ(true, asoct
.init(get_rand_socket_path()));
183 AdminSocketClient
client(get_rand_socket_path());
184 ASSERT_EQ(0, asoct
.m_asokc
->register_command("test name=args,type=CephString,n=N", my_test_asok
.get(), ""));
185 ASSERT_EQ(0, asoct
.m_asokc
->register_command("test command name=args,type=CephString,n=N", my_test2_asok
.get(), ""));
187 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test\"}", &result
));
188 ASSERT_EQ("test|", result
);
189 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test command\"}", &result
));
190 ASSERT_EQ("test command|", result
);
191 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test command\",\"args\":[\"post\"]}", &result
));
192 ASSERT_EQ("test command|post", result
);
193 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test command\",\"args\":[\" post\"]}", &result
));
194 ASSERT_EQ("test command| post", result
);
195 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test\",\"args\":[\"this thing\"]}", &result
));
196 ASSERT_EQ("test|this thing", result
);
198 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test\",\"args\":[\" command post\"]}", &result
));
199 ASSERT_EQ("test| command post", result
);
200 ASSERT_EQ("", client
.do_request("{\"prefix\":\"test\",\"args\":[\" this thing\"]}", &result
));
201 ASSERT_EQ("test| this thing", result
);
202 ASSERT_EQ(true, asoct
.shutdown());
205 class BlockingHook
: public AdminSocketHook
{
207 ceph::mutex _lock
= ceph::make_mutex("BlockingHook::_lock");
208 ceph::condition_variable _cond
;
210 BlockingHook() = default;
212 int call(std::string_view command
, const cmdmap_t
& cmdmap
,
215 bufferlist
& result
) override
{
216 std::unique_lock l
{_lock
};
222 TEST(AdminSocketClient
, Ping
) {
223 string path
= get_rand_socket_path();
224 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
225 AdminSocketClient
client(path
);
229 std::string result
= client
.ping(&ok
);
231 // TODO: convert WSA errors.
232 EXPECT_NE(std::string::npos
, result
.find("No such file or directory"));
236 // file exists but does not allow connections (no process, wrong type...)
237 int fd
= ::creat(path
.c_str(), 0777);
239 // On Windows, we won't be able to remove the file unless we close it
241 ASSERT_FALSE(::close(fd
));
244 std::string result
= client
.ping(&ok
);
246 #if defined(__APPLE__) || defined(__FreeBSD__)
247 const char* errmsg
= "Socket operation on non-socket";
249 const char* errmsg
= "Connection refused";
251 EXPECT_NE(std::string::npos
, result
.find(errmsg
));
255 // a daemon is connected to the socket
257 AdminSocketTest
asoct(asokc
.get());
258 ASSERT_TRUE(asoct
.init(path
));
260 std::string result
= client
.ping(&ok
);
261 EXPECT_EQ("", result
);
263 ASSERT_TRUE(asoct
.shutdown());
265 // hardcoded five seconds timeout prevents infinite blockage
267 AdminSocketTest
asoct(asokc
.get());
268 BlockingHook
*blocking
= new BlockingHook();
269 ASSERT_EQ(0, asoct
.m_asokc
->register_command("0", blocking
, ""));
270 ASSERT_TRUE(asoct
.init(path
));
272 std::string result
= client
.ping(&ok
);
274 EXPECT_NE(std::string::npos
, result
.find("Resource temporarily unavailable"));
278 std::lock_guard l
{blocking
->_lock
};
279 blocking
->_cond
.notify_all();
281 ASSERT_TRUE(asoct
.shutdown());
286 TEST(AdminSocket
, bind_and_listen
) {
287 string path
= get_rand_socket_path();
288 std::unique_ptr
<AdminSocket
> asokc
= std::make_unique
<AdminSocket
>(g_ceph_context
);
290 AdminSocketTest
asoct(asokc
.get());
295 message
= asoct
.bind_and_listen(path
, &fd
);
297 ASSERT_EQ("", message
);
298 ASSERT_EQ(0, ::compat_closesocket(fd
));
299 ASSERT_EQ(0, ::unlink(path
.c_str()));
301 // silently discard an existing file
305 int fd2
= ::creat(path
.c_str(), 0777);
307 // On Windows, we won't be able to remove the file unless we close it
309 ASSERT_FALSE(::close(fd2
));
310 message
= asoct
.bind_and_listen(path
, &fd
);
312 ASSERT_EQ("", message
);
313 ASSERT_EQ(0, ::compat_closesocket(fd
));
314 ASSERT_EQ(0, ::unlink(path
.c_str()));
316 // do not take over a live socket
318 ASSERT_TRUE(asoct
.init(path
));
321 message
= asoct
.bind_and_listen(path
, &fd
);
322 std::cout
<< "message: " << message
<< std::endl
;
323 EXPECT_NE(std::string::npos
, message
.find("File exists"));
324 ASSERT_TRUE(asoct
.shutdown());
330 * compile-command: "cd .. ;
331 * make unittest_admin_socket &&
333 * --max-stackframe=20000000 --tool=memcheck \
334 * ./unittest_admin_socket --debug-asok 20 # --gtest_filter=AdminSocket*.*