1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/rbd_mirror/test_mock_fixture.h"
5 #include "include/stringify.h"
6 #include "tools/rbd_mirror/MirrorStatusUpdater.h"
7 #include "tools/rbd_mirror/MirrorStatusWatcher.h"
8 #include "tools/rbd_mirror/Threads.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librbd/mock/MockImageCtx.h"
11 #include "test/rbd_mirror/mock/MockContextWQ.h"
12 #include "test/rbd_mirror/mock/MockSafeTimer.h"
20 struct MockTestImageCtx
: public MockImageCtx
{
21 MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
22 : librbd::MockImageCtx(image_ctx
) {
26 } // anonymous namespace
33 struct MirrorStatusWatcher
<librbd::MockTestImageCtx
> {
34 static MirrorStatusWatcher
* s_instance
;
35 static MirrorStatusWatcher
* create(librados::IoCtx
& io_ctx
,
36 MockContextWQ
* mock_context_wq
) {
37 ceph_assert(s_instance
!= nullptr);
41 MOCK_METHOD1(init
, void(Context
*));
42 MOCK_METHOD1(shut_down
, void(Context
*));
44 MirrorStatusWatcher() {
49 MirrorStatusWatcher
<librbd::MockTestImageCtx
>* MirrorStatusWatcher
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
52 struct Threads
<librbd::MockTestImageCtx
> {
54 ceph::mutex
&timer_lock
;
56 MockContextWQ
*work_queue
;
58 Threads(Threads
<librbd::ImageCtx
> *threads
)
59 : timer(new MockSafeTimer()),
60 timer_lock(threads
->timer_lock
),
61 work_queue(new MockContextWQ()) {
72 #include "tools/rbd_mirror/MirrorStatusUpdater.cc"
78 using ::testing::DoDefault
;
79 using ::testing::InSequence
;
80 using ::testing::Invoke
;
81 using ::testing::StrEq
;
82 using ::testing::Return
;
83 using ::testing::WithArg
;
85 class TestMockMirrorStatusUpdater
: public TestMockFixture
{
87 typedef MirrorStatusUpdater
<librbd::MockTestImageCtx
> MockMirrorStatusUpdater
;
88 typedef MirrorStatusWatcher
<librbd::MockTestImageCtx
> MockMirrorStatusWatcher
;
89 typedef Threads
<librbd::MockTestImageCtx
> MockThreads
;
91 typedef std::map
<std::string
, cls::rbd::MirrorImageSiteStatus
>
92 MirrorImageSiteStatuses
;
94 void SetUp() override
{
95 TestMockFixture::SetUp();
97 m_mock_local_io_ctx
= &get_mock_io_ctx(m_local_io_ctx
);
98 m_mock_threads
= new MockThreads(m_threads
);
101 void TearDown() override
{
102 delete m_mock_threads
;
103 TestMockFixture::TearDown();
106 void expect_timer_add_event(Context
** timer_event
) {
107 EXPECT_CALL(*m_mock_threads
->timer
, add_event_after(_
, _
))
108 .WillOnce(WithArg
<1>(Invoke([timer_event
](Context
*ctx
) {
114 void expect_timer_cancel_event() {
115 EXPECT_CALL(*m_mock_threads
->timer
, cancel_event(_
))
116 .WillOnce(Invoke([](Context
* ctx
) {
122 void expect_work_queue(bool async
) {
123 EXPECT_CALL(*m_mock_threads
->work_queue
, queue(_
, _
))
124 .WillOnce(Invoke([this, async
](Context
*ctx
, int r
) {
126 m_threads
->work_queue
->queue(ctx
, r
);
133 void expect_mirror_status_watcher_init(
134 MockMirrorStatusWatcher
& mock_mirror_status_watcher
, int r
) {
135 EXPECT_CALL(*mock_mirror_status_watcher
.s_instance
, init(_
))
136 .WillOnce(Invoke([this, r
](Context
* ctx
) {
137 m_threads
->work_queue
->queue(ctx
, r
);
141 void expect_mirror_status_watcher_shut_down(
142 MockMirrorStatusWatcher
& mock_mirror_status_watcher
, int r
) {
143 EXPECT_CALL(*mock_mirror_status_watcher
.s_instance
, shut_down(_
))
144 .WillOnce(Invoke([this, r
](Context
* ctx
) {
145 m_threads
->work_queue
->queue(ctx
, r
);
149 void expect_mirror_status_update(
150 const std::string
& global_image_id
,
151 const cls::rbd::MirrorImageSiteStatus
& mirror_image_status
, int r
) {
152 EXPECT_CALL(*m_mock_local_io_ctx
,
153 exec(RBD_MIRRORING
, _
, StrEq("rbd"),
154 StrEq("mirror_image_status_set"), _
, _
, _
, _
))
155 .WillOnce(WithArg
<4>(Invoke(
156 [r
, global_image_id
, mirror_image_status
](bufferlist
& in_bl
) {
157 auto bl_it
= in_bl
.cbegin();
158 std::string decode_global_image_id
;
159 decode(decode_global_image_id
, bl_it
);
160 EXPECT_EQ(global_image_id
, decode_global_image_id
);
162 cls::rbd::MirrorImageSiteStatus decode_mirror_image_status
;
163 decode(decode_mirror_image_status
, bl_it
);
164 EXPECT_EQ(mirror_image_status
, decode_mirror_image_status
);
169 void expect_mirror_status_update(
170 const MirrorImageSiteStatuses
& mirror_image_site_statuses
,
171 const std::string
& mirror_uuid
, int r
) {
172 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
))
173 .WillOnce(Invoke([this](auto&&... args
) {
174 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
175 m_mock_local_io_ctx
->aio_flush();
179 for (auto [global_image_id
, mirror_image_status
] :
180 mirror_image_site_statuses
) {
181 mirror_image_status
.mirror_uuid
= mirror_uuid
;
182 expect_mirror_status_update(global_image_id
, mirror_image_status
, r
);
189 void fire_timer_event(Context
** timer_event
,
190 Context
** update_task
) {
191 expect_timer_add_event(timer_event
);
193 // timer queues the update task
194 EXPECT_CALL(*m_mock_threads
->work_queue
, queue(_
, _
))
195 .WillOnce(WithArg
<0>(Invoke([update_task
](Context
* ctx
) mutable {
199 // fire the timer task
201 std::lock_guard timer_locker
{m_mock_threads
->timer_lock
};
202 ceph_assert(*timer_event
!= nullptr);
203 (*timer_event
)->complete(0);
207 void init_mirror_status_updater(
208 MockMirrorStatusUpdater
& mock_mirror_status_updater
,
209 MockMirrorStatusWatcher
& mock_mirror_status_watcher
,
210 Context
** timer_event
) {
211 expect_timer_add_event(timer_event
);
212 expect_mirror_status_watcher_init(mock_mirror_status_watcher
, 0);
213 expect_work_queue(true);
216 mock_mirror_status_updater
.init(&ctx
);
217 ASSERT_EQ(0, ctx
.wait());
220 void shut_down_mirror_status_updater(
221 MockMirrorStatusUpdater
& mock_mirror_status_updater
,
222 MockMirrorStatusWatcher
& mock_mirror_status_watcher
) {
223 expect_timer_cancel_event();
224 expect_mirror_status_watcher_shut_down(mock_mirror_status_watcher
, 0);
225 expect_work_queue(true);
228 mock_mirror_status_updater
.shut_down(&ctx
);
229 ASSERT_EQ(0, ctx
.wait());
232 librados::MockTestMemIoCtxImpl
* m_mock_local_io_ctx
= nullptr;
233 MockThreads
* m_mock_threads
= nullptr;
236 TEST_F(TestMockMirrorStatusUpdater
, InitShutDown
) {
237 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
239 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
240 new MockMirrorStatusWatcher();
242 Context
* timer_event
= nullptr;
243 init_mirror_status_updater(mock_mirror_status_updater
,
244 *mock_mirror_status_watcher
, &timer_event
);
246 shut_down_mirror_status_updater(mock_mirror_status_updater
,
247 *mock_mirror_status_watcher
);
250 TEST_F(TestMockMirrorStatusUpdater
, InitStatusWatcherError
) {
251 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
253 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
254 new MockMirrorStatusWatcher();
256 Context
* timer_event
= nullptr;
257 expect_timer_add_event(&timer_event
);
258 expect_mirror_status_watcher_init(*mock_mirror_status_watcher
, -EINVAL
);
259 expect_timer_cancel_event();
260 expect_work_queue(true);
263 mock_mirror_status_updater
.init(&ctx
);
264 ASSERT_EQ(-EINVAL
, ctx
.wait());
267 TEST_F(TestMockMirrorStatusUpdater
, ShutDownStatusWatcherError
) {
268 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
270 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
271 new MockMirrorStatusWatcher();
273 Context
* timer_event
= nullptr;
274 init_mirror_status_updater(mock_mirror_status_updater
,
275 *mock_mirror_status_watcher
, &timer_event
);
277 C_SaferCond on_shutdown
;
278 expect_timer_cancel_event();
279 expect_mirror_status_watcher_shut_down(*mock_mirror_status_watcher
, -EINVAL
);
280 expect_work_queue(true);
281 mock_mirror_status_updater
.shut_down(&on_shutdown
);
283 ASSERT_EQ(-EINVAL
, on_shutdown
.wait());
286 TEST_F(TestMockMirrorStatusUpdater
, SmallBatch
) {
287 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
289 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
290 new MockMirrorStatusWatcher();
294 Context
* timer_event
= nullptr;
295 init_mirror_status_updater(mock_mirror_status_updater
,
296 *mock_mirror_status_watcher
, &timer_event
);
298 MirrorImageSiteStatuses mirror_image_site_statuses
;
299 for (auto i
= 0; i
< 100; ++i
) {
300 auto pair
= mirror_image_site_statuses
.emplace(
301 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
302 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
307 Context
* update_task
= nullptr;
308 fire_timer_event(&timer_event
, &update_task
);
310 expect_mirror_status_update(mirror_image_site_statuses
, "", 0);
311 update_task
->complete(0);
313 shut_down_mirror_status_updater(mock_mirror_status_updater
,
314 *mock_mirror_status_watcher
);
317 TEST_F(TestMockMirrorStatusUpdater
, LargeBatch
) {
318 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
320 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
321 new MockMirrorStatusWatcher();
325 Context
* timer_event
= nullptr;
326 init_mirror_status_updater(mock_mirror_status_updater
,
327 *mock_mirror_status_watcher
, &timer_event
);
329 MirrorImageSiteStatuses mirror_image_site_statuses
;
330 for (auto i
= 0; i
< 200; ++i
) {
331 auto pair
= mirror_image_site_statuses
.emplace(
332 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
333 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
338 auto it_1
= mirror_image_site_statuses
.begin();
339 auto it_2
= mirror_image_site_statuses
.begin();
340 std::advance(it_2
, 100);
341 MirrorImageSiteStatuses mirror_image_site_statuses_1
{it_1
, it_2
};
344 std::advance(it_2
, 100);
345 MirrorImageSiteStatuses mirror_image_site_statuses_2
{it_1
, it_2
};
347 Context
* update_task
= nullptr;
348 fire_timer_event(&timer_event
, &update_task
);
350 expect_mirror_status_update(mirror_image_site_statuses_1
, "", 0);
351 expect_mirror_status_update(mirror_image_site_statuses_2
, "", 0);
352 update_task
->complete(0);
354 shut_down_mirror_status_updater(mock_mirror_status_updater
,
355 *mock_mirror_status_watcher
);
358 TEST_F(TestMockMirrorStatusUpdater
, OverwriteStatus
) {
359 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
361 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
362 new MockMirrorStatusWatcher();
366 Context
* timer_event
= nullptr;
367 init_mirror_status_updater(mock_mirror_status_updater
,
368 *mock_mirror_status_watcher
, &timer_event
);
370 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
371 mock_mirror_status_updater
.set_mirror_image_status(
372 "1", {"", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"},
375 Context
* update_task
= nullptr;
376 fire_timer_event(&timer_event
, &update_task
);
378 expect_mirror_status_update(
379 {{"1", cls::rbd::MirrorImageSiteStatus
{
380 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"}}},
382 update_task
->complete(0);
384 shut_down_mirror_status_updater(mock_mirror_status_updater
,
385 *mock_mirror_status_watcher
);
388 TEST_F(TestMockMirrorStatusUpdater
, OverwriteStatusInFlight
) {
389 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
391 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
392 new MockMirrorStatusWatcher();
396 Context
* timer_event
= nullptr;
397 init_mirror_status_updater(mock_mirror_status_updater
,
398 *mock_mirror_status_watcher
, &timer_event
);
400 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
402 Context
* update_task
= nullptr;
403 fire_timer_event(&timer_event
, &update_task
);
405 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
))
406 .WillOnce(Invoke([this, &mock_mirror_status_updater
](auto&&... args
) {
407 mock_mirror_status_updater
.set_mirror_image_status(
408 "1", {"", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
,
412 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
413 m_mock_local_io_ctx
->aio_flush();
416 expect_mirror_status_update("1", cls::rbd::MirrorImageSiteStatus
{}, 0);
417 expect_work_queue(false);
418 expect_mirror_status_update(
419 {{"1", cls::rbd::MirrorImageSiteStatus
{
420 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"}}},
423 update_task
->complete(0);
425 shut_down_mirror_status_updater(mock_mirror_status_updater
,
426 *mock_mirror_status_watcher
);
429 TEST_F(TestMockMirrorStatusUpdater
, ImmediateUpdate
) {
430 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
432 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
433 new MockMirrorStatusWatcher();
437 Context
* timer_event
= nullptr;
438 init_mirror_status_updater(mock_mirror_status_updater
,
439 *mock_mirror_status_watcher
, &timer_event
);
441 expect_work_queue(false);
442 expect_mirror_status_update({{"1", cls::rbd::MirrorImageSiteStatus
{}}},
444 mock_mirror_status_updater
.set_mirror_image_status("1", {}, true);
446 shut_down_mirror_status_updater(mock_mirror_status_updater
,
447 *mock_mirror_status_watcher
);
450 TEST_F(TestMockMirrorStatusUpdater
, RemoveIdleStatus
) {
451 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
453 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
454 new MockMirrorStatusWatcher();
458 Context
* timer_event
= nullptr;
459 init_mirror_status_updater(mock_mirror_status_updater
,
460 *mock_mirror_status_watcher
, &timer_event
);
462 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
465 expect_work_queue(true);
466 mock_mirror_status_updater
.remove_mirror_image_status("1", &ctx
);
467 ASSERT_EQ(0, ctx
.wait());
469 shut_down_mirror_status_updater(mock_mirror_status_updater
,
470 *mock_mirror_status_watcher
);
473 TEST_F(TestMockMirrorStatusUpdater
, RemoveInFlightStatus
) {
474 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
476 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
477 new MockMirrorStatusWatcher();
481 Context
* timer_event
= nullptr;
482 init_mirror_status_updater(mock_mirror_status_updater
,
483 *mock_mirror_status_watcher
, &timer_event
);
485 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
487 Context
* update_task
= nullptr;
488 fire_timer_event(&timer_event
, &update_task
);
490 C_SaferCond on_removed
;
491 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
))
493 [this, &mock_mirror_status_updater
, &on_removed
](auto&&... args
) {
494 mock_mirror_status_updater
.remove_mirror_image_status("1", &on_removed
);
496 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
497 m_mock_local_io_ctx
->aio_flush();
500 update_task
->complete(0);
501 ASSERT_EQ(0, on_removed
.wait());
503 shut_down_mirror_status_updater(mock_mirror_status_updater
,
504 *mock_mirror_status_watcher
);
507 TEST_F(TestMockMirrorStatusUpdater
, ShutDownWhileUpdating
) {
508 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
510 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
511 new MockMirrorStatusWatcher();
515 Context
* timer_event
= nullptr;
516 init_mirror_status_updater(mock_mirror_status_updater
,
517 *mock_mirror_status_watcher
, &timer_event
);
519 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
521 Context
* update_task
= nullptr;
522 fire_timer_event(&timer_event
, &update_task
);
524 C_SaferCond on_shutdown
;
525 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
))
527 [this, &mock_mirror_status_updater
, &on_shutdown
](auto&&... args
) {
528 mock_mirror_status_updater
.shut_down(&on_shutdown
);
529 m_threads
->work_queue
->drain();
531 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
532 m_mock_local_io_ctx
->aio_flush();
536 expect_timer_cancel_event();
537 expect_mirror_status_watcher_shut_down(*mock_mirror_status_watcher
, 0);
539 update_task
->complete(0);
540 ASSERT_EQ(0, on_shutdown
.wait());
543 TEST_F(TestMockMirrorStatusUpdater
, MirrorPeerSitePing
) {
544 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
547 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
548 new MockMirrorStatusWatcher();
552 Context
* timer_event
= nullptr;
553 init_mirror_status_updater(mock_mirror_status_updater
,
554 *mock_mirror_status_watcher
, &timer_event
);
556 MirrorImageSiteStatuses mirror_image_site_statuses
;
557 for (auto i
= 0; i
< 100; ++i
) {
558 auto pair
= mirror_image_site_statuses
.emplace(
559 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
560 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
565 Context
* update_task
= nullptr;
566 fire_timer_event(&timer_event
, &update_task
);
568 expect_mirror_status_update(mirror_image_site_statuses
, "mirror uuid", 0);
569 update_task
->complete(0);
571 shut_down_mirror_status_updater(mock_mirror_status_updater
,
572 *mock_mirror_status_watcher
);
575 } // namespace mirror