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/version.h"
25 #include "common/dout.h"
26 #include "common/debug.h"
27 #include "common/ceph_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/ceph_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
57 ceph::mutex lock
= ceph::make_mutex("mon-msg-test::lock");
63 explicit MonClientHelper(CephContext
*cct_
)
72 dout(1) << __func__
<< dendl
;
75 msg
->add_dispatcher_tail(this);
79 int init_messenger() {
80 dout(1) << __func__
<< dendl
;
82 std::string public_msgr_type
= cct
->_conf
->ms_public_type
.empty() ? cct
->_conf
.get_val
<std::string
>("ms_type") : cct
->_conf
->ms_public_type
;
83 msg
= Messenger::create(cct
, public_msgr_type
, entity_name_t::CLIENT(-1),
84 "test-mon-msg", 0, 0);
85 ceph_assert(msg
!= NULL
);
86 msg
->set_default_policy(Messenger::Policy::lossy_client(0));
87 dout(0) << __func__
<< " starting messenger at "
88 << msg
->get_myaddrs() << dendl
;
94 dout(1) << __func__
<< dendl
;
95 ceph_assert(msg
!= NULL
);
96 int err
= monc
.build_initial_monmap();
98 derr
<< __func__
<< " error building monmap: "
99 << cpp_strerror(err
) << dendl
;
103 monc
.set_messenger(msg
);
104 msg
->add_dispatcher_head(&monc
);
106 monc
.set_want_keys(CEPH_ENTITY_TYPE_MON
);
109 derr
<< __func__
<< " monc init failed: "
110 << cpp_strerror(err
) << dendl
;
114 err
= monc
.authenticate();
116 derr
<< __func__
<< " monc auth failed: "
117 << cpp_strerror(err
) << dendl
;
120 monc
.wait_auth_rotating(30.0);
122 dout(0) << __func__
<< " finished" << dendl
;
126 derr
<< __func__
<< " failing monc" << dendl
;
132 void shutdown_messenger() {
133 dout(0) << __func__
<< dendl
;
138 void shutdown_monc() {
139 dout(0) << __func__
<< dendl
;
144 dout(0) << __func__
<< dendl
;
146 shutdown_messenger();
149 MonMap
*get_monmap() {
154 int err
= init_messenger();
167 shutdown_messenger();
172 virtual void handle_wanted(Message
*m
) { }
174 bool handle_message(Message
*m
) {
175 dout(1) << __func__
<< " " << *m
<< dendl
;
177 dout(10) << __func__
<< " not wanted" << dendl
;
186 bool ms_dispatch(Message
*m
) override
{
187 return handle_message(m
);
189 void ms_handle_connect(Connection
*con
) override
{ }
190 void ms_handle_remote_reset(Connection
*con
) override
{ }
191 bool ms_handle_reset(Connection
*con
) override
{ return false; }
192 bool ms_handle_refused(Connection
*con
) override
{ return false; }
194 bool is_wanted(Message
*m
) {
195 dout(20) << __func__
<< " " << *m
<< " type " << m
->get_type() << dendl
;
196 return (wanted
.find(m
->get_type()) != wanted
.end());
199 void add_wanted(int t
) {
200 dout(20) << __func__
<< " type " << t
<< dendl
;
204 void rm_wanted(int t
) {
205 dout(20) << __func__
<< " type " << t
<< dendl
;
209 void send_message(Message
*m
) {
210 dout(15) << __func__
<< " " << *m
<< dendl
;
211 monc
.send_mon_message(m
);
214 void wait() { msg
->wait(); }
217 class MonMsgTest
: public MonClientHelper
,
218 public ::testing::Test
222 Message
*reply_msg
= nullptr;
223 ceph::mutex lock
= ceph::make_mutex("lock");
224 ceph::condition_variable cond
;
227 MonClientHelper(g_ceph_context
) { }
230 void SetUp() override
{
236 ASSERT_EQ(init(), 0);
239 void TearDown() override
{
247 void handle_wanted(Message
*m
) override
{
248 std::lock_guard l
{lock
};
249 // caller will put() after they call us, so hold on to a ref
255 Message
*send_wait_reply(Message
*m
, int t
, double timeout
=30.0) {
256 std::unique_lock l
{lock
};
261 std::cv_status status
= std::cv_status::no_timeout
;
263 utime_t s
= ceph_clock_now();
264 status
= cond
.wait_for(l
, ceph::make_timespan(timeout
));
265 utime_t e
= ceph_clock_now();
266 dout(20) << __func__
<< " took " << (e
-s
) << " seconds" << dendl
;
272 if (status
== std::cv_status::timeout
) {
273 dout(20) << __func__
<< " error: " << cpp_strerror(ETIMEDOUT
) << dendl
;
274 return (Message
*)((long)-ETIMEDOUT
);
278 dout(20) << __func__
<< " reply_msg is nullptr" << dendl
;
280 dout(20) << __func__
<< " reply_msg " << *reply_msg
<< dendl
;
285 TEST_F(MonMsgTest
, MMonProbeTest
)
287 Message
*m
= new MMonProbe(get_monmap()->fsid
,
288 MMonProbe::OP_PROBE
, "b", false,
290 Message
*r
= send_wait_reply(m
, MSG_MON_PROBE
);
291 ASSERT_NE(IS_ERR(r
), 0);
292 ASSERT_EQ(PTR_ERR(r
), -ETIMEDOUT
);
295 TEST_F(MonMsgTest
, MRouteTest
)
297 Message
*payload
= new MGenericMessage(CEPH_MSG_SHUTDOWN
);
298 MRoute
*m
= new MRoute
;
300 Message
*r
= send_wait_reply(m
, CEPH_MSG_SHUTDOWN
);
302 ASSERT_NE(IS_ERR(r
), 0);
303 ASSERT_EQ(PTR_ERR(r
), -ETIMEDOUT
);
306 /* MMonScrub and MMonSync have other safeguards in place that prevent
307 * us from actually receiving a reply even if the message is handled
308 * by the monitor due to lack of cap checking.
310 TEST_F(MonMsgTest
, MMonJoin
)
312 Message
*m
= new MMonJoin(get_monmap()->fsid
, string("client"),
314 send_wait_reply(m
, MSG_MON_PAXOS
, 10.0);
316 int r
= monc
.get_monmap();
318 ASSERT_FALSE(monc
.monmap
.contains("client"));
321 int main(int argc
, char *argv
[])
323 vector
<const char*> args
;
324 argv_to_vec(argc
, (const char **)argv
, args
);
326 auto cct
= global_init(nullptr, args
,
327 CEPH_ENTITY_TYPE_CLIENT
, CODE_ENVIRONMENT_UTILITY
,
328 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
329 common_init_finish(g_ceph_context
);
330 g_ceph_context
->_conf
.apply_changes(nullptr);
331 ::testing::InitGoogleTest(&argc
, argv
);
333 return RUN_ALL_TESTS();