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/async/context_pool.h"
24 #include "common/ceph_argparse.h"
25 #include "common/version.h"
26 #include "common/dout.h"
27 #include "common/debug.h"
28 #include "common/ceph_mutex.h"
29 #include "common/Timer.h"
30 #include "common/errno.h"
31 #include "mon/MonClient.h"
32 #include "msg/Dispatcher.h"
33 #include "include/err.h"
34 #include <boost/scoped_ptr.hpp>
36 #include "gtest/gtest.h"
38 #include "common/config.h"
39 #include "include/ceph_assert.h"
41 #include "messages/MMonProbe.h"
42 #include "messages/MRoute.h"
43 #include "messages/MGenericMessage.h"
44 #include "messages/MMonJoin.h"
46 #define dout_context g_ceph_context
47 #define dout_subsys ceph_subsys_
49 #define dout_prefix *_dout << "test-mon-msg "
51 class MonClientHelper
: public Dispatcher
55 ceph::async::io_context_pool poolctx
;
59 ceph::mutex lock
= ceph::make_mutex("mon-msg-test::lock");
65 explicit MonClientHelper(CephContext
*cct_
)
75 dout(1) << __func__
<< dendl
;
78 msg
->add_dispatcher_tail(this);
82 int init_messenger() {
83 dout(1) << __func__
<< dendl
;
85 std::string public_msgr_type
= cct
->_conf
->ms_public_type
.empty() ? cct
->_conf
.get_val
<std::string
>("ms_type") : cct
->_conf
->ms_public_type
;
86 msg
= Messenger::create(cct
, public_msgr_type
, entity_name_t::CLIENT(-1),
88 ceph_assert(msg
!= NULL
);
89 msg
->set_default_policy(Messenger::Policy::lossy_client(0));
90 dout(0) << __func__
<< " starting messenger at "
91 << msg
->get_myaddrs() << dendl
;
97 dout(1) << __func__
<< dendl
;
98 ceph_assert(msg
!= NULL
);
99 int err
= monc
.build_initial_monmap();
101 derr
<< __func__
<< " error building monmap: "
102 << cpp_strerror(err
) << dendl
;
106 monc
.set_messenger(msg
);
107 msg
->add_dispatcher_head(&monc
);
109 monc
.set_want_keys(CEPH_ENTITY_TYPE_MON
);
112 derr
<< __func__
<< " monc init failed: "
113 << cpp_strerror(err
) << dendl
;
117 err
= monc
.authenticate();
119 derr
<< __func__
<< " monc auth failed: "
120 << cpp_strerror(err
) << dendl
;
123 monc
.wait_auth_rotating(30.0);
125 dout(0) << __func__
<< " finished" << dendl
;
129 derr
<< __func__
<< " failing monc" << dendl
;
135 void shutdown_messenger() {
136 dout(0) << __func__
<< dendl
;
141 void shutdown_monc() {
142 dout(0) << __func__
<< dendl
;
147 dout(0) << __func__
<< dendl
;
149 shutdown_messenger();
152 MonMap
*get_monmap() {
157 int err
= init_messenger();
170 shutdown_messenger();
175 virtual void handle_wanted(Message
*m
) { }
177 bool handle_message(Message
*m
) {
178 dout(1) << __func__
<< " " << *m
<< dendl
;
180 dout(10) << __func__
<< " not wanted" << dendl
;
189 bool ms_dispatch(Message
*m
) override
{
190 return handle_message(m
);
192 void ms_handle_connect(Connection
*con
) override
{ }
193 void ms_handle_remote_reset(Connection
*con
) override
{ }
194 bool ms_handle_reset(Connection
*con
) override
{ return false; }
195 bool ms_handle_refused(Connection
*con
) override
{ return false; }
197 bool is_wanted(Message
*m
) {
198 dout(20) << __func__
<< " " << *m
<< " type " << m
->get_type() << dendl
;
199 return (wanted
.find(m
->get_type()) != wanted
.end());
202 void add_wanted(int t
) {
203 dout(20) << __func__
<< " type " << t
<< dendl
;
207 void rm_wanted(int t
) {
208 dout(20) << __func__
<< " type " << t
<< dendl
;
212 void send_message(Message
*m
) {
213 dout(15) << __func__
<< " " << *m
<< dendl
;
214 monc
.send_mon_message(m
);
217 void wait() { msg
->wait(); }
220 class MonMsgTest
: public MonClientHelper
,
221 public ::testing::Test
225 Message
*reply_msg
= nullptr;
226 ceph::mutex lock
= ceph::make_mutex("lock");
227 ceph::condition_variable cond
;
230 MonClientHelper(g_ceph_context
) { }
233 void SetUp() override
{
239 ASSERT_EQ(init(), 0);
242 void TearDown() override
{
250 void handle_wanted(Message
*m
) override
{
251 std::lock_guard l
{lock
};
252 // 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) {
259 std::unique_lock l
{lock
};
264 std::cv_status status
= std::cv_status::no_timeout
;
266 utime_t s
= ceph_clock_now();
267 status
= cond
.wait_for(l
, ceph::make_timespan(timeout
));
268 utime_t e
= ceph_clock_now();
269 dout(20) << __func__
<< " took " << (e
-s
) << " seconds" << dendl
;
275 if (status
== std::cv_status::timeout
) {
276 dout(20) << __func__
<< " error: " << cpp_strerror(ETIMEDOUT
) << dendl
;
277 return (Message
*)((long)-ETIMEDOUT
);
281 dout(20) << __func__
<< " reply_msg is nullptr" << dendl
;
283 dout(20) << __func__
<< " reply_msg " << *reply_msg
<< dendl
;
288 TEST_F(MonMsgTest
, MMonProbeTest
)
290 Message
*m
= new MMonProbe(get_monmap()->fsid
,
291 MMonProbe::OP_PROBE
, "b", false,
293 Message
*r
= send_wait_reply(m
, MSG_MON_PROBE
);
294 ASSERT_NE(IS_ERR(r
), 0);
295 ASSERT_EQ(PTR_ERR(r
), -ETIMEDOUT
);
298 TEST_F(MonMsgTest
, MRouteTest
)
300 Message
*payload
= new MGenericMessage(CEPH_MSG_SHUTDOWN
);
301 MRoute
*m
= new MRoute
;
303 Message
*r
= send_wait_reply(m
, CEPH_MSG_SHUTDOWN
);
305 ASSERT_NE(IS_ERR(r
), 0);
306 ASSERT_EQ(PTR_ERR(r
), -ETIMEDOUT
);
309 /* MMonScrub and MMonSync have other safeguards in place that prevent
310 * us from actually receiving a reply even if the message is handled
311 * by the monitor due to lack of cap checking.
313 TEST_F(MonMsgTest
, MMonJoin
)
315 Message
*m
= new MMonJoin(get_monmap()->fsid
, string("client"),
317 send_wait_reply(m
, MSG_MON_PAXOS
, 10.0);
319 int r
= monc
.get_monmap();
321 ASSERT_FALSE(monc
.monmap
.contains("client"));
324 int main(int argc
, char *argv
[])
326 vector
<const char*> args
;
327 argv_to_vec(argc
, (const char **)argv
, args
);
329 auto cct
= global_init(nullptr, args
,
330 CEPH_ENTITY_TYPE_CLIENT
, CODE_ENVIRONMENT_UTILITY
,
331 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
332 common_init_finish(g_ceph_context
);
333 g_ceph_context
->_conf
.apply_changes(nullptr);
334 ::testing::InitGoogleTest(&argc
, argv
);
336 return RUN_ALL_TESTS();