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) 2014 Red Hat
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.
21 #include "global/global_init.h"
22 #include "global/global_context.h"
23 #include "common/ceph_argparse.h"
24 #include "common/dout.h"
25 #include "common/debug.h"
26 #include "common/Cond.h"
27 #include "common/Mutex.h"
28 #include "common/Timer.h"
29 #include "common/errno.h"
30 #include "mon/MonClient.h"
31 #include "msg/Dispatcher.h"
32 #include "include/err.h"
33 #include <boost/scoped_ptr.hpp>
35 #include "gtest/gtest.h"
37 #include "common/config.h"
38 #include "include/assert.h"
40 #include "messages/MMonProbe.h"
41 #include "messages/MRoute.h"
42 #include "messages/MGenericMessage.h"
43 #include "messages/MMonJoin.h"
45 #define dout_context g_ceph_context
46 #define dout_subsys ceph_subsys_
48 #define dout_prefix *_dout << "test-mon-msg "
50 class MonClientHelper : public Dispatcher
63 explicit MonClientHelper(CephContext *cct_)
68 lock("mon-msg-test::lock")
73 dout(1) << __func__ << dendl;
76 msg->add_dispatcher_tail(this);
80 int init_messenger() {
81 dout(1) << __func__ << dendl;
83 std::string public_msgr_type = cct->_conf->ms_public_type.empty() ? cct->_conf->get_val<std::string>("ms_type") : cct->_conf->ms_public_type;
84 msg = Messenger::create(cct, public_msgr_type, entity_name_t::CLIENT(-1),
85 "test-mon-msg", 0, 0);
87 msg->set_default_policy(Messenger::Policy::lossy_client(0));
88 dout(0) << __func__ << " starting messenger at "
89 << msg->get_myaddr() << dendl;
95 dout(1) << __func__ << dendl;
97 int err = monc.build_initial_monmap();
99 derr << __func__ << " error building monmap: "
100 << cpp_strerror(err) << dendl;
104 monc.set_messenger(msg);
105 msg->add_dispatcher_head(&monc);
107 monc.set_want_keys(CEPH_ENTITY_TYPE_MON);
110 derr << __func__ << " monc init failed: "
111 << cpp_strerror(err) << dendl;
115 err = monc.authenticate();
117 derr << __func__ << " monc auth failed: "
118 << cpp_strerror(err) << dendl;
121 monc.wait_auth_rotating(30.0);
123 dout(0) << __func__ << " finished" << dendl;
127 derr << __func__ << " failing monc" << dendl;
133 void shutdown_messenger() {
134 dout(0) << __func__ << dendl;
139 void shutdown_monc() {
140 dout(0) << __func__ << dendl;
145 dout(0) << __func__ << dendl;
147 shutdown_messenger();
150 MonMap *get_monmap() {
155 int err = init_messenger();
168 shutdown_messenger();
173 virtual void handle_wanted(Message *m) { }
175 bool handle_message(Message *m) {
176 dout(1) << __func__ << " " << *m << dendl;
178 dout(10) << __func__ << " not wanted" << dendl;
187 bool ms_dispatch(Message *m) override {
188 return handle_message(m);
190 void ms_handle_connect(Connection *con) override { }
191 void ms_handle_remote_reset(Connection *con) override { }
192 bool ms_handle_reset(Connection *con) override { return false; }
193 bool ms_handle_refused(Connection *con) override { return false; }
195 bool is_wanted(Message *m) {
196 dout(20) << __func__ << " " << *m << " type " << m->get_type() << dendl;
197 return (wanted.find(m->get_type()) != wanted.end());
200 void add_wanted(int t) {
201 dout(20) << __func__ << " type " << t << dendl;
205 void rm_wanted(int t) {
206 dout(20) << __func__ << " type " << t << dendl;
210 void send_message(Message *m) {
211 dout(15) << __func__ << " " << *m << dendl;
212 monc.send_mon_message(m);
215 void wait() { msg->wait(); }
218 class MonMsgTest : public MonClientHelper,
219 public ::testing::Test
223 Message *reply_msg = nullptr;
228 MonClientHelper(g_ceph_context),
232 void SetUp() override {
238 ASSERT_EQ(init(), 0);
241 void TearDown() override {
249 void handle_wanted(Message *m) override {
251 // caller will put() after they call us, so hold on to a ref
258 Message *send_wait_reply(Message *m, int t, double timeout=30.0) {
266 utime_t cond_timeout;
267 cond_timeout.set_from_double(timeout);
268 utime_t s = ceph_clock_now();
269 err = cond.WaitInterval(lock, cond_timeout);
270 utime_t e = ceph_clock_now();
271 dout(20) << __func__ << " took " << (e-s) << " seconds" << dendl;
273 err = cond.Wait(lock);
278 dout(20) << __func__ << " error: " << cpp_strerror(err) << dendl;
279 return (Message*)((long)-err);
283 dout(20) << __func__ << " reply_msg is nullptr" << dendl;
285 dout(20) << __func__ << " reply_msg " << *reply_msg << dendl;
290 TEST_F(MonMsgTest, MMonProbeTest)
292 Message *m = new MMonProbe(get_monmap()->fsid,
293 MMonProbe::OP_PROBE, "b", false);
294 Message *r = send_wait_reply(m, MSG_MON_PROBE);
295 ASSERT_NE(IS_ERR(r), 0);
296 ASSERT_EQ(PTR_ERR(r), -ETIMEDOUT);
299 TEST_F(MonMsgTest, MRouteTest)
301 Message *payload = new MGenericMessage(CEPH_MSG_SHUTDOWN);
302 MRoute *m = new MRoute;
304 m->dest = msg->get_myinst();
305 Message *r = send_wait_reply(m, CEPH_MSG_SHUTDOWN);
307 ASSERT_NE(IS_ERR(r), 0);
308 ASSERT_EQ(PTR_ERR(r), -ETIMEDOUT);
311 /* MMonScrub and MMonSync have other safeguards in place that prevent
312 * us from actually receiving a reply even if the message is handled
313 * by the monitor due to lack of cap checking.
315 TEST_F(MonMsgTest, MMonJoin)
317 Message *m = new MMonJoin(get_monmap()->fsid, string("client"),
319 send_wait_reply(m, MSG_MON_PAXOS, 10.0);
321 int r = monc.get_monmap();
323 ASSERT_FALSE(monc.monmap.contains("client"));
326 int main(int argc, char *argv[])
328 vector<const char*> args;
329 argv_to_vec(argc, (const char **)argv, args);
331 auto cct = global_init(nullptr, args,
332 CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
334 common_init_finish(g_ceph_context);
335 g_ceph_context->_conf->apply_changes(NULL);
336 ::testing::InitGoogleTest(&argc, argv);
338 return RUN_ALL_TESTS();