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 expect_mirror_status_remove(const std::string
& global_image_id
, int r
) {
190 EXPECT_CALL(*m_mock_local_io_ctx
,
191 exec(RBD_MIRRORING
, _
, StrEq("rbd"),
192 StrEq("mirror_image_status_remove"), _
, _
, _
, _
))
193 .WillOnce(WithArg
<4>(Invoke(
194 [r
, global_image_id
](bufferlist
& in_bl
) {
195 auto bl_it
= in_bl
.cbegin();
196 std::string decode_global_image_id
;
197 decode(decode_global_image_id
, bl_it
);
198 EXPECT_EQ(global_image_id
, decode_global_image_id
);
204 void expect_mirror_status_removes(const std::set
<std::string
>& mirror_images
,
206 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
, _
))
207 .WillOnce(Invoke([this](auto&&... args
) {
208 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
209 m_mock_local_io_ctx
->aio_flush();
213 for (auto global_image_id
: mirror_images
) {
214 expect_mirror_status_remove(global_image_id
, r
);
221 void fire_timer_event(Context
** timer_event
,
222 Context
** update_task
) {
223 expect_timer_add_event(timer_event
);
225 // timer queues the update task
226 EXPECT_CALL(*m_mock_threads
->work_queue
, queue(_
, _
))
227 .WillOnce(WithArg
<0>(Invoke([update_task
](Context
* ctx
) mutable {
231 // fire the timer task
233 std::lock_guard timer_locker
{m_mock_threads
->timer_lock
};
234 ceph_assert(*timer_event
!= nullptr);
235 (*timer_event
)->complete(0);
239 void init_mirror_status_updater(
240 MockMirrorStatusUpdater
& mock_mirror_status_updater
,
241 MockMirrorStatusWatcher
& mock_mirror_status_watcher
,
242 Context
** timer_event
) {
243 expect_timer_add_event(timer_event
);
244 expect_mirror_status_watcher_init(mock_mirror_status_watcher
, 0);
245 expect_work_queue(true);
248 mock_mirror_status_updater
.init(&ctx
);
249 ASSERT_EQ(0, ctx
.wait());
252 void shut_down_mirror_status_updater(
253 MockMirrorStatusUpdater
& mock_mirror_status_updater
,
254 MockMirrorStatusWatcher
& mock_mirror_status_watcher
) {
255 expect_timer_cancel_event();
256 expect_mirror_status_watcher_shut_down(mock_mirror_status_watcher
, 0);
257 expect_work_queue(true);
260 mock_mirror_status_updater
.shut_down(&ctx
);
261 ASSERT_EQ(0, ctx
.wait());
264 librados::MockTestMemIoCtxImpl
* m_mock_local_io_ctx
= nullptr;
265 MockThreads
* m_mock_threads
= nullptr;
268 TEST_F(TestMockMirrorStatusUpdater
, InitShutDown
) {
269 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
271 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
272 new MockMirrorStatusWatcher();
274 Context
* timer_event
= nullptr;
275 init_mirror_status_updater(mock_mirror_status_updater
,
276 *mock_mirror_status_watcher
, &timer_event
);
278 shut_down_mirror_status_updater(mock_mirror_status_updater
,
279 *mock_mirror_status_watcher
);
282 TEST_F(TestMockMirrorStatusUpdater
, InitStatusWatcherError
) {
283 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
285 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
286 new MockMirrorStatusWatcher();
288 Context
* timer_event
= nullptr;
289 expect_timer_add_event(&timer_event
);
290 expect_mirror_status_watcher_init(*mock_mirror_status_watcher
, -EINVAL
);
291 expect_timer_cancel_event();
292 expect_work_queue(true);
295 mock_mirror_status_updater
.init(&ctx
);
296 ASSERT_EQ(-EINVAL
, ctx
.wait());
299 TEST_F(TestMockMirrorStatusUpdater
, ShutDownStatusWatcherError
) {
300 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
302 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
303 new MockMirrorStatusWatcher();
305 Context
* timer_event
= nullptr;
306 init_mirror_status_updater(mock_mirror_status_updater
,
307 *mock_mirror_status_watcher
, &timer_event
);
309 C_SaferCond on_shutdown
;
310 expect_timer_cancel_event();
311 expect_mirror_status_watcher_shut_down(*mock_mirror_status_watcher
, -EINVAL
);
312 expect_work_queue(true);
313 mock_mirror_status_updater
.shut_down(&on_shutdown
);
315 ASSERT_EQ(-EINVAL
, on_shutdown
.wait());
318 TEST_F(TestMockMirrorStatusUpdater
, SmallBatch
) {
319 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
321 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
322 new MockMirrorStatusWatcher();
326 Context
* timer_event
= nullptr;
327 init_mirror_status_updater(mock_mirror_status_updater
,
328 *mock_mirror_status_watcher
, &timer_event
);
330 MirrorImageSiteStatuses mirror_image_site_statuses
;
331 for (auto i
= 0; i
< 100; ++i
) {
332 auto pair
= mirror_image_site_statuses
.emplace(
333 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
334 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
339 Context
* update_task
= nullptr;
340 fire_timer_event(&timer_event
, &update_task
);
342 expect_mirror_status_update(mirror_image_site_statuses
, "", 0);
343 update_task
->complete(0);
345 shut_down_mirror_status_updater(mock_mirror_status_updater
,
346 *mock_mirror_status_watcher
);
349 TEST_F(TestMockMirrorStatusUpdater
, LargeBatch
) {
350 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
352 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
353 new MockMirrorStatusWatcher();
357 Context
* timer_event
= nullptr;
358 init_mirror_status_updater(mock_mirror_status_updater
,
359 *mock_mirror_status_watcher
, &timer_event
);
361 MirrorImageSiteStatuses mirror_image_site_statuses
;
362 for (auto i
= 0; i
< 200; ++i
) {
363 auto pair
= mirror_image_site_statuses
.emplace(
364 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
365 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
370 auto it_1
= mirror_image_site_statuses
.begin();
371 auto it_2
= mirror_image_site_statuses
.begin();
372 std::advance(it_2
, 100);
373 MirrorImageSiteStatuses mirror_image_site_statuses_1
{it_1
, it_2
};
376 std::advance(it_2
, 100);
377 MirrorImageSiteStatuses mirror_image_site_statuses_2
{it_1
, it_2
};
379 Context
* update_task
= nullptr;
380 fire_timer_event(&timer_event
, &update_task
);
382 expect_mirror_status_update(mirror_image_site_statuses_1
, "", 0);
383 expect_mirror_status_update(mirror_image_site_statuses_2
, "", 0);
384 update_task
->complete(0);
386 shut_down_mirror_status_updater(mock_mirror_status_updater
,
387 *mock_mirror_status_watcher
);
390 TEST_F(TestMockMirrorStatusUpdater
, OverwriteStatus
) {
391 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
393 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
394 new MockMirrorStatusWatcher();
398 Context
* timer_event
= nullptr;
399 init_mirror_status_updater(mock_mirror_status_updater
,
400 *mock_mirror_status_watcher
, &timer_event
);
402 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
403 mock_mirror_status_updater
.set_mirror_image_status(
404 "1", {"", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"},
407 Context
* update_task
= nullptr;
408 fire_timer_event(&timer_event
, &update_task
);
410 expect_mirror_status_update(
411 {{"1", cls::rbd::MirrorImageSiteStatus
{
412 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"}}},
414 update_task
->complete(0);
416 shut_down_mirror_status_updater(mock_mirror_status_updater
,
417 *mock_mirror_status_watcher
);
420 TEST_F(TestMockMirrorStatusUpdater
, RemoveStatus
) {
421 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
423 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
424 new MockMirrorStatusWatcher();
428 Context
* timer_event
= nullptr;
429 init_mirror_status_updater(mock_mirror_status_updater
,
430 *mock_mirror_status_watcher
, &timer_event
);
433 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
434 expect_work_queue(false);
435 mock_mirror_status_updater
.remove_mirror_image_status("1", false, &ctx
);
436 ASSERT_EQ(0, ctx
.wait());
438 Context
* update_task
= nullptr;
439 fire_timer_event(&timer_event
, &update_task
);
441 C_SaferCond remove_flush_ctx
;
442 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
, _
))
443 .WillOnce(Invoke([this, &remove_flush_ctx
](auto&&... args
) {
444 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
445 m_mock_local_io_ctx
->aio_flush();
446 remove_flush_ctx
.complete(r
);
449 expect_mirror_status_remove("1", 0);
450 update_task
->complete(0);
451 ASSERT_EQ(0, remove_flush_ctx
.wait());
453 shut_down_mirror_status_updater(mock_mirror_status_updater
,
454 *mock_mirror_status_watcher
);
457 TEST_F(TestMockMirrorStatusUpdater
, OverwriteRemoveStatus
) {
458 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
460 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
461 new MockMirrorStatusWatcher();
465 Context
* timer_event
= nullptr;
466 init_mirror_status_updater(mock_mirror_status_updater
,
467 *mock_mirror_status_watcher
, &timer_event
);
470 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
471 expect_work_queue(false);
472 mock_mirror_status_updater
.remove_mirror_image_status("1", false, &ctx
);
473 ASSERT_EQ(0, ctx
.wait());
474 mock_mirror_status_updater
.set_mirror_image_status(
475 "1", {"", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"},
479 Context
* update_task
= nullptr;
480 fire_timer_event(&timer_event
, &update_task
);
482 expect_mirror_status_update(
483 {{"1", cls::rbd::MirrorImageSiteStatus
{
484 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"}}},
486 update_task
->complete(0);
488 shut_down_mirror_status_updater(mock_mirror_status_updater
,
489 *mock_mirror_status_watcher
);
492 TEST_F(TestMockMirrorStatusUpdater
, OverwriteStatusInFlight
) {
493 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
495 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
496 new MockMirrorStatusWatcher();
500 Context
* timer_event
= nullptr;
501 init_mirror_status_updater(mock_mirror_status_updater
,
502 *mock_mirror_status_watcher
, &timer_event
);
504 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
506 Context
* update_task
= nullptr;
507 fire_timer_event(&timer_event
, &update_task
);
509 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
, _
))
510 .WillOnce(Invoke([this, &mock_mirror_status_updater
](auto&&... args
) {
511 mock_mirror_status_updater
.set_mirror_image_status(
512 "1", {"", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
,
516 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
517 m_mock_local_io_ctx
->aio_flush();
520 expect_mirror_status_update("1", cls::rbd::MirrorImageSiteStatus
{}, 0);
521 expect_work_queue(false);
522 expect_mirror_status_update(
523 {{"1", cls::rbd::MirrorImageSiteStatus
{
524 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "description"}}},
527 update_task
->complete(0);
529 shut_down_mirror_status_updater(mock_mirror_status_updater
,
530 *mock_mirror_status_watcher
);
533 TEST_F(TestMockMirrorStatusUpdater
, ImmediateUpdate
) {
534 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
536 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
537 new MockMirrorStatusWatcher();
541 Context
* timer_event
= nullptr;
542 init_mirror_status_updater(mock_mirror_status_updater
,
543 *mock_mirror_status_watcher
, &timer_event
);
545 expect_work_queue(false);
546 expect_mirror_status_update({{"1", cls::rbd::MirrorImageSiteStatus
{}}},
548 mock_mirror_status_updater
.set_mirror_image_status("1", {}, true);
550 shut_down_mirror_status_updater(mock_mirror_status_updater
,
551 *mock_mirror_status_watcher
);
554 TEST_F(TestMockMirrorStatusUpdater
, RemoveImmediateUpdate
) {
555 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
557 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
558 new MockMirrorStatusWatcher();
562 Context
* timer_event
= nullptr;
563 init_mirror_status_updater(mock_mirror_status_updater
,
564 *mock_mirror_status_watcher
, &timer_event
);
566 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
569 expect_work_queue(false);
570 expect_mirror_status_removes({"1"}, 0);
571 expect_work_queue(false);
572 mock_mirror_status_updater
.remove_mirror_image_status("1", true, &ctx
);
573 ASSERT_EQ(0, ctx
.wait());
575 shut_down_mirror_status_updater(mock_mirror_status_updater
,
576 *mock_mirror_status_watcher
);
579 TEST_F(TestMockMirrorStatusUpdater
, RemoveRefreshIdleStatus
) {
580 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
582 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
583 new MockMirrorStatusWatcher();
587 Context
* timer_event
= nullptr;
588 init_mirror_status_updater(mock_mirror_status_updater
,
589 *mock_mirror_status_watcher
, &timer_event
);
591 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
594 expect_work_queue(true);
595 mock_mirror_status_updater
.remove_refresh_mirror_image_status("1", &ctx
);
596 ASSERT_EQ(0, ctx
.wait());
598 shut_down_mirror_status_updater(mock_mirror_status_updater
,
599 *mock_mirror_status_watcher
);
602 TEST_F(TestMockMirrorStatusUpdater
, RemoveRefreshInFlightStatus
) {
603 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
605 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
606 new MockMirrorStatusWatcher();
610 Context
* timer_event
= nullptr;
611 init_mirror_status_updater(mock_mirror_status_updater
,
612 *mock_mirror_status_watcher
, &timer_event
);
614 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
616 Context
* update_task
= nullptr;
617 fire_timer_event(&timer_event
, &update_task
);
619 C_SaferCond on_removed
;
620 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
, _
))
622 [this, &mock_mirror_status_updater
, &on_removed
](auto&&... args
) {
623 mock_mirror_status_updater
.remove_refresh_mirror_image_status(
626 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
627 m_mock_local_io_ctx
->aio_flush();
630 update_task
->complete(0);
631 ASSERT_EQ(0, on_removed
.wait());
633 shut_down_mirror_status_updater(mock_mirror_status_updater
,
634 *mock_mirror_status_watcher
);
637 TEST_F(TestMockMirrorStatusUpdater
, ShutDownWhileUpdating
) {
638 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
640 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
641 new MockMirrorStatusWatcher();
645 Context
* timer_event
= nullptr;
646 init_mirror_status_updater(mock_mirror_status_updater
,
647 *mock_mirror_status_watcher
, &timer_event
);
649 mock_mirror_status_updater
.set_mirror_image_status("1", {}, false);
651 Context
* update_task
= nullptr;
652 fire_timer_event(&timer_event
, &update_task
);
654 C_SaferCond on_shutdown
;
655 EXPECT_CALL(*m_mock_local_io_ctx
, aio_operate(_
, _
, _
, _
, _
, _
))
657 [this, &mock_mirror_status_updater
, &on_shutdown
](auto&&... args
) {
658 mock_mirror_status_updater
.shut_down(&on_shutdown
);
659 m_threads
->work_queue
->drain();
661 int r
= m_mock_local_io_ctx
->do_aio_operate(decltype(args
)(args
)...);
662 m_mock_local_io_ctx
->aio_flush();
666 expect_timer_cancel_event();
667 expect_mirror_status_watcher_shut_down(*mock_mirror_status_watcher
, 0);
669 update_task
->complete(0);
670 ASSERT_EQ(0, on_shutdown
.wait());
673 TEST_F(TestMockMirrorStatusUpdater
, MirrorPeerSitePing
) {
674 MockMirrorStatusUpdater
mock_mirror_status_updater(m_local_io_ctx
,
677 MockMirrorStatusWatcher
* mock_mirror_status_watcher
=
678 new MockMirrorStatusWatcher();
682 Context
* timer_event
= nullptr;
683 init_mirror_status_updater(mock_mirror_status_updater
,
684 *mock_mirror_status_watcher
, &timer_event
);
686 MirrorImageSiteStatuses mirror_image_site_statuses
;
687 for (auto i
= 0; i
< 100; ++i
) {
688 auto pair
= mirror_image_site_statuses
.emplace(
689 stringify(i
), cls::rbd::MirrorImageSiteStatus
{});
690 mock_mirror_status_updater
.set_mirror_image_status(pair
.first
->first
,
695 Context
* update_task
= nullptr;
696 fire_timer_event(&timer_event
, &update_task
);
698 expect_mirror_status_update(mirror_image_site_statuses
, "mirror uuid", 0);
699 update_task
->complete(0);
701 shut_down_mirror_status_updater(mock_mirror_status_updater
,
702 *mock_mirror_status_watcher
);
705 } // namespace mirror