1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "cls/rbd/cls_rbd_client.h"
8 #include "librbd/Operations.h"
9 #include "librbd/internal.h"
10 #include "librbd/image/SetFlagsRequest.h"
11 #include "librbd/io/AioCompletion.h"
12 #include "librbd/mirror/EnableRequest.h"
13 #include "librbd/journal/CreateRequest.h"
14 #include "librbd/journal/Types.h"
15 #include "librbd/object_map/CreateRequest.h"
16 #include "librbd/operation/EnableFeaturesRequest.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
24 struct MockOperationImageCtx : public MockImageCtx {
25 MockOperationImageCtx(librbd::ImageCtx& image_ctx)
26 : MockImageCtx(image_ctx) {
30 } // anonymous namespace
35 class SetFlagsRequest<MockOperationImageCtx> {
37 static SetFlagsRequest *s_instance;
38 Context *on_finish = nullptr;
40 static SetFlagsRequest *create(MockOperationImageCtx *image_ctx, uint64_t flags,
41 uint64_t mask, Context *on_finish) {
42 assert(s_instance != nullptr);
43 s_instance->on_finish = on_finish;
51 MOCK_METHOD0(send, void());
54 SetFlagsRequest<MockOperationImageCtx> *SetFlagsRequest<MockOperationImageCtx>::s_instance;
61 class CreateRequest<MockOperationImageCtx> {
63 static CreateRequest *s_instance;
64 Context *on_finish = nullptr;
66 static CreateRequest *create(IoCtx &ioctx, const std::string &imageid,
67 uint8_t order, uint8_t splay_width,
68 const std::string &object_pool,
69 uint64_t tag_class, TagData &tag_data,
70 const std::string &client_id,
71 MockContextWQ *op_work_queue,
73 assert(s_instance != nullptr);
74 s_instance->on_finish = on_finish;
82 MOCK_METHOD0(send, void());
85 CreateRequest<MockOperationImageCtx> *CreateRequest<MockOperationImageCtx>::s_instance = nullptr;
87 } // namespace journal
92 class EnableRequest<MockOperationImageCtx> {
94 static EnableRequest *s_instance;
95 Context *on_finish = nullptr;
97 static EnableRequest *create(MockOperationImageCtx *image_ctx, Context *on_finish) {
98 assert(s_instance != nullptr);
99 s_instance->on_finish = on_finish;
107 MOCK_METHOD0(send, void());
110 EnableRequest<MockOperationImageCtx> *EnableRequest<MockOperationImageCtx>::s_instance = nullptr;
112 } // namespace mirror
114 namespace object_map {
117 class CreateRequest<MockOperationImageCtx> {
119 static CreateRequest *s_instance;
120 Context *on_finish = nullptr;
122 static CreateRequest *create(MockOperationImageCtx *image_ctx, Context *on_finish) {
123 assert(s_instance != nullptr);
124 s_instance->on_finish = on_finish;
132 MOCK_METHOD0(send, void());
135 CreateRequest<MockOperationImageCtx> *CreateRequest<MockOperationImageCtx>::s_instance = nullptr;
137 } // namespace object_map
140 struct AsyncRequest<MockOperationImageCtx> : public AsyncRequest<MockImageCtx> {
141 MockOperationImageCtx &m_image_ctx;
143 AsyncRequest(MockOperationImageCtx &image_ctx, Context *on_finish)
144 : AsyncRequest<MockImageCtx>(image_ctx, on_finish), m_image_ctx(image_ctx) {
148 } // namespace librbd
150 // template definitions
151 #include "librbd/AsyncRequest.cc"
152 #include "librbd/AsyncObjectThrottle.cc"
153 #include "librbd/operation/Request.cc"
154 #include "librbd/operation/EnableFeaturesRequest.cc"
157 namespace operation {
159 using ::testing::Invoke;
160 using ::testing::Return;
161 using ::testing::WithArg;
164 class TestMockOperationEnableFeaturesRequest : public TestMockFixture {
166 typedef librbd::image::SetFlagsRequest<MockOperationImageCtx> MockSetFlagsRequest;
167 typedef librbd::journal::CreateRequest<MockOperationImageCtx> MockCreateJournalRequest;
168 typedef librbd::mirror::EnableRequest<MockOperationImageCtx> MockEnableMirrorRequest;
169 typedef librbd::object_map::CreateRequest<MockOperationImageCtx> MockCreateObjectMapRequest;
170 typedef EnableFeaturesRequest<MockOperationImageCtx> MockEnableFeaturesRequest;
172 class PoolMirrorModeEnabler {
174 PoolMirrorModeEnabler(librados::IoCtx &ioctx) : m_ioctx(ioctx) {
175 EXPECT_EQ(0, librbd::cls_client::mirror_uuid_set(&m_ioctx, "test-uuid"));
176 EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(
177 &m_ioctx, cls::rbd::MIRROR_MODE_POOL));
180 ~PoolMirrorModeEnabler() {
181 EXPECT_EQ(0, librbd::cls_client::mirror_mode_set(
182 &m_ioctx, cls::rbd::MIRROR_MODE_DISABLED));
185 librados::IoCtx &m_ioctx;
188 void ensure_features_disabled(librbd::ImageCtx *ictx,
189 uint64_t features_to_disable) {
192 ASSERT_EQ(0, librbd::get_features(ictx, &features));
193 features_to_disable &= features;
194 if (!features_to_disable) {
197 ASSERT_EQ(0, ictx->operations->update_features(features_to_disable, false));
198 ASSERT_EQ(0, librbd::get_features(ictx, &features));
199 ASSERT_EQ(0U, features & features_to_disable);
202 void expect_prepare_lock(MockOperationImageCtx &mock_image_ctx) {
203 EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
204 .WillOnce(Invoke([](Context *on_ready) {
205 on_ready->complete(0);
207 expect_op_work_queue(mock_image_ctx);
210 void expect_handle_prepare_lock_complete(MockOperationImageCtx &mock_image_ctx) {
211 EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
214 void expect_block_writes(MockOperationImageCtx &mock_image_ctx) {
215 EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_))
216 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
219 void expect_unblock_writes(MockOperationImageCtx &mock_image_ctx) {
220 EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes()).Times(1);
223 void expect_verify_lock_ownership(MockOperationImageCtx &mock_image_ctx) {
224 if (mock_image_ctx.exclusive_lock != nullptr) {
225 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
226 .WillRepeatedly(Return(true));
230 void expect_block_requests(MockOperationImageCtx &mock_image_ctx) {
231 if (mock_image_ctx.exclusive_lock != nullptr) {
232 EXPECT_CALL(*mock_image_ctx.exclusive_lock, block_requests(0)).Times(1);
236 void expect_unblock_requests(MockOperationImageCtx &mock_image_ctx) {
237 if (mock_image_ctx.exclusive_lock != nullptr) {
238 EXPECT_CALL(*mock_image_ctx.exclusive_lock, unblock_requests()).Times(1);
242 void expect_set_flags_request_send(
243 MockOperationImageCtx &mock_image_ctx,
244 MockSetFlagsRequest &mock_set_flags_request, int r) {
245 EXPECT_CALL(mock_set_flags_request, send())
246 .WillOnce(FinishRequest(&mock_set_flags_request, r,
250 void expect_create_journal_request_send(
251 MockOperationImageCtx &mock_image_ctx,
252 MockCreateJournalRequest &mock_create_journal_request, int r) {
253 EXPECT_CALL(mock_create_journal_request, send())
254 .WillOnce(FinishRequest(&mock_create_journal_request, r,
258 void expect_enable_mirror_request_send(
259 MockOperationImageCtx &mock_image_ctx,
260 MockEnableMirrorRequest &mock_enable_mirror_request, int r) {
261 EXPECT_CALL(mock_enable_mirror_request, send())
262 .WillOnce(FinishRequest(&mock_enable_mirror_request, r,
266 void expect_create_object_map_request_send(
267 MockOperationImageCtx &mock_image_ctx,
268 MockCreateObjectMapRequest &mock_create_object_map_request, int r) {
269 EXPECT_CALL(mock_create_object_map_request, send())
270 .WillOnce(FinishRequest(&mock_create_object_map_request, r,
274 void expect_notify_update(MockOperationImageCtx &mock_image_ctx) {
275 EXPECT_CALL(mock_image_ctx, notify_update(_))
276 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
281 TEST_F(TestMockOperationEnableFeaturesRequest, All) {
284 librbd::ImageCtx *ictx;
285 ASSERT_EQ(0, open_image(m_image_name, &ictx));
288 ASSERT_EQ(0, librbd::get_features(ictx, &features));
290 uint64_t features_to_enable = RBD_FEATURES_MUTABLE & features;
292 REQUIRE(features_to_enable);
294 ensure_features_disabled(ictx, features_to_enable);
296 MockOperationImageCtx mock_image_ctx(*ictx);
298 MockSetFlagsRequest mock_set_flags_request;
299 MockCreateJournalRequest mock_create_journal_request;
300 MockCreateObjectMapRequest mock_create_object_map_request;
302 ::testing::InSequence seq;
303 expect_prepare_lock(mock_image_ctx);
304 expect_block_writes(mock_image_ctx);
305 expect_block_requests(mock_image_ctx);
306 if (features_to_enable & RBD_FEATURE_JOURNALING) {
307 expect_create_journal_request_send(mock_image_ctx,
308 mock_create_journal_request, 0);
310 if (features_to_enable & (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF)) {
311 expect_set_flags_request_send(mock_image_ctx,
312 mock_set_flags_request, 0);
314 if (features_to_enable & RBD_FEATURE_OBJECT_MAP) {
315 expect_create_object_map_request_send(mock_image_ctx,
316 mock_create_object_map_request, 0);
318 expect_notify_update(mock_image_ctx);
319 expect_unblock_requests(mock_image_ctx);
320 expect_unblock_writes(mock_image_ctx);
321 expect_handle_prepare_lock_complete(mock_image_ctx);
323 C_SaferCond cond_ctx;
324 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
325 mock_image_ctx, &cond_ctx, 0, features_to_enable);
327 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
330 ASSERT_EQ(0, cond_ctx.wait());
333 TEST_F(TestMockOperationEnableFeaturesRequest, ObjectMap) {
334 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
336 librbd::ImageCtx *ictx;
337 ASSERT_EQ(0, open_image(m_image_name, &ictx));
340 ASSERT_EQ(0, librbd::get_features(ictx, &features));
342 ensure_features_disabled(
343 ictx, RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
345 MockOperationImageCtx mock_image_ctx(*ictx);
346 MockExclusiveLock mock_exclusive_lock;
347 MockJournal mock_journal;
348 MockObjectMap mock_object_map;
349 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
352 expect_verify_lock_ownership(mock_image_ctx);
354 MockSetFlagsRequest mock_set_flags_request;
355 MockCreateObjectMapRequest mock_create_object_map_request;
357 ::testing::InSequence seq;
358 expect_prepare_lock(mock_image_ctx);
359 expect_block_writes(mock_image_ctx);
360 if (mock_image_ctx.journal != nullptr) {
361 expect_is_journal_replaying(*mock_image_ctx.journal);
363 expect_block_requests(mock_image_ctx);
364 expect_append_op_event(mock_image_ctx, true, 0);
365 expect_set_flags_request_send(mock_image_ctx,
366 mock_set_flags_request, 0);
367 expect_create_object_map_request_send(mock_image_ctx,
368 mock_create_object_map_request, 0);
369 expect_notify_update(mock_image_ctx);
370 expect_unblock_requests(mock_image_ctx);
371 expect_unblock_writes(mock_image_ctx);
372 expect_handle_prepare_lock_complete(mock_image_ctx);
373 expect_commit_op_event(mock_image_ctx, 0);
375 C_SaferCond cond_ctx;
376 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
377 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_OBJECT_MAP);
379 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
382 ASSERT_EQ(0, cond_ctx.wait());
385 TEST_F(TestMockOperationEnableFeaturesRequest, ObjectMapError) {
386 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
388 librbd::ImageCtx *ictx;
389 ASSERT_EQ(0, open_image(m_image_name, &ictx));
392 ASSERT_EQ(0, librbd::get_features(ictx, &features));
394 ensure_features_disabled(
395 ictx, RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
397 MockOperationImageCtx mock_image_ctx(*ictx);
398 MockExclusiveLock mock_exclusive_lock;
399 MockJournal mock_journal;
400 MockObjectMap mock_object_map;
401 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
404 expect_verify_lock_ownership(mock_image_ctx);
406 MockSetFlagsRequest mock_set_flags_request;
407 MockCreateObjectMapRequest mock_create_object_map_request;
409 ::testing::InSequence seq;
410 expect_prepare_lock(mock_image_ctx);
411 expect_block_writes(mock_image_ctx);
412 if (mock_image_ctx.journal != nullptr) {
413 expect_is_journal_replaying(*mock_image_ctx.journal);
415 expect_block_requests(mock_image_ctx);
416 expect_append_op_event(mock_image_ctx, true, 0);
417 expect_set_flags_request_send(mock_image_ctx,
418 mock_set_flags_request, 0);
419 expect_create_object_map_request_send(
420 mock_image_ctx, mock_create_object_map_request, -EINVAL);
421 expect_unblock_requests(mock_image_ctx);
422 expect_unblock_writes(mock_image_ctx);
423 expect_handle_prepare_lock_complete(mock_image_ctx);
424 expect_commit_op_event(mock_image_ctx, -EINVAL);
426 C_SaferCond cond_ctx;
427 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
428 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_OBJECT_MAP);
430 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
433 ASSERT_EQ(-EINVAL, cond_ctx.wait());
436 TEST_F(TestMockOperationEnableFeaturesRequest, SetFlagsError) {
437 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
439 librbd::ImageCtx *ictx;
440 ASSERT_EQ(0, open_image(m_image_name, &ictx));
443 ASSERT_EQ(0, librbd::get_features(ictx, &features));
445 ensure_features_disabled(
446 ictx, RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
448 MockOperationImageCtx mock_image_ctx(*ictx);
449 MockExclusiveLock mock_exclusive_lock;
450 MockJournal mock_journal;
451 MockObjectMap mock_object_map;
452 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
455 expect_verify_lock_ownership(mock_image_ctx);
457 MockSetFlagsRequest mock_set_flags_request;
458 MockCreateObjectMapRequest mock_create_object_map_request;
460 ::testing::InSequence seq;
461 expect_prepare_lock(mock_image_ctx);
462 expect_block_writes(mock_image_ctx);
463 if (mock_image_ctx.journal != nullptr) {
464 expect_is_journal_replaying(*mock_image_ctx.journal);
466 expect_block_requests(mock_image_ctx);
467 expect_append_op_event(mock_image_ctx, true, 0);
468 expect_set_flags_request_send(mock_image_ctx,
469 mock_set_flags_request, -EINVAL);
470 expect_unblock_requests(mock_image_ctx);
471 expect_unblock_writes(mock_image_ctx);
472 expect_handle_prepare_lock_complete(mock_image_ctx);
473 expect_commit_op_event(mock_image_ctx, -EINVAL);
475 C_SaferCond cond_ctx;
476 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
477 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_OBJECT_MAP);
479 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
482 ASSERT_EQ(-EINVAL, cond_ctx.wait());
485 TEST_F(TestMockOperationEnableFeaturesRequest, Mirroring) {
486 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
488 librbd::ImageCtx *ictx;
489 ASSERT_EQ(0, open_image(m_image_name, &ictx));
492 ASSERT_EQ(0, librbd::get_features(ictx, &features));
494 ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING);
496 PoolMirrorModeEnabler enabler(m_ioctx);
498 MockOperationImageCtx mock_image_ctx(*ictx);
499 MockExclusiveLock mock_exclusive_lock;
500 MockJournal mock_journal;
501 MockObjectMap mock_object_map;
502 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
505 expect_verify_lock_ownership(mock_image_ctx);
507 MockCreateJournalRequest mock_create_journal_request;
508 MockEnableMirrorRequest mock_enable_mirror_request;
510 ::testing::InSequence seq;
511 expect_prepare_lock(mock_image_ctx);
512 expect_block_writes(mock_image_ctx);
513 expect_block_requests(mock_image_ctx);
514 expect_create_journal_request_send(mock_image_ctx,
515 mock_create_journal_request, 0);
516 expect_enable_mirror_request_send(mock_image_ctx,
517 mock_enable_mirror_request, 0);
518 expect_notify_update(mock_image_ctx);
519 expect_unblock_requests(mock_image_ctx);
520 expect_unblock_writes(mock_image_ctx);
521 expect_handle_prepare_lock_complete(mock_image_ctx);
523 C_SaferCond cond_ctx;
524 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
525 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING);
527 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
530 ASSERT_EQ(0, cond_ctx.wait());
533 TEST_F(TestMockOperationEnableFeaturesRequest, JournalingError) {
534 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
536 librbd::ImageCtx *ictx;
537 ASSERT_EQ(0, open_image(m_image_name, &ictx));
540 ASSERT_EQ(0, librbd::get_features(ictx, &features));
542 ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING);
544 PoolMirrorModeEnabler enabler(m_ioctx);
546 MockOperationImageCtx mock_image_ctx(*ictx);
547 MockExclusiveLock mock_exclusive_lock;
548 MockJournal mock_journal;
549 MockObjectMap mock_object_map;
550 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
553 expect_verify_lock_ownership(mock_image_ctx);
555 MockCreateJournalRequest mock_create_journal_request;
556 MockEnableMirrorRequest mock_enable_mirror_request;
558 ::testing::InSequence seq;
559 expect_prepare_lock(mock_image_ctx);
560 expect_block_writes(mock_image_ctx);
561 expect_block_requests(mock_image_ctx);
562 expect_create_journal_request_send(mock_image_ctx,
563 mock_create_journal_request, -EINVAL);
564 expect_unblock_requests(mock_image_ctx);
565 expect_unblock_writes(mock_image_ctx);
566 expect_handle_prepare_lock_complete(mock_image_ctx);
568 C_SaferCond cond_ctx;
569 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
570 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING);
572 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
575 ASSERT_EQ(-EINVAL, cond_ctx.wait());
578 TEST_F(TestMockOperationEnableFeaturesRequest, MirroringError) {
579 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
581 librbd::ImageCtx *ictx;
582 ASSERT_EQ(0, open_image(m_image_name, &ictx));
585 ASSERT_EQ(0, librbd::get_features(ictx, &features));
587 ensure_features_disabled(ictx, RBD_FEATURE_JOURNALING);
589 PoolMirrorModeEnabler enabler(m_ioctx);
591 MockOperationImageCtx mock_image_ctx(*ictx);
592 MockExclusiveLock mock_exclusive_lock;
593 MockJournal mock_journal;
594 MockObjectMap mock_object_map;
595 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
598 expect_verify_lock_ownership(mock_image_ctx);
600 MockCreateJournalRequest mock_create_journal_request;
601 MockEnableMirrorRequest mock_enable_mirror_request;
603 ::testing::InSequence seq;
604 expect_prepare_lock(mock_image_ctx);
605 expect_block_writes(mock_image_ctx);
606 expect_block_requests(mock_image_ctx);
607 expect_create_journal_request_send(mock_image_ctx,
608 mock_create_journal_request, 0);
609 expect_enable_mirror_request_send(mock_image_ctx,
610 mock_enable_mirror_request, -EINVAL);
611 expect_notify_update(mock_image_ctx);
612 expect_unblock_requests(mock_image_ctx);
613 expect_unblock_writes(mock_image_ctx);
614 expect_handle_prepare_lock_complete(mock_image_ctx);
616 C_SaferCond cond_ctx;
617 MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
618 mock_image_ctx, &cond_ctx, 0, RBD_FEATURE_JOURNALING);
620 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
623 ASSERT_EQ(0, cond_ctx.wait());
626 } // namespace operation
627 } // namespace librbd