]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_ImageReplayer.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_ImageReplayer.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "cls/journal/cls_journal_types.h"
7c673cae 5#include "librbd/journal/Types.h"
9f95a23c 6#include "librbd/journal/TypeTraits.h"
c07f9fc5 7#include "tools/rbd_mirror/ImageDeleter.h"
7c673cae 8#include "tools/rbd_mirror/ImageReplayer.h"
31f18b77 9#include "tools/rbd_mirror/InstanceWatcher.h"
9f95a23c 10#include "tools/rbd_mirror/MirrorStatusUpdater.h"
d2e6a577 11#include "tools/rbd_mirror/Threads.h"
7c673cae 12#include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
9f95a23c
TL
13#include "tools/rbd_mirror/image_replayer/Replayer.h"
14#include "tools/rbd_mirror/image_replayer/ReplayerListener.h"
15#include "tools/rbd_mirror/image_replayer/StateBuilder.h"
16#include "tools/rbd_mirror/image_replayer/Utils.h"
7c673cae 17#include "test/rbd_mirror/test_mock_fixture.h"
7c673cae 18#include "test/librbd/mock/MockImageCtx.h"
d2e6a577
FG
19#include "test/rbd_mirror/mock/MockContextWQ.h"
20#include "test/rbd_mirror/mock/MockSafeTimer.h"
7c673cae
FG
21
22namespace librbd {
23
24namespace {
25
7c673cae
FG
26struct MockTestImageCtx : public MockImageCtx {
27 MockTestImageCtx(librbd::ImageCtx &image_ctx)
28 : librbd::MockImageCtx(image_ctx) {
29 }
7c673cae
FG
30};
31
32} // anonymous namespace
33
7c673cae
FG
34} // namespace librbd
35
36namespace rbd {
37namespace mirror {
38
11fdf7f2
TL
39template <>
40struct ImageDeleter<librbd::MockTestImageCtx> {
41 static ImageDeleter* s_instance;
42
43 static void trash_move(librados::IoCtx& local_io_ctx,
44 const std::string& global_image_id, bool resync,
45 MockContextWQ* work_queue, Context* on_finish) {
46 ceph_assert(s_instance != nullptr);
47 s_instance->trash_move(global_image_id, resync, on_finish);
48 }
49
50 MOCK_METHOD3(trash_move, void(const std::string&, bool, Context*));
51
52 ImageDeleter() {
53 s_instance = this;
54 }
55};
56
57ImageDeleter<librbd::MockTestImageCtx>* ImageDeleter<librbd::MockTestImageCtx>::s_instance = nullptr;
58
9f95a23c
TL
59template <>
60struct MirrorStatusUpdater<librbd::MockTestImageCtx> {
61
62 MOCK_METHOD1(exists, bool(const std::string&));
63 MOCK_METHOD3(set_mirror_image_status,
64 void(const std::string&, const cls::rbd::MirrorImageSiteStatus&,
65 bool));
a4b75251
TL
66 MOCK_METHOD2(remove_refresh_mirror_image_status, void(const std::string&,
67 Context*));
68 MOCK_METHOD3(remove_mirror_image_status, void(const std::string&, bool,
69 Context*));
9f95a23c
TL
70};
71
d2e6a577
FG
72template <>
73struct Threads<librbd::MockTestImageCtx> {
74 MockSafeTimer *timer;
9f95a23c 75 ceph::mutex &timer_lock;
d2e6a577
FG
76
77 MockContextWQ *work_queue;
78
79 Threads(Threads<librbd::ImageCtx> *threads)
80 : timer(new MockSafeTimer()),
81 timer_lock(threads->timer_lock),
82 work_queue(new MockContextWQ()) {
83 }
84 ~Threads() {
85 delete timer;
86 delete work_queue;
87 }
88};
89
7c673cae 90template<>
31f18b77 91class InstanceWatcher<librbd::MockTestImageCtx> {
7c673cae
FG
92};
93
94namespace image_replayer {
95
7c673cae
FG
96template<>
97struct BootstrapRequest<librbd::MockTestImageCtx> {
98 static BootstrapRequest* s_instance;
9f95a23c
TL
99
100 StateBuilder<librbd::MockTestImageCtx>** state_builder = nullptr;
7c673cae 101 bool *do_resync = nullptr;
9f95a23c 102 Context *on_finish = nullptr;
7c673cae 103
31f18b77 104 static BootstrapRequest* create(
11fdf7f2 105 Threads<librbd::MockTestImageCtx>* threads,
9f95a23c
TL
106 librados::IoCtx &local_io_ctx,
107 librados::IoCtx& remote_io_ctx,
31f18b77 108 rbd::mirror::InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
11fdf7f2 109 const std::string &global_image_id,
d2e6a577 110 const std::string &local_mirror_uuid,
9f95a23c
TL
111 const RemotePoolMeta& remote_pool_meta,
112 ::journal::CacheManagerHandler *cache_manager_handler,
113 PoolMetaCache* pool_meta_cache,
114 rbd::mirror::ProgressContext *progress_ctx,
115 StateBuilder<librbd::MockTestImageCtx>** state_builder,
116 bool *do_resync, Context *on_finish) {
11fdf7f2 117 ceph_assert(s_instance != nullptr);
9f95a23c 118 s_instance->state_builder = state_builder;
7c673cae 119 s_instance->do_resync = do_resync;
9f95a23c 120 s_instance->on_finish = on_finish;
7c673cae
FG
121 return s_instance;
122 }
123
124 BootstrapRequest() {
11fdf7f2 125 ceph_assert(s_instance == nullptr);
7c673cae
FG
126 s_instance = this;
127 }
128
129 ~BootstrapRequest() {
11fdf7f2 130 ceph_assert(s_instance == this);
7c673cae
FG
131 s_instance = nullptr;
132 }
133
134 void put() {
135 }
136
137 void get() {
138 }
139
9f95a23c
TL
140 std::string get_local_image_name() const {
141 return "local image name";
142 }
143
c07f9fc5
FG
144 inline bool is_syncing() const {
145 return false;
146 }
147
7c673cae
FG
148 MOCK_METHOD0(send, void());
149 MOCK_METHOD0(cancel, void());
150};
151
9f95a23c
TL
152struct MockReplayer : public Replayer {
153 image_replayer::ReplayerListener* replayer_listener;
7c673cae 154
9f95a23c 155 MOCK_METHOD0(destroy, void());
7c673cae 156
9f95a23c
TL
157 MOCK_METHOD1(init, void(Context*));
158 MOCK_METHOD1(shut_down, void(Context*));
159 MOCK_METHOD1(flush, void(Context*));
7c673cae 160
9f95a23c 161 MOCK_METHOD2(get_replay_status, bool(std::string*, Context*));
7c673cae 162
9f95a23c
TL
163 MOCK_CONST_METHOD0(is_replaying, bool());
164 MOCK_CONST_METHOD0(is_resync_requested, bool());
165 MOCK_CONST_METHOD0(get_error_code, int());
166 MOCK_CONST_METHOD0(get_error_description, std::string());
7c673cae
FG
167};
168
9f95a23c
TL
169template <>
170struct StateBuilder<librbd::MockTestImageCtx> {
171 static StateBuilder* s_instance;
7c673cae 172
9f95a23c
TL
173 librbd::MockTestImageCtx* local_image_ctx = nullptr;
174 std::string local_image_id;
175 std::string remote_image_id;
7c673cae 176
9f95a23c 177 void destroy() {
7c673cae
FG
178 }
179
9f95a23c
TL
180 MOCK_METHOD1(close, void(Context*));
181 MOCK_METHOD5(create_replayer, Replayer*(Threads<librbd::MockTestImageCtx>*,
182 InstanceWatcher<librbd::MockTestImageCtx>*,
183 const std::string&, PoolMetaCache*,
184 ReplayerListener*));
7c673cae 185
9f95a23c 186 StateBuilder() {
7c673cae
FG
187 s_instance = this;
188 }
7c673cae
FG
189};
190
191BootstrapRequest<librbd::MockTestImageCtx>* BootstrapRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
9f95a23c 192StateBuilder<librbd::MockTestImageCtx>* StateBuilder<librbd::MockTestImageCtx>::s_instance = nullptr;
7c673cae
FG
193
194} // namespace image_replayer
195} // namespace mirror
196} // namespace rbd
197
198// template definitions
199#include "tools/rbd_mirror/ImageReplayer.cc"
7c673cae
FG
200
201namespace rbd {
202namespace mirror {
203
9f95a23c
TL
204using ::testing::_;
205using ::testing::AtLeast;
206using ::testing::DoAll;
207using ::testing::InSequence;
208using ::testing::Invoke;
209using ::testing::MatcherCast;
210using ::testing::Return;
211using ::testing::ReturnArg;
212using ::testing::SetArgPointee;
213using ::testing::WithArg;
214
7c673cae
FG
215class TestMockImageReplayer : public TestMockFixture {
216public:
d2e6a577 217 typedef Threads<librbd::MockTestImageCtx> MockThreads;
c07f9fc5 218 typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter;
9f95a23c
TL
219 typedef MirrorStatusUpdater<librbd::MockTestImageCtx> MockMirrorStatusUpdater;
220 typedef image_replayer::BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
221 typedef image_replayer::StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
222 typedef image_replayer::MockReplayer MockReplayer;
7c673cae 223 typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
31f18b77 224 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
7c673cae
FG
225
226 void SetUp() override {
227 TestMockFixture::SetUp();
228
229 librbd::RBD rbd;
230 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
231 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
7c673cae
FG
232 }
233
234 void TearDown() override {
235 delete m_image_replayer;
236
237 TestMockFixture::TearDown();
238 }
239
240 void create_local_image() {
241 librbd::RBD rbd;
242 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
243 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
244 }
245
d2e6a577
FG
246 void expect_work_queue_repeatedly(MockThreads &mock_threads) {
247 EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
248 .WillRepeatedly(Invoke([this](Context *ctx, int r) {
249 m_threads->work_queue->queue(ctx, r);
250 }));
251 }
252
253 void expect_add_event_after_repeatedly(MockThreads &mock_threads) {
254 EXPECT_CALL(*mock_threads.timer, add_event_after(_, _))
255 .WillRepeatedly(
3efd9988
FG
256 DoAll(Invoke([this](double seconds, Context *ctx) {
257 m_threads->timer->add_event_after(seconds, ctx);
258 }),
259 ReturnArg<1>()));
d2e6a577
FG
260 EXPECT_CALL(*mock_threads.timer, cancel_event(_))
261 .WillRepeatedly(
262 Invoke([this](Context *ctx) {
263 return m_threads->timer->cancel_event(ctx);
264 }));
265 }
266
11fdf7f2
TL
267 void expect_trash_move(MockImageDeleter& mock_image_deleter,
268 const std::string& global_image_id,
269 bool ignore_orphan, int r) {
d2e6a577 270 EXPECT_CALL(mock_image_deleter,
11fdf7f2
TL
271 trash_move(global_image_id, ignore_orphan, _))
272 .WillOnce(WithArg<2>(Invoke([this, r](Context* ctx) {
d2e6a577
FG
273 m_threads->work_queue->queue(ctx, r);
274 })));
275 }
276
7c673cae
FG
277 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
278 bufferlist bl;
11fdf7f2 279 encode(tag_data, bl);
7c673cae
FG
280 return bl;
281 }
282
9f95a23c
TL
283 void expect_send(MockBootstrapRequest& mock_bootstrap_request,
284 MockStateBuilder& mock_state_builder,
285 librbd::MockTestImageCtx& mock_local_image_ctx,
a4b75251 286 bool do_resync, bool set_local_image, int r) {
7c673cae 287 EXPECT_CALL(mock_bootstrap_request, send())
9f95a23c 288 .WillOnce(Invoke([this, &mock_bootstrap_request, &mock_state_builder,
a4b75251
TL
289 &mock_local_image_ctx, set_local_image, do_resync,
290 r]() {
9f95a23c
TL
291 if (r == 0 || r == -ENOLINK) {
292 mock_state_builder.local_image_id = mock_local_image_ctx.id;
293 mock_state_builder.remote_image_id = m_remote_image_ctx->id;
294 *mock_bootstrap_request.state_builder = &mock_state_builder;
295 }
7c673cae 296 if (r == 0) {
9f95a23c 297 mock_state_builder.local_image_ctx = &mock_local_image_ctx;
7c673cae
FG
298 *mock_bootstrap_request.do_resync = do_resync;
299 }
a4b75251 300 if (r < 0 && r != -ENOENT) {
9f95a23c
TL
301 mock_state_builder.remote_image_id = "";
302 }
a4b75251
TL
303 if (r == -ENOENT) {
304 *mock_bootstrap_request.state_builder = &mock_state_builder;
305 }
306 if (set_local_image) {
307 mock_state_builder.local_image_id = mock_local_image_ctx.id;
308 }
7c673cae
FG
309 mock_bootstrap_request.on_finish->complete(r);
310 }));
311 }
312
9f95a23c
TL
313 void expect_create_replayer(MockStateBuilder& mock_state_builder,
314 MockReplayer& mock_replayer) {
315 EXPECT_CALL(mock_state_builder, create_replayer(_, _, _, _, _))
316 .WillOnce(WithArg<4>(
317 Invoke([&mock_replayer]
318 (image_replayer::ReplayerListener* replayer_listener) {
319 mock_replayer.replayer_listener = replayer_listener;
320 return &mock_replayer;
321 })));
7c673cae
FG
322 }
323
9f95a23c
TL
324 void expect_close(MockStateBuilder& mock_state_builder, int r) {
325 EXPECT_CALL(mock_state_builder, close(_))
326 .WillOnce(Invoke([this, r](Context* ctx) {
327 m_threads->work_queue->queue(ctx, r);
328 }));
7c673cae
FG
329 }
330
9f95a23c
TL
331 void expect_init(MockReplayer& mock_replayer, int r) {
332 EXPECT_CALL(mock_replayer, init(_))
333 .WillOnce(Invoke([this, r](Context* ctx) {
334 m_threads->work_queue->queue(ctx, r);
335 }));
7c673cae
FG
336 }
337
9f95a23c
TL
338 void expect_shut_down(MockReplayer& mock_replayer, int r) {
339 EXPECT_CALL(mock_replayer, shut_down(_))
340 .WillOnce(Invoke([this, r](Context* ctx) {
341 m_threads->work_queue->queue(ctx, r);
342 }));
343 EXPECT_CALL(mock_replayer, destroy());
7c673cae
FG
344 }
345
9f95a23c
TL
346 void expect_get_replay_status(MockReplayer& mock_replayer) {
347 EXPECT_CALL(mock_replayer, get_replay_status(_, _))
348 .WillRepeatedly(DoAll(WithArg<1>(CompleteContext(-EEXIST)),
349 Return(true)));
7c673cae
FG
350 }
351
9f95a23c
TL
352 void expect_set_mirror_image_status_repeatedly() {
353 EXPECT_CALL(m_local_status_updater, set_mirror_image_status(_, _, _))
354 .WillRepeatedly(Invoke([](auto, auto, auto){}));
355 EXPECT_CALL(m_remote_status_updater, set_mirror_image_status(_, _, _))
356 .WillRepeatedly(Invoke([](auto, auto, auto){}));
7c673cae
FG
357 }
358
9f95a23c
TL
359 void expect_mirror_image_status_exists(bool exists) {
360 EXPECT_CALL(m_local_status_updater, exists(_))
361 .WillOnce(Return(exists));
362 EXPECT_CALL(m_remote_status_updater, exists(_))
363 .WillOnce(Return(exists));
7c673cae
FG
364 }
365
11fdf7f2 366 void create_image_replayer(MockThreads &mock_threads) {
c07f9fc5 367 m_image_replayer = new MockImageReplayer(
9f95a23c
TL
368 m_local_io_ctx, "local_mirror_uuid", "global image id",
369 &mock_threads, &m_instance_watcher, &m_local_status_updater, nullptr,
370 nullptr);
371 m_image_replayer->add_peer({"peer_uuid", m_remote_io_ctx,
372 {"remote mirror uuid",
373 "remote mirror peer uuid"},
374 &m_remote_status_updater});
375 }
376
377 void wait_for_stopped() {
378 for (int i = 0; i < 10000; i++) {
379 if (m_image_replayer->is_stopped()) {
380 break;
381 }
382 usleep(1000);
383 }
384 ASSERT_TRUE(m_image_replayer->is_stopped());
c07f9fc5
FG
385 }
386
7c673cae
FG
387 librbd::ImageCtx *m_remote_image_ctx;
388 librbd::ImageCtx *m_local_image_ctx = nullptr;
31f18b77 389 MockInstanceWatcher m_instance_watcher;
9f95a23c
TL
390 MockMirrorStatusUpdater m_local_status_updater;
391 MockMirrorStatusUpdater m_remote_status_updater;
c07f9fc5 392 MockImageReplayer *m_image_replayer = nullptr;
7c673cae
FG
393};
394
395TEST_F(TestMockImageReplayer, StartStop) {
396 // START
397
398 create_local_image();
399 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
400
d2e6a577
FG
401 MockThreads mock_threads(m_threads);
402 expect_work_queue_repeatedly(mock_threads);
403 expect_add_event_after_repeatedly(mock_threads);
404
405 MockImageDeleter mock_image_deleter;
9f95a23c 406 MockReplayer mock_replayer;
7c673cae 407
9f95a23c
TL
408 expect_get_replay_status(mock_replayer);
409 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
410
411 InSequence seq;
9f95a23c
TL
412 MockBootstrapRequest mock_bootstrap_request;
413 MockStateBuilder mock_state_builder;
414 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 415 false, false, 0);
7c673cae 416
9f95a23c
TL
417 expect_create_replayer(mock_state_builder, mock_replayer);
418 expect_init(mock_replayer, 0);
7c673cae 419
11fdf7f2 420 create_image_replayer(mock_threads);
c07f9fc5 421
7c673cae
FG
422 C_SaferCond start_ctx;
423 m_image_replayer->start(&start_ctx);
424 ASSERT_EQ(0, start_ctx.wait());
c07f9fc5
FG
425 ASSERT_EQ(image_replayer::HEALTH_STATE_OK,
426 m_image_replayer->get_health_state());
7c673cae
FG
427
428 // STOP
9f95a23c
TL
429 expect_shut_down(mock_replayer, 0);
430 expect_close(mock_state_builder, 0);
431 expect_mirror_image_status_exists(false);
7c673cae 432
7c673cae
FG
433 C_SaferCond stop_ctx;
434 m_image_replayer->stop(&stop_ctx);
435 ASSERT_EQ(0, stop_ctx.wait());
c07f9fc5
FG
436 ASSERT_EQ(image_replayer::HEALTH_STATE_OK,
437 m_image_replayer->get_health_state());
7c673cae
FG
438}
439
440TEST_F(TestMockImageReplayer, LocalImagePrimary) {
441 create_local_image();
442 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
443
d2e6a577
FG
444 MockThreads mock_threads(m_threads);
445 expect_work_queue_repeatedly(mock_threads);
446 expect_add_event_after_repeatedly(mock_threads);
447
448 MockImageDeleter mock_image_deleter;
7c673cae 449 MockBootstrapRequest mock_bootstrap_request;
7c673cae 450
9f95a23c 451 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
452
453 InSequence seq;
7c673cae 454
9f95a23c
TL
455 MockStateBuilder mock_state_builder;
456 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251
TL
457 false, false, -ENOMSG);
458
459 expect_mirror_image_status_exists(false);
460
461 create_image_replayer(mock_threads);
462
463 C_SaferCond start_ctx;
464 m_image_replayer->start(&start_ctx);
465 ASSERT_EQ(0, start_ctx.wait());
466}
467
468TEST_F(TestMockImageReplayer, MetadataCleanup) {
469 // START
470
471 create_local_image();
472 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
473
474 MockThreads mock_threads(m_threads);
475 expect_work_queue_repeatedly(mock_threads);
476 expect_add_event_after_repeatedly(mock_threads);
477
478 MockImageDeleter mock_image_deleter;
479 MockBootstrapRequest mock_bootstrap_request;
480 MockReplayer mock_replayer;
481
482 expect_get_replay_status(mock_replayer);
483 expect_set_mirror_image_status_repeatedly();
484
485 InSequence seq;
486
487 MockStateBuilder mock_state_builder;
488 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
489 false, true, -ENOLINK);
9f95a23c 490
a4b75251
TL
491 expect_close(mock_state_builder, 0);
492 expect_trash_move(mock_image_deleter, "global image id", false, 0);
9f95a23c 493 expect_mirror_image_status_exists(false);
7c673cae 494
11fdf7f2 495 create_image_replayer(mock_threads);
c07f9fc5 496
7c673cae
FG
497 C_SaferCond start_ctx;
498 m_image_replayer->start(&start_ctx);
9f95a23c 499 ASSERT_EQ(0, start_ctx.wait());
7c673cae
FG
500}
501
9f95a23c 502TEST_F(TestMockImageReplayer, BootstrapRemoteDeleted) {
7c673cae
FG
503 create_local_image();
504 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
505
d2e6a577
FG
506 MockThreads mock_threads(m_threads);
507 expect_work_queue_repeatedly(mock_threads);
508 expect_add_event_after_repeatedly(mock_threads);
509
510 MockImageDeleter mock_image_deleter;
7c673cae 511
9f95a23c 512 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
513
514 InSequence seq;
d2e6a577 515
9f95a23c
TL
516 MockBootstrapRequest mock_bootstrap_request;
517 MockStateBuilder mock_state_builder;
518 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 519 false, false, -ENOLINK);
d2e6a577 520
9f95a23c 521 expect_close(mock_state_builder, 0);
d2e6a577 522
11fdf7f2 523 expect_trash_move(mock_image_deleter, "global image id", false, 0);
9f95a23c 524 expect_mirror_image_status_exists(false);
d2e6a577 525
11fdf7f2 526 create_image_replayer(mock_threads);
d2e6a577
FG
527
528 C_SaferCond start_ctx;
529 m_image_replayer->start(&start_ctx);
530 ASSERT_EQ(0, start_ctx.wait());
531}
532
9f95a23c 533TEST_F(TestMockImageReplayer, BootstrapResyncRequested) {
d2e6a577
FG
534 create_local_image();
535 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
536
537 MockThreads mock_threads(m_threads);
538 expect_work_queue_repeatedly(mock_threads);
539 expect_add_event_after_repeatedly(mock_threads);
540
541 MockImageDeleter mock_image_deleter;
d2e6a577 542
9f95a23c 543 expect_set_mirror_image_status_repeatedly();
d2e6a577
FG
544
545 InSequence seq;
d2e6a577 546
9f95a23c
TL
547 MockBootstrapRequest mock_bootstrap_request;
548 MockStateBuilder mock_state_builder;
549 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 550 true, false, 0);
d2e6a577 551
9f95a23c 552 expect_close(mock_state_builder, 0);
d2e6a577 553
9f95a23c
TL
554 expect_trash_move(mock_image_deleter, "global image id", true, 0);
555 expect_mirror_image_status_exists(false);
d2e6a577 556
11fdf7f2 557 create_image_replayer(mock_threads);
c07f9fc5 558
7c673cae
FG
559 C_SaferCond start_ctx;
560 m_image_replayer->start(&start_ctx);
9f95a23c 561 ASSERT_EQ(0, start_ctx.wait());
7c673cae
FG
562}
563
564TEST_F(TestMockImageReplayer, BootstrapError) {
7c673cae
FG
565 create_local_image();
566 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
567
d2e6a577
FG
568 MockThreads mock_threads(m_threads);
569 expect_work_queue_repeatedly(mock_threads);
570 expect_add_event_after_repeatedly(mock_threads);
571
572 MockImageDeleter mock_image_deleter;
7c673cae 573 MockBootstrapRequest mock_bootstrap_request;
7c673cae 574
9f95a23c 575 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
576
577 InSequence seq;
9f95a23c
TL
578 MockStateBuilder mock_state_builder;
579 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 580 false, false, -EINVAL);
7c673cae 581
9f95a23c 582 expect_mirror_image_status_exists(false);
7c673cae 583
11fdf7f2 584 create_image_replayer(mock_threads);
c07f9fc5 585
7c673cae
FG
586 C_SaferCond start_ctx;
587 m_image_replayer->start(&start_ctx);
588 ASSERT_EQ(-EINVAL, start_ctx.wait());
589}
590
9f95a23c 591TEST_F(TestMockImageReplayer, BootstrapCancel) {
11fdf7f2
TL
592 create_local_image();
593 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
594
11fdf7f2
TL
595 MockThreads mock_threads(m_threads);
596 expect_work_queue_repeatedly(mock_threads);
597 expect_add_event_after_repeatedly(mock_threads);
598
599 MockImageDeleter mock_image_deleter;
11fdf7f2 600
9f95a23c 601 expect_set_mirror_image_status_repeatedly();
11fdf7f2
TL
602
603 InSequence seq;
11fdf7f2
TL
604
605 create_image_replayer(mock_threads);
606
9f95a23c
TL
607 MockBootstrapRequest mock_bootstrap_request;
608 MockStateBuilder mock_state_builder;
609 EXPECT_CALL(mock_bootstrap_request, send())
610 .WillOnce(Invoke([this, &mock_bootstrap_request]() {
20effc67 611 m_image_replayer->stop(nullptr);
9f95a23c
TL
612 mock_bootstrap_request.on_finish->complete(-ECANCELED);
613 }));
614 EXPECT_CALL(mock_bootstrap_request, cancel());
615
616 expect_mirror_image_status_exists(false);
617
11fdf7f2
TL
618 C_SaferCond start_ctx;
619 m_image_replayer->start(&start_ctx);
620 ASSERT_EQ(-ECANCELED, start_ctx.wait());
621}
622
9f95a23c 623TEST_F(TestMockImageReplayer, StopError) {
7c673cae
FG
624 // START
625
626 create_local_image();
627 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
628
d2e6a577
FG
629 MockThreads mock_threads(m_threads);
630 expect_work_queue_repeatedly(mock_threads);
631 expect_add_event_after_repeatedly(mock_threads);
632
633 MockImageDeleter mock_image_deleter;
7c673cae 634 MockBootstrapRequest mock_bootstrap_request;
9f95a23c 635 MockReplayer mock_replayer;
7c673cae 636
9f95a23c
TL
637 expect_get_replay_status(mock_replayer);
638 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
639
640 InSequence seq;
9f95a23c
TL
641 MockStateBuilder mock_state_builder;
642 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 643 false, false, 0);
7c673cae 644
9f95a23c
TL
645 expect_create_replayer(mock_state_builder, mock_replayer);
646 expect_init(mock_replayer, 0);
7c673cae 647
11fdf7f2 648 create_image_replayer(mock_threads);
c07f9fc5 649
7c673cae
FG
650 C_SaferCond start_ctx;
651 m_image_replayer->start(&start_ctx);
9f95a23c 652 ASSERT_EQ(0, start_ctx.wait());
7c673cae 653
9f95a23c
TL
654 // STOP (errors are ignored)
655
656 expect_shut_down(mock_replayer, -EINVAL);
657 expect_close(mock_state_builder, -EINVAL);
658 expect_mirror_image_status_exists(false);
659
660 C_SaferCond stop_ctx;
661 m_image_replayer->stop(&stop_ctx);
662 ASSERT_EQ(0, stop_ctx.wait());
663}
7c673cae 664
9f95a23c 665TEST_F(TestMockImageReplayer, ReplayerError) {
7c673cae
FG
666 create_local_image();
667 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
668
d2e6a577
FG
669 MockThreads mock_threads(m_threads);
670 expect_work_queue_repeatedly(mock_threads);
671 expect_add_event_after_repeatedly(mock_threads);
672
673 MockImageDeleter mock_image_deleter;
7c673cae 674 MockBootstrapRequest mock_bootstrap_request;
9f95a23c 675 MockReplayer mock_replayer;
7c673cae 676
9f95a23c 677 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
678
679 InSequence seq;
9f95a23c
TL
680 MockStateBuilder mock_state_builder;
681 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 682 false, false, 0);
7c673cae 683
9f95a23c
TL
684 expect_create_replayer(mock_state_builder, mock_replayer);
685 expect_init(mock_replayer, -EINVAL);
686 EXPECT_CALL(mock_replayer, get_error_description())
687 .WillOnce(Return("FAIL"));
7c673cae 688
9f95a23c
TL
689 EXPECT_CALL(mock_replayer, destroy());
690 expect_close(mock_state_builder, -EINVAL);
7c673cae 691
9f95a23c 692 expect_mirror_image_status_exists(false);
11fdf7f2 693 create_image_replayer(mock_threads);
c07f9fc5 694
7c673cae
FG
695 C_SaferCond start_ctx;
696 m_image_replayer->start(&start_ctx);
9f95a23c 697 ASSERT_EQ(-EINVAL, start_ctx.wait());
7c673cae
FG
698}
699
9f95a23c 700TEST_F(TestMockImageReplayer, ReplayerResync) {
7c673cae 701 // START
7c673cae
FG
702 create_local_image();
703 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
704
d2e6a577
FG
705 MockThreads mock_threads(m_threads);
706 expect_work_queue_repeatedly(mock_threads);
707 expect_add_event_after_repeatedly(mock_threads);
708
709 MockImageDeleter mock_image_deleter;
7c673cae 710 MockBootstrapRequest mock_bootstrap_request;
9f95a23c 711 MockReplayer mock_replayer;
7c673cae 712
9f95a23c
TL
713 expect_get_replay_status(mock_replayer);
714 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
715
716 InSequence seq;
9f95a23c
TL
717 MockStateBuilder mock_state_builder;
718 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 719 false, false, 0);
7c673cae 720
9f95a23c
TL
721 expect_create_replayer(mock_state_builder, mock_replayer);
722 expect_init(mock_replayer, 0);
7c673cae 723
11fdf7f2 724 create_image_replayer(mock_threads);
c07f9fc5 725
7c673cae
FG
726 C_SaferCond start_ctx;
727 m_image_replayer->start(&start_ctx);
728 ASSERT_EQ(0, start_ctx.wait());
729
9f95a23c
TL
730 // NOTIFY
731 EXPECT_CALL(mock_replayer, is_resync_requested())
732 .WillOnce(Return(true));
733 expect_shut_down(mock_replayer, 0);
734 expect_close(mock_state_builder, 0);
735 expect_trash_move(mock_image_deleter, "global image id", true, 0);
736 expect_mirror_image_status_exists(false);
737 mock_replayer.replayer_listener->handle_notification();
738 ASSERT_FALSE(m_image_replayer->is_running());
739
740 wait_for_stopped();
7c673cae
FG
741}
742
9f95a23c 743TEST_F(TestMockImageReplayer, ReplayerInterrupted) {
7c673cae 744 // START
7c673cae
FG
745 create_local_image();
746 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
747
d2e6a577
FG
748 MockThreads mock_threads(m_threads);
749 expect_work_queue_repeatedly(mock_threads);
750 expect_add_event_after_repeatedly(mock_threads);
751
752 MockImageDeleter mock_image_deleter;
7c673cae 753 MockBootstrapRequest mock_bootstrap_request;
9f95a23c 754 MockReplayer mock_replayer;
7c673cae 755
9f95a23c
TL
756 expect_get_replay_status(mock_replayer);
757 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
758
759 InSequence seq;
9f95a23c
TL
760 MockStateBuilder mock_state_builder;
761 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 762 false, false, 0);
7c673cae 763
9f95a23c
TL
764 expect_create_replayer(mock_state_builder, mock_replayer);
765 expect_init(mock_replayer, 0);
7c673cae 766
11fdf7f2 767 create_image_replayer(mock_threads);
c07f9fc5 768
7c673cae
FG
769 C_SaferCond start_ctx;
770 m_image_replayer->start(&start_ctx);
771 ASSERT_EQ(0, start_ctx.wait());
772
9f95a23c
TL
773 // NOTIFY
774 EXPECT_CALL(mock_replayer, is_resync_requested())
775 .WillOnce(Return(false));
776 EXPECT_CALL(mock_replayer, is_replaying())
777 .WillOnce(Return(false));
778 EXPECT_CALL(mock_replayer, get_error_code())
7c673cae 779 .WillOnce(Return(-EINVAL));
9f95a23c
TL
780 EXPECT_CALL(mock_replayer, get_error_description())
781 .WillOnce(Return("INVALID"));
782 expect_shut_down(mock_replayer, 0);
783 expect_close(mock_state_builder, 0);
784 expect_mirror_image_status_exists(false);
785 mock_replayer.replayer_listener->handle_notification();
786 ASSERT_FALSE(m_image_replayer->is_running());
787
788 wait_for_stopped();
7c673cae
FG
789}
790
9f95a23c 791TEST_F(TestMockImageReplayer, ReplayerRenamed) {
7c673cae 792 // START
7c673cae
FG
793 create_local_image();
794 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
795
d2e6a577
FG
796 MockThreads mock_threads(m_threads);
797 expect_work_queue_repeatedly(mock_threads);
798 expect_add_event_after_repeatedly(mock_threads);
799
800 MockImageDeleter mock_image_deleter;
7c673cae 801 MockBootstrapRequest mock_bootstrap_request;
9f95a23c 802 MockReplayer mock_replayer;
7c673cae 803
9f95a23c
TL
804 expect_get_replay_status(mock_replayer);
805 expect_set_mirror_image_status_repeatedly();
7c673cae
FG
806
807 InSequence seq;
9f95a23c
TL
808 MockStateBuilder mock_state_builder;
809 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
a4b75251 810 false, false, 0);
7c673cae 811
9f95a23c
TL
812 expect_create_replayer(mock_state_builder, mock_replayer);
813 expect_init(mock_replayer, 0);
7c673cae 814
11fdf7f2 815 create_image_replayer(mock_threads);
c07f9fc5 816
7c673cae
FG
817 C_SaferCond start_ctx;
818 m_image_replayer->start(&start_ctx);
819 ASSERT_EQ(0, start_ctx.wait());
820
9f95a23c
TL
821 // NOTIFY
822 EXPECT_CALL(mock_replayer, is_resync_requested())
823 .WillOnce(Return(false));
824 EXPECT_CALL(mock_replayer, is_replaying())
825 .WillOnce(Return(true));
826 mock_local_image_ctx.name = "NEW NAME";
827 mock_replayer.replayer_listener->handle_notification();
7c673cae
FG
828
829 // STOP
9f95a23c
TL
830 expect_shut_down(mock_replayer, 0);
831 expect_close(mock_state_builder, 0);
832 expect_mirror_image_status_exists(false);
7c673cae 833
7c673cae
FG
834 C_SaferCond stop_ctx;
835 m_image_replayer->stop(&stop_ctx);
836 ASSERT_EQ(0, stop_ctx.wait());
7c673cae 837
9f95a23c
TL
838 auto image_spec = image_replayer::util::compute_image_spec(
839 m_local_io_ctx, "NEW NAME");
840 ASSERT_EQ(image_spec, m_image_replayer->get_name());
841}
d2e6a577 842
20effc67
TL
843TEST_F(TestMockImageReplayer, StopJoinInterruptedReplayer) {
844 // START
845 create_local_image();
846 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
847
848 MockThreads mock_threads(m_threads);
849 expect_work_queue_repeatedly(mock_threads);
850 expect_add_event_after_repeatedly(mock_threads);
851
852 MockReplayer mock_replayer;
853 expect_get_replay_status(mock_replayer);
854 expect_set_mirror_image_status_repeatedly();
855
856 InSequence seq;
857 MockBootstrapRequest mock_bootstrap_request;
858 MockStateBuilder mock_state_builder;
859 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
860 false, false, 0);
861
862 expect_create_replayer(mock_state_builder, mock_replayer);
863 expect_init(mock_replayer, 0);
864
865 create_image_replayer(mock_threads);
866
867 C_SaferCond start_ctx;
868 m_image_replayer->start(&start_ctx);
869 ASSERT_EQ(0, start_ctx.wait());
870
871 // NOTIFY
872 EXPECT_CALL(mock_replayer, is_resync_requested())
873 .WillOnce(Return(false));
874 EXPECT_CALL(mock_replayer, is_replaying())
875 .WillOnce(Return(false));
876 EXPECT_CALL(mock_replayer, get_error_code())
877 .WillOnce(Return(-EINVAL));
878 EXPECT_CALL(mock_replayer, get_error_description())
879 .WillOnce(Return("INVALID"));
880 const double DELAY = 10;
881 EXPECT_CALL(mock_replayer, shut_down(_))
882 .WillOnce(Invoke([this, DELAY](Context* ctx) {
883 m_threads->timer->add_event_after(DELAY, ctx);
884 }));
885 EXPECT_CALL(mock_replayer, destroy());
886 expect_close(mock_state_builder, 0);
887 expect_mirror_image_status_exists(false);
888
889 mock_replayer.replayer_listener->handle_notification();
890 ASSERT_FALSE(m_image_replayer->is_running());
891
892 C_SaferCond stop_ctx;
893 m_image_replayer->stop(&stop_ctx);
894 ASSERT_EQ(ETIMEDOUT, stop_ctx.wait_for(DELAY * 3 / 4));
895 ASSERT_EQ(0, stop_ctx.wait_for(DELAY));
896}
897
898TEST_F(TestMockImageReplayer, StopJoinRequestedStop) {
899 // START
900 create_local_image();
901 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
902
903 MockThreads mock_threads(m_threads);
904 expect_work_queue_repeatedly(mock_threads);
905 expect_add_event_after_repeatedly(mock_threads);
906
907 MockReplayer mock_replayer;
908 expect_get_replay_status(mock_replayer);
909 expect_set_mirror_image_status_repeatedly();
910
911 InSequence seq;
912 MockBootstrapRequest mock_bootstrap_request;
913 MockStateBuilder mock_state_builder;
914 expect_send(mock_bootstrap_request, mock_state_builder, mock_local_image_ctx,
915 false, false, 0);
916
917 expect_create_replayer(mock_state_builder, mock_replayer);
918 expect_init(mock_replayer, 0);
919
920 create_image_replayer(mock_threads);
921
922 C_SaferCond start_ctx;
923 m_image_replayer->start(&start_ctx);
924 ASSERT_EQ(0, start_ctx.wait());
925
926 // STOP
927 const double DELAY = 10;
928 EXPECT_CALL(mock_replayer, shut_down(_))
929 .WillOnce(Invoke([this, DELAY](Context* ctx) {
930 m_threads->timer->add_event_after(DELAY, ctx);
931 }));
932 EXPECT_CALL(mock_replayer, destroy());
933 expect_close(mock_state_builder, 0);
934 expect_mirror_image_status_exists(false);
935
936 C_SaferCond stop_ctx1;
937 m_image_replayer->stop(&stop_ctx1);
938
939 C_SaferCond stop_ctx2;
940 m_image_replayer->stop(&stop_ctx2);
941 ASSERT_EQ(ETIMEDOUT, stop_ctx2.wait_for(DELAY * 3 / 4));
942 ASSERT_EQ(0, stop_ctx2.wait_for(DELAY));
943
944 ASSERT_EQ(0, stop_ctx1.wait_for(0));
945}
946
7c673cae
FG
947} // namespace mirror
948} // namespace rbd