]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/admin_socket.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / test / admin_socket.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
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.
12 *
13 */
14
15 #include "common/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"
21
22 #include <stdint.h>
23 #include <string.h>
24 #include <string>
25 #include <sys/un.h>
26
27 class AdminSocketTest
28 {
29 public:
30 explicit AdminSocketTest(AdminSocket *asokc)
31 : m_asokc(asokc)
32 {
33 }
34 bool init(const std::string &uri) {
35 return m_asokc->init(uri);
36 }
37 string bind_and_listen(const std::string &sock_path, int *fd) {
38 return m_asokc->bind_and_listen(sock_path, fd);
39 }
40 bool shutdown() {
41 m_asokc->shutdown();
42 return true;
43 }
44 AdminSocket *m_asokc;
45 };
46
47 TEST(AdminSocket, Teardown) {
48 std::unique_ptr<AdminSocket>
49 asokc(new AdminSocket(g_ceph_context));
50 AdminSocketTest asoct(asokc.get());
51 ASSERT_EQ(true, asoct.shutdown());
52 }
53
54 TEST(AdminSocket, TeardownSetup) {
55 std::unique_ptr<AdminSocket>
56 asokc(new 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());
61 }
62
63 TEST(AdminSocket, SendHelp) {
64 std::unique_ptr<AdminSocket>
65 asokc(new AdminSocket(g_ceph_context));
66 AdminSocketTest asoct(asokc.get());
67 ASSERT_EQ(true, asoct.shutdown());
68 ASSERT_EQ(true, asoct.init(get_rand_socket_path()));
69 AdminSocketClient client(get_rand_socket_path());
70
71 {
72 string help;
73 ASSERT_EQ("", client.do_request("{\"prefix\":\"help\"}", &help));
74 ASSERT_NE(string::npos, help.find("\"list available commands\""));
75 }
76 {
77 string help;
78 ASSERT_EQ("", client.do_request("{"
79 " \"prefix\":\"help\","
80 " \"format\":\"xml\","
81 "}", &help));
82 ASSERT_NE(string::npos, help.find(">list available commands<"));
83 }
84 {
85 string help;
86 ASSERT_EQ("", client.do_request("{"
87 " \"prefix\":\"help\","
88 " \"format\":\"UNSUPPORTED\","
89 "}", &help));
90 ASSERT_NE(string::npos, help.find("\"list available commands\""));
91 }
92 ASSERT_EQ(true, asoct.shutdown());
93 }
94
95 TEST(AdminSocket, SendNoOp) {
96 std::unique_ptr<AdminSocket>
97 asokc(new AdminSocket(g_ceph_context));
98 AdminSocketTest asoct(asokc.get());
99 ASSERT_EQ(true, asoct.shutdown());
100 ASSERT_EQ(true, asoct.init(get_rand_socket_path()));
101 AdminSocketClient client(get_rand_socket_path());
102 string version;
103 ASSERT_EQ("", client.do_request("{\"prefix\":\"0\"}", &version));
104 ASSERT_EQ(CEPH_ADMIN_SOCK_VERSION, version);
105 ASSERT_EQ(true, asoct.shutdown());
106 }
107
108 TEST(AdminSocket, SendTooLongRequest) {
109 std::unique_ptr<AdminSocket>
110 asokc(new AdminSocket(g_ceph_context));
111 AdminSocketTest asoct(asokc.get());
112 ASSERT_EQ(true, asoct.shutdown());
113 ASSERT_EQ(true, asoct.init(get_rand_socket_path()));
114 AdminSocketClient client(get_rand_socket_path());
115 string version;
116 string request(16384, 'a');
117 //if admin_socket cannot handle it, segfault will happened.
118 ASSERT_NE("", client.do_request(request, &version));
119 ASSERT_EQ(true, asoct.shutdown());
120 }
121
122 class MyTest : public AdminSocketHook {
123 bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& result) override {
124 std::vector<std::string> args;
125 cmd_getval(g_ceph_context, cmdmap, "args", args);
126 result.append(command);
127 result.append("|");
128 string resultstr;
129 for (std::vector<std::string>::iterator it = args.begin();
130 it != args.end(); ++it) {
131 if (it != args.begin())
132 resultstr += ' ';
133 resultstr += *it;
134 }
135 result.append(resultstr);
136 return true;
137 }
138 };
139
140 TEST(AdminSocket, RegisterCommand) {
141 std::unique_ptr<AdminSocket>
142 asokc(new AdminSocket(g_ceph_context));
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", "test", new MyTest(), ""));
148 string result;
149 ASSERT_EQ("", client.do_request("{\"prefix\":\"test\"}", &result));
150 ASSERT_EQ("test|", result);
151 ASSERT_EQ(true, asoct.shutdown());
152 }
153
154 class MyTest2 : public AdminSocketHook {
155 bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& result) override {
156 std::vector<std::string> args;
157 cmd_getval(g_ceph_context, cmdmap, "args", args);
158 result.append(command);
159 result.append("|");
160 string resultstr;
161 for (std::vector<std::string>::iterator it = args.begin();
162 it != args.end(); ++it) {
163 if (it != args.begin())
164 resultstr += ' ';
165 resultstr += *it;
166 }
167 result.append(resultstr);
168 return true;
169 }
170 };
171
172 TEST(AdminSocket, RegisterCommandPrefixes) {
173 std::unique_ptr<AdminSocket>
174 asokc(new AdminSocket(g_ceph_context));
175 AdminSocketTest asoct(asokc.get());
176 ASSERT_EQ(true, asoct.shutdown());
177 ASSERT_EQ(true, asoct.init(get_rand_socket_path()));
178 AdminSocketClient client(get_rand_socket_path());
179 ASSERT_EQ(0, asoct.m_asokc->register_command("test", "test name=args,type=CephString,n=N", new MyTest(), ""));
180 ASSERT_EQ(0, asoct.m_asokc->register_command("test command", "test command name=args,type=CephString,n=N", new MyTest2(), ""));
181 string result;
182 ASSERT_EQ("", client.do_request("{\"prefix\":\"test\"}", &result));
183 ASSERT_EQ("test|", result);
184 ASSERT_EQ("", client.do_request("{\"prefix\":\"test command\"}", &result));
185 ASSERT_EQ("test command|", result);
186 ASSERT_EQ("", client.do_request("{\"prefix\":\"test command\",\"args\":[\"post\"]}", &result));
187 ASSERT_EQ("test command|post", result);
188 ASSERT_EQ("", client.do_request("{\"prefix\":\"test command\",\"args\":[\" post\"]}", &result));
189 ASSERT_EQ("test command| post", result);
190 ASSERT_EQ("", client.do_request("{\"prefix\":\"test\",\"args\":[\"this thing\"]}", &result));
191 ASSERT_EQ("test|this thing", result);
192
193 ASSERT_EQ("", client.do_request("{\"prefix\":\"test\",\"args\":[\" command 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);
197 ASSERT_EQ(true, asoct.shutdown());
198 }
199
200 class BlockingHook : public AdminSocketHook {
201 public:
202 Mutex _lock;
203 Cond _cond;
204
205 BlockingHook() : _lock("BlockingHook::_lock") {}
206
207 bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& result) override {
208 Mutex::Locker l(_lock);
209 _cond.Wait(_lock);
210 return true;
211 }
212 };
213
214 TEST(AdminSocketClient, Ping) {
215 string path = get_rand_socket_path();
216 std::unique_ptr<AdminSocket>
217 asokc(new AdminSocket(g_ceph_context));
218 AdminSocketClient client(path);
219 // no socket
220 {
221 bool ok;
222 std::string result = client.ping(&ok);
223 EXPECT_NE(std::string::npos, result.find("No such file or directory"));
224 ASSERT_FALSE(ok);
225 }
226 // file exists but does not allow connections (no process, wrong type...)
227 ASSERT_TRUE(::creat(path.c_str(), 0777));
228 {
229 bool ok;
230 std::string result = client.ping(&ok);
231 #if defined(__APPLE__) || defined(__FreeBSD__)
232 const char* errmsg = "Socket operation on non-socket";
233 #else
234 const char* errmsg = "Connection refused";
235 #endif
236 EXPECT_NE(std::string::npos, result.find(errmsg));
237 ASSERT_FALSE(ok);
238 }
239 // a daemon is connected to the socket
240 {
241 AdminSocketTest asoct(asokc.get());
242 ASSERT_TRUE(asoct.init(path));
243 bool ok;
244 std::string result = client.ping(&ok);
245 EXPECT_EQ("", result);
246 ASSERT_TRUE(ok);
247 ASSERT_TRUE(asoct.shutdown());
248 }
249 // hardcoded five seconds timeout prevents infinite blockage
250 {
251 AdminSocketTest asoct(asokc.get());
252 BlockingHook *blocking = new BlockingHook();
253 ASSERT_EQ(0, asoct.m_asokc->register_command("0", "0", blocking, ""));
254 ASSERT_TRUE(asoct.init(path));
255 bool ok;
256 std::string result = client.ping(&ok);
257 EXPECT_NE(std::string::npos, result.find("Resource temporarily unavailable"));
258 ASSERT_FALSE(ok);
259 {
260 Mutex::Locker l(blocking->_lock);
261 blocking->_cond.Signal();
262 }
263 ASSERT_TRUE(asoct.shutdown());
264 delete blocking;
265 }
266 }
267
268 TEST(AdminSocket, bind_and_listen) {
269 string path = get_rand_socket_path();
270 std::unique_ptr<AdminSocket>
271 asokc(new AdminSocket(g_ceph_context));
272
273 AdminSocketTest asoct(asokc.get());
274 // successfull bind
275 {
276 int fd = 0;
277 string message;
278 message = asoct.bind_and_listen(path, &fd);
279 ASSERT_NE(0, fd);
280 ASSERT_EQ("", message);
281 ASSERT_EQ(0, ::close(fd));
282 ASSERT_EQ(0, ::unlink(path.c_str()));
283 }
284 // silently discard an existing file
285 {
286 int fd = 0;
287 string message;
288 ASSERT_TRUE(::creat(path.c_str(), 0777));
289 message = asoct.bind_and_listen(path, &fd);
290 ASSERT_NE(0, fd);
291 ASSERT_EQ("", message);
292 ASSERT_EQ(0, ::close(fd));
293 ASSERT_EQ(0, ::unlink(path.c_str()));
294 }
295 // do not take over a live socket
296 {
297 ASSERT_TRUE(asoct.init(path));
298 int fd = 0;
299 string message;
300 message = asoct.bind_and_listen(path, &fd);
301 std::cout << "message: " << message << std::endl;
302 EXPECT_NE(std::string::npos, message.find("File exists"));
303 ASSERT_TRUE(asoct.shutdown());
304 }
305 }
306
307 /*
308 * Local Variables:
309 * compile-command: "cd .. ;
310 * make unittest_admin_socket &&
311 * valgrind \
312 * --max-stackframe=20000000 --tool=memcheck \
313 * ./unittest_admin_socket --debug-asok 20 # --gtest_filter=AdminSocket*.*
314 * "
315 * End:
316 */
317