Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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