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