]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/test_mock_MirrorStatusUpdater.cc
4db576eb4343b744740ec9c805c42900c87ef9ca
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_MirrorStatusUpdater.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
13 #include <map>
14 #include <string>
15 #include <utility>
16
17 namespace librbd {
18 namespace {
19
20 struct MockTestImageCtx : public MockImageCtx {
21 MockTestImageCtx(librbd::ImageCtx &image_ctx)
22 : librbd::MockImageCtx(image_ctx) {
23 }
24 };
25
26 } // anonymous namespace
27 } // namespace librbd
28
29 namespace rbd {
30 namespace mirror {
31
32 template <>
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);
38 return s_instance;
39 }
40
41 MOCK_METHOD1(init, void(Context*));
42 MOCK_METHOD1(shut_down, void(Context*));
43
44 MirrorStatusWatcher() {
45 s_instance = this;
46 }
47 };
48
49 MirrorStatusWatcher<librbd::MockTestImageCtx>* MirrorStatusWatcher<librbd::MockTestImageCtx>::s_instance = nullptr;
50
51 template <>
52 struct Threads<librbd::MockTestImageCtx> {
53 MockSafeTimer *timer;
54 ceph::mutex &timer_lock;
55
56 MockContextWQ *work_queue;
57
58 Threads(Threads<librbd::ImageCtx> *threads)
59 : timer(new MockSafeTimer()),
60 timer_lock(threads->timer_lock),
61 work_queue(new MockContextWQ()) {
62 }
63 ~Threads() {
64 delete timer;
65 delete work_queue;
66 }
67 };
68
69 } // namespace mirror
70 } // namespace rbd
71
72 #include "tools/rbd_mirror/MirrorStatusUpdater.cc"
73
74 namespace rbd {
75 namespace mirror {
76
77 using ::testing::_;
78 using ::testing::DoDefault;
79 using ::testing::InSequence;
80 using ::testing::Invoke;
81 using ::testing::StrEq;
82 using ::testing::Return;
83 using ::testing::WithArg;
84
85 class TestMockMirrorStatusUpdater : public TestMockFixture {
86 public:
87 typedef MirrorStatusUpdater<librbd::MockTestImageCtx> MockMirrorStatusUpdater;
88 typedef MirrorStatusWatcher<librbd::MockTestImageCtx> MockMirrorStatusWatcher;
89 typedef Threads<librbd::MockTestImageCtx> MockThreads;
90
91 typedef std::map<std::string, cls::rbd::MirrorImageSiteStatus>
92 MirrorImageSiteStatuses;
93
94 void SetUp() override {
95 TestMockFixture::SetUp();
96
97 m_mock_local_io_ctx = &get_mock_io_ctx(m_local_io_ctx);
98 m_mock_threads = new MockThreads(m_threads);
99 }
100
101 void TearDown() override {
102 delete m_mock_threads;
103 TestMockFixture::TearDown();
104 }
105
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) {
109 *timer_event = ctx;
110 return ctx;
111 })));
112 }
113
114 void expect_timer_cancel_event() {
115 EXPECT_CALL(*m_mock_threads->timer, cancel_event(_))
116 .WillOnce(Invoke([](Context* ctx) {
117 delete ctx;
118 return false;
119 }));
120 }
121
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) {
125 if (async) {
126 m_threads->work_queue->queue(ctx, r);
127 } else {
128 ctx->complete(r);
129 }
130 }));
131 }
132
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);
138 }));
139 }
140
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);
146 }));
147 }
148
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);
161
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);
165 return r;
166 })));
167 }
168
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();
176 return r;
177 }));
178
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);
183 if (r < 0) {
184 break;
185 }
186 }
187 }
188
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);
199
200 return r;
201 })));
202 }
203
204 void expect_mirror_status_removes(const std::set<std::string>& mirror_images,
205 int r) {
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();
210 return r;
211 }));
212
213 for (auto global_image_id : mirror_images) {
214 expect_mirror_status_remove(global_image_id, r);
215 if (r < 0) {
216 break;
217 }
218 }
219 }
220
221 void fire_timer_event(Context** timer_event,
222 Context** update_task) {
223 expect_timer_add_event(timer_event);
224
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 {
228 *update_task = ctx;
229 })));
230
231 // fire the timer task
232 {
233 std::lock_guard timer_locker{m_mock_threads->timer_lock};
234 ceph_assert(*timer_event != nullptr);
235 (*timer_event)->complete(0);
236 }
237 }
238
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);
246
247 C_SaferCond ctx;
248 mock_mirror_status_updater.init(&ctx);
249 ASSERT_EQ(0, ctx.wait());
250 }
251
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);
258
259 C_SaferCond ctx;
260 mock_mirror_status_updater.shut_down(&ctx);
261 ASSERT_EQ(0, ctx.wait());
262 }
263
264 librados::MockTestMemIoCtxImpl* m_mock_local_io_ctx = nullptr;
265 MockThreads* m_mock_threads = nullptr;
266 };
267
268 TEST_F(TestMockMirrorStatusUpdater, InitShutDown) {
269 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
270 m_mock_threads, "");
271 MockMirrorStatusWatcher* mock_mirror_status_watcher =
272 new MockMirrorStatusWatcher();
273
274 Context* timer_event = nullptr;
275 init_mirror_status_updater(mock_mirror_status_updater,
276 *mock_mirror_status_watcher, &timer_event);
277
278 shut_down_mirror_status_updater(mock_mirror_status_updater,
279 *mock_mirror_status_watcher);
280 }
281
282 TEST_F(TestMockMirrorStatusUpdater, InitStatusWatcherError) {
283 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
284 m_mock_threads, "");
285 MockMirrorStatusWatcher* mock_mirror_status_watcher =
286 new MockMirrorStatusWatcher();
287
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);
293
294 C_SaferCond ctx;
295 mock_mirror_status_updater.init(&ctx);
296 ASSERT_EQ(-EINVAL, ctx.wait());
297 }
298
299 TEST_F(TestMockMirrorStatusUpdater, ShutDownStatusWatcherError) {
300 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
301 m_mock_threads, "");
302 MockMirrorStatusWatcher* mock_mirror_status_watcher =
303 new MockMirrorStatusWatcher();
304
305 Context* timer_event = nullptr;
306 init_mirror_status_updater(mock_mirror_status_updater,
307 *mock_mirror_status_watcher, &timer_event);
308
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);
314
315 ASSERT_EQ(-EINVAL, on_shutdown.wait());
316 }
317
318 TEST_F(TestMockMirrorStatusUpdater, SmallBatch) {
319 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
320 m_mock_threads, "");
321 MockMirrorStatusWatcher* mock_mirror_status_watcher =
322 new MockMirrorStatusWatcher();
323
324 InSequence seq;
325
326 Context* timer_event = nullptr;
327 init_mirror_status_updater(mock_mirror_status_updater,
328 *mock_mirror_status_watcher, &timer_event);
329
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,
335 pair.first->second,
336 false);
337 }
338
339 Context* update_task = nullptr;
340 fire_timer_event(&timer_event, &update_task);
341
342 expect_mirror_status_update(mirror_image_site_statuses, "", 0);
343 update_task->complete(0);
344
345 shut_down_mirror_status_updater(mock_mirror_status_updater,
346 *mock_mirror_status_watcher);
347 }
348
349 TEST_F(TestMockMirrorStatusUpdater, LargeBatch) {
350 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
351 m_mock_threads, "");
352 MockMirrorStatusWatcher* mock_mirror_status_watcher =
353 new MockMirrorStatusWatcher();
354
355 InSequence seq;
356
357 Context* timer_event = nullptr;
358 init_mirror_status_updater(mock_mirror_status_updater,
359 *mock_mirror_status_watcher, &timer_event);
360
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,
366 pair.first->second,
367 false);
368 }
369
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};
374
375 it_1 = it_2;
376 std::advance(it_2, 100);
377 MirrorImageSiteStatuses mirror_image_site_statuses_2{it_1, it_2};
378
379 Context* update_task = nullptr;
380 fire_timer_event(&timer_event, &update_task);
381
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);
385
386 shut_down_mirror_status_updater(mock_mirror_status_updater,
387 *mock_mirror_status_watcher);
388 }
389
390 TEST_F(TestMockMirrorStatusUpdater, OverwriteStatus) {
391 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
392 m_mock_threads, "");
393 MockMirrorStatusWatcher* mock_mirror_status_watcher =
394 new MockMirrorStatusWatcher();
395
396 InSequence seq;
397
398 Context* timer_event = nullptr;
399 init_mirror_status_updater(mock_mirror_status_updater,
400 *mock_mirror_status_watcher, &timer_event);
401
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"},
405 false);
406
407 Context* update_task = nullptr;
408 fire_timer_event(&timer_event, &update_task);
409
410 expect_mirror_status_update(
411 {{"1", cls::rbd::MirrorImageSiteStatus{
412 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING, "description"}}},
413 "", 0);
414 update_task->complete(0);
415
416 shut_down_mirror_status_updater(mock_mirror_status_updater,
417 *mock_mirror_status_watcher);
418 }
419
420 TEST_F(TestMockMirrorStatusUpdater, RemoveStatus) {
421 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
422 m_mock_threads, "");
423 MockMirrorStatusWatcher* mock_mirror_status_watcher =
424 new MockMirrorStatusWatcher();
425
426 InSequence seq;
427
428 Context* timer_event = nullptr;
429 init_mirror_status_updater(mock_mirror_status_updater,
430 *mock_mirror_status_watcher, &timer_event);
431
432 C_SaferCond ctx;
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());
437
438 Context* update_task = nullptr;
439 fire_timer_event(&timer_event, &update_task);
440
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);
447 return r;
448 }));
449 expect_mirror_status_remove("1", 0);
450 update_task->complete(0);
451 ASSERT_EQ(0, remove_flush_ctx.wait());
452
453 shut_down_mirror_status_updater(mock_mirror_status_updater,
454 *mock_mirror_status_watcher);
455 }
456
457 TEST_F(TestMockMirrorStatusUpdater, OverwriteRemoveStatus) {
458 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
459 m_mock_threads, "");
460 MockMirrorStatusWatcher* mock_mirror_status_watcher =
461 new MockMirrorStatusWatcher();
462
463 InSequence seq;
464
465 Context* timer_event = nullptr;
466 init_mirror_status_updater(mock_mirror_status_updater,
467 *mock_mirror_status_watcher, &timer_event);
468
469 C_SaferCond ctx;
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"},
476 false);
477
478
479 Context* update_task = nullptr;
480 fire_timer_event(&timer_event, &update_task);
481
482 expect_mirror_status_update(
483 {{"1", cls::rbd::MirrorImageSiteStatus{
484 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING, "description"}}},
485 "", 0);
486 update_task->complete(0);
487
488 shut_down_mirror_status_updater(mock_mirror_status_updater,
489 *mock_mirror_status_watcher);
490 }
491
492 TEST_F(TestMockMirrorStatusUpdater, OverwriteStatusInFlight) {
493 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
494 m_mock_threads, "");
495 MockMirrorStatusWatcher* mock_mirror_status_watcher =
496 new MockMirrorStatusWatcher();
497
498 InSequence seq;
499
500 Context* timer_event = nullptr;
501 init_mirror_status_updater(mock_mirror_status_updater,
502 *mock_mirror_status_watcher, &timer_event);
503
504 mock_mirror_status_updater.set_mirror_image_status("1", {}, false);
505
506 Context* update_task = nullptr;
507 fire_timer_event(&timer_event, &update_task);
508
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,
513 "description"},
514 true);
515
516 int r = m_mock_local_io_ctx->do_aio_operate(decltype(args)(args)...);
517 m_mock_local_io_ctx->aio_flush();
518 return r;
519 }));
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"}}},
525 "", 0);
526
527 update_task->complete(0);
528
529 shut_down_mirror_status_updater(mock_mirror_status_updater,
530 *mock_mirror_status_watcher);
531 }
532
533 TEST_F(TestMockMirrorStatusUpdater, ImmediateUpdate) {
534 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
535 m_mock_threads, "");
536 MockMirrorStatusWatcher* mock_mirror_status_watcher =
537 new MockMirrorStatusWatcher();
538
539 InSequence seq;
540
541 Context* timer_event = nullptr;
542 init_mirror_status_updater(mock_mirror_status_updater,
543 *mock_mirror_status_watcher, &timer_event);
544
545 expect_work_queue(false);
546 expect_mirror_status_update({{"1", cls::rbd::MirrorImageSiteStatus{}}},
547 "", 0);
548 mock_mirror_status_updater.set_mirror_image_status("1", {}, true);
549
550 shut_down_mirror_status_updater(mock_mirror_status_updater,
551 *mock_mirror_status_watcher);
552 }
553
554 TEST_F(TestMockMirrorStatusUpdater, RemoveImmediateUpdate) {
555 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
556 m_mock_threads, "");
557 MockMirrorStatusWatcher* mock_mirror_status_watcher =
558 new MockMirrorStatusWatcher();
559
560 InSequence seq;
561
562 Context* timer_event = nullptr;
563 init_mirror_status_updater(mock_mirror_status_updater,
564 *mock_mirror_status_watcher, &timer_event);
565
566 mock_mirror_status_updater.set_mirror_image_status("1", {}, false);
567
568 C_SaferCond ctx;
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());
574
575 shut_down_mirror_status_updater(mock_mirror_status_updater,
576 *mock_mirror_status_watcher);
577 }
578
579 TEST_F(TestMockMirrorStatusUpdater, RemoveRefreshIdleStatus) {
580 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
581 m_mock_threads, "");
582 MockMirrorStatusWatcher* mock_mirror_status_watcher =
583 new MockMirrorStatusWatcher();
584
585 InSequence seq;
586
587 Context* timer_event = nullptr;
588 init_mirror_status_updater(mock_mirror_status_updater,
589 *mock_mirror_status_watcher, &timer_event);
590
591 mock_mirror_status_updater.set_mirror_image_status("1", {}, false);
592
593 C_SaferCond ctx;
594 expect_work_queue(true);
595 mock_mirror_status_updater.remove_refresh_mirror_image_status("1", &ctx);
596 ASSERT_EQ(0, ctx.wait());
597
598 shut_down_mirror_status_updater(mock_mirror_status_updater,
599 *mock_mirror_status_watcher);
600 }
601
602 TEST_F(TestMockMirrorStatusUpdater, RemoveRefreshInFlightStatus) {
603 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
604 m_mock_threads, "");
605 MockMirrorStatusWatcher* mock_mirror_status_watcher =
606 new MockMirrorStatusWatcher();
607
608 InSequence seq;
609
610 Context* timer_event = nullptr;
611 init_mirror_status_updater(mock_mirror_status_updater,
612 *mock_mirror_status_watcher, &timer_event);
613
614 mock_mirror_status_updater.set_mirror_image_status("1", {}, false);
615
616 Context* update_task = nullptr;
617 fire_timer_event(&timer_event, &update_task);
618
619 C_SaferCond on_removed;
620 EXPECT_CALL(*m_mock_local_io_ctx, aio_operate(_, _, _, _, _))
621 .WillOnce(Invoke(
622 [this, &mock_mirror_status_updater, &on_removed](auto&&... args) {
623 mock_mirror_status_updater.remove_refresh_mirror_image_status(
624 "1", &on_removed);
625
626 int r = m_mock_local_io_ctx->do_aio_operate(decltype(args)(args)...);
627 m_mock_local_io_ctx->aio_flush();
628 return r;
629 }));
630 update_task->complete(0);
631 ASSERT_EQ(0, on_removed.wait());
632
633 shut_down_mirror_status_updater(mock_mirror_status_updater,
634 *mock_mirror_status_watcher);
635 }
636
637 TEST_F(TestMockMirrorStatusUpdater, ShutDownWhileUpdating) {
638 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
639 m_mock_threads, "");
640 MockMirrorStatusWatcher* mock_mirror_status_watcher =
641 new MockMirrorStatusWatcher();
642
643 InSequence seq;
644
645 Context* timer_event = nullptr;
646 init_mirror_status_updater(mock_mirror_status_updater,
647 *mock_mirror_status_watcher, &timer_event);
648
649 mock_mirror_status_updater.set_mirror_image_status("1", {}, false);
650
651 Context* update_task = nullptr;
652 fire_timer_event(&timer_event, &update_task);
653
654 C_SaferCond on_shutdown;
655 EXPECT_CALL(*m_mock_local_io_ctx, aio_operate(_, _, _, _, _))
656 .WillOnce(Invoke(
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();
660
661 int r = m_mock_local_io_ctx->do_aio_operate(decltype(args)(args)...);
662 m_mock_local_io_ctx->aio_flush();
663 return r;
664 }));
665
666 expect_timer_cancel_event();
667 expect_mirror_status_watcher_shut_down(*mock_mirror_status_watcher, 0);
668
669 update_task->complete(0);
670 ASSERT_EQ(0, on_shutdown.wait());
671 }
672
673 TEST_F(TestMockMirrorStatusUpdater, MirrorPeerSitePing) {
674 MockMirrorStatusUpdater mock_mirror_status_updater(m_local_io_ctx,
675 m_mock_threads,
676 "mirror uuid");
677 MockMirrorStatusWatcher* mock_mirror_status_watcher =
678 new MockMirrorStatusWatcher();
679
680 InSequence seq;
681
682 Context* timer_event = nullptr;
683 init_mirror_status_updater(mock_mirror_status_updater,
684 *mock_mirror_status_watcher, &timer_event);
685
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,
691 pair.first->second,
692 false);
693 }
694
695 Context* update_task = nullptr;
696 fire_timer_event(&timer_event, &update_task);
697
698 expect_mirror_status_update(mirror_image_site_statuses, "mirror uuid", 0);
699 update_task->complete(0);
700
701 shut_down_mirror_status_updater(mock_mirror_status_updater,
702 *mock_mirror_status_watcher);
703 }
704
705 } // namespace mirror
706 } // namespace rbd