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 "test/librbd/mock/MockJournal.h"
8 #include "test/librbd/mock/MockJournalPolicy.h"
9 #include "test/librbd/mock/MockObjectMap.h"
10 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
11 #include "test/librados_test_stub/MockTestMemRadosClient.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/internal.h"
14 #include "librbd/Operations.h"
15 #include "librbd/image/RefreshRequest.h"
16 #include "librbd/image/RefreshParentRequest.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include <arpa/inet.h>
21 #include <boost/scope_exit.hpp>
27 struct MockRefreshImageCtx
: public MockImageCtx
{
28 MockRefreshImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
32 } // anonymous namespace
37 struct RefreshParentRequest
<MockRefreshImageCtx
> {
38 static RefreshParentRequest
* s_instance
;
39 static RefreshParentRequest
* create(MockRefreshImageCtx
&mock_image_ctx
,
40 const ParentInfo
& parent_md
,
42 assert(s_instance
!= nullptr);
43 s_instance
->on_finish
= on_finish
;
46 static bool is_refresh_required(MockRefreshImageCtx
&mock_image_ctx
,
47 const ParentInfo
& parent_md
) {
48 assert(s_instance
!= nullptr);
49 return s_instance
->is_refresh_required();
52 Context
*on_finish
= nullptr;
54 RefreshParentRequest() {
58 MOCK_CONST_METHOD0(is_refresh_required
, bool());
59 MOCK_METHOD0(send
, void());
60 MOCK_METHOD0(apply
, void());
61 MOCK_METHOD1(finalize
, void(Context
*));
64 RefreshParentRequest
<MockRefreshImageCtx
>* RefreshParentRequest
<MockRefreshImageCtx
>::s_instance
= nullptr;
69 // template definitions
70 #include "librbd/image/RefreshRequest.cc"
71 template class librbd::image::RefreshRequest
<librbd::MockRefreshImageCtx
>;
73 ACTION_P(TestFeatures
, image_ctx
) {
74 return ((image_ctx
->features
& arg0
) != 0);
77 ACTION_P(ShutDownExclusiveLock
, image_ctx
) {
78 // shutting down exclusive lock will close object map and journal
79 image_ctx
->exclusive_lock
= nullptr;
80 image_ctx
->object_map
= nullptr;
81 image_ctx
->journal
= nullptr;
88 using ::testing::DoAll
;
89 using ::testing::DoDefault
;
90 using ::testing::InSequence
;
91 using ::testing::Return
;
92 using ::testing::WithArg
;
93 using ::testing::StrEq
;
95 class TestMockImageRefreshRequest
: public TestMockFixture
{
97 typedef RefreshRequest
<MockRefreshImageCtx
> MockRefreshRequest
;
98 typedef RefreshParentRequest
<MockRefreshImageCtx
> MockRefreshParentRequest
;
100 void expect_set_require_lock(MockRefreshImageCtx
&mock_image_ctx
,
101 librbd::io::Direction direction
, bool enabled
) {
102 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, set_require_lock(direction
,
106 void expect_v1_read_header(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
107 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
108 read(mock_image_ctx
.header_oid
, _
, _
, _
));
110 expect
.WillOnce(Return(r
));
112 expect
.WillOnce(DoDefault());
116 void expect_v1_get_snapshots(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
117 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
118 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("snap_list"), _
, _
, _
));
120 expect
.WillOnce(Return(r
));
122 expect
.WillOnce(DoDefault());
126 void expect_v1_get_locks(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
127 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
128 exec(mock_image_ctx
.header_oid
, _
, StrEq("lock"), StrEq("get_info"), _
, _
, _
));
130 expect
.WillOnce(Return(r
));
132 expect
.WillOnce(DoDefault());
136 void expect_get_mutable_metadata(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
137 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
138 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_size"), _
, _
, _
));
140 expect
.WillOnce(Return(r
));
142 expect
.WillOnce(DoDefault());
143 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
144 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_features"), _
, _
, _
))
145 .WillOnce(DoDefault());
146 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
147 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_snapcontext"), _
, _
, _
))
148 .WillOnce(DoDefault());
149 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
150 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_parent"), _
, _
, _
))
151 .WillOnce(DoDefault());
152 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
153 exec(mock_image_ctx
.header_oid
, _
, StrEq("lock"), StrEq("get_info"), _
, _
, _
))
154 .WillOnce(DoDefault());
158 void expect_get_flags(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
159 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
160 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_flags"), _
, _
, _
));
162 expect
.WillOnce(Return(r
));
164 expect
.WillOnce(DoDefault());
168 void expect_get_group(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
169 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
170 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
171 StrEq("image_get_group"), _
, _
, _
));
173 expect
.WillOnce(Return(r
));
175 expect
.WillOnce(DoDefault());
180 void expect_get_snapshots(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
181 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
182 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_snapshot_name"), _
, _
, _
));
184 expect
.WillOnce(Return(r
));
186 expect
.WillOnce(DoDefault());
187 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
188 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_size"), _
, _
, _
))
189 .WillOnce(DoDefault());
190 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
191 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_parent"), _
, _
, _
))
192 .WillOnce(DoDefault());
193 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
194 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_protection_status"), _
, _
, _
))
195 .WillOnce(DoDefault());
199 void expect_snap_timestamp_list(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
200 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
201 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_snapshot_timestamp"), _
, _
, _
));
203 expect
.WillOnce(Return(r
));
205 expect
.WillOnce(DoDefault());
209 void expect_snap_namespace_list(MockRefreshImageCtx
&mock_image_ctx
, int r
) {
210 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
211 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"), StrEq("get_snapshot_namespace"), _
, _
, _
));
213 expect
.WillOnce(Return(r
));
215 expect
.WillOnce(DoDefault());
219 void expect_add_snap(MockRefreshImageCtx
&mock_image_ctx
,
220 const std::string
&snap_name
, uint64_t snap_id
) {
221 EXPECT_CALL(mock_image_ctx
, add_snap(_
, snap_name
, snap_id
, _
, _
, _
, _
, _
));
224 void expect_init_exclusive_lock(MockRefreshImageCtx
&mock_image_ctx
,
225 MockExclusiveLock
&mock_exclusive_lock
,
227 EXPECT_CALL(mock_image_ctx
, create_exclusive_lock())
228 .WillOnce(Return(&mock_exclusive_lock
));
229 EXPECT_CALL(mock_exclusive_lock
, init(mock_image_ctx
.features
, _
))
230 .WillOnce(WithArg
<1>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
233 void expect_shut_down_exclusive_lock(MockRefreshImageCtx
&mock_image_ctx
,
234 MockExclusiveLock
&mock_exclusive_lock
,
236 EXPECT_CALL(mock_exclusive_lock
, shut_down(_
))
237 .WillOnce(DoAll(ShutDownExclusiveLock(&mock_image_ctx
),
238 CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
241 void expect_init_layout(MockRefreshImageCtx
&mock_image_ctx
) {
242 EXPECT_CALL(mock_image_ctx
, init_layout());
245 void expect_test_features(MockRefreshImageCtx
&mock_image_ctx
) {
246 EXPECT_CALL(mock_image_ctx
, test_features(_
, _
))
247 .WillRepeatedly(TestFeatures(&mock_image_ctx
));
250 void expect_refresh_parent_is_required(MockRefreshParentRequest
&mock_refresh_parent_request
,
252 EXPECT_CALL(mock_refresh_parent_request
, is_refresh_required())
253 .WillRepeatedly(Return(required
));
256 void expect_refresh_parent_send(MockRefreshImageCtx
&mock_image_ctx
,
257 MockRefreshParentRequest
&mock_refresh_parent_request
,
259 EXPECT_CALL(mock_refresh_parent_request
, send())
260 .WillOnce(FinishRequest(&mock_refresh_parent_request
, r
,
264 void expect_refresh_parent_apply(MockRefreshParentRequest
&mock_refresh_parent_request
) {
265 EXPECT_CALL(mock_refresh_parent_request
, apply());
268 void expect_refresh_parent_finalize(MockRefreshImageCtx
&mock_image_ctx
,
269 MockRefreshParentRequest
&mock_refresh_parent_request
,
271 EXPECT_CALL(mock_refresh_parent_request
, finalize(_
))
272 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
275 void expect_is_exclusive_lock_owner(MockExclusiveLock
&mock_exclusive_lock
,
277 EXPECT_CALL(mock_exclusive_lock
, is_lock_owner()).WillOnce(Return(is_owner
));
280 void expect_get_journal_policy(MockImageCtx
&mock_image_ctx
,
281 MockJournalPolicy
&mock_journal_policy
) {
282 EXPECT_CALL(mock_image_ctx
, get_journal_policy())
283 .WillOnce(Return(&mock_journal_policy
));
286 void expect_journal_disabled(MockJournalPolicy
&mock_journal_policy
,
288 EXPECT_CALL(mock_journal_policy
, journal_disabled())
289 .WillOnce(Return(disabled
));
292 void expect_open_journal(MockRefreshImageCtx
&mock_image_ctx
,
293 MockJournal
&mock_journal
, int r
) {
294 EXPECT_CALL(mock_image_ctx
, create_journal())
295 .WillOnce(Return(&mock_journal
));
296 EXPECT_CALL(mock_journal
, open(_
))
297 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
300 void expect_close_journal(MockRefreshImageCtx
&mock_image_ctx
,
301 MockJournal
&mock_journal
, int r
) {
302 EXPECT_CALL(mock_journal
, close(_
))
303 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
306 void expect_open_object_map(MockRefreshImageCtx
&mock_image_ctx
,
307 MockObjectMap
*mock_object_map
, int r
) {
308 EXPECT_CALL(mock_image_ctx
, create_object_map(_
))
309 .WillOnce(Return(mock_object_map
));
310 EXPECT_CALL(*mock_object_map
, open(_
))
311 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
314 void expect_close_object_map(MockRefreshImageCtx
&mock_image_ctx
,
315 MockObjectMap
&mock_object_map
, int r
) {
316 EXPECT_CALL(mock_object_map
, close(_
))
317 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
320 void expect_get_snap_id(MockRefreshImageCtx
&mock_image_ctx
,
321 const std::string
&snap_name
,
323 EXPECT_CALL(mock_image_ctx
,
324 get_snap_id(_
, snap_name
)).WillOnce(Return(snap_id
));
327 void expect_block_writes(MockImageCtx
&mock_image_ctx
, int r
) {
328 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, block_writes(_
))
329 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
332 void expect_unblock_writes(MockImageCtx
&mock_image_ctx
) {
333 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, unblock_writes())
339 TEST_F(TestMockImageRefreshRequest
, SuccessV1
) {
342 librbd::ImageCtx
*ictx
;
343 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
345 MockRefreshImageCtx
mock_image_ctx(*ictx
);
346 expect_op_work_queue(mock_image_ctx
);
347 expect_test_features(mock_image_ctx
);
350 expect_v1_read_header(mock_image_ctx
, 0);
351 expect_v1_get_snapshots(mock_image_ctx
, 0);
352 expect_v1_get_locks(mock_image_ctx
, 0);
353 expect_init_layout(mock_image_ctx
);
356 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
359 ASSERT_EQ(0, ctx
.wait());
362 TEST_F(TestMockImageRefreshRequest
, SuccessSnapshotV1
) {
364 librbd::ImageCtx
*ictx
;
365 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
366 ASSERT_EQ(0, snap_create(*ictx
, "snap"));
367 ASSERT_EQ(0, ictx
->state
->refresh());
369 MockRefreshImageCtx
mock_image_ctx(*ictx
);
370 expect_op_work_queue(mock_image_ctx
);
371 expect_test_features(mock_image_ctx
);
374 expect_v1_read_header(mock_image_ctx
, 0);
375 expect_v1_get_snapshots(mock_image_ctx
, 0);
376 expect_v1_get_locks(mock_image_ctx
, 0);
377 expect_init_layout(mock_image_ctx
);
378 expect_add_snap(mock_image_ctx
, "snap", ictx
->snap_ids
.begin()->second
);
381 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
384 ASSERT_EQ(0, ctx
.wait());
387 TEST_F(TestMockImageRefreshRequest
, SuccessV2
) {
390 librbd::ImageCtx
*ictx
;
391 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
393 MockRefreshImageCtx
mock_image_ctx(*ictx
);
394 MockRefreshParentRequest mock_refresh_parent_request
;
395 MockExclusiveLock mock_exclusive_lock
;
396 expect_op_work_queue(mock_image_ctx
);
397 expect_test_features(mock_image_ctx
);
400 expect_get_mutable_metadata(mock_image_ctx
, 0);
401 expect_get_flags(mock_image_ctx
, 0);
402 expect_get_group(mock_image_ctx
, 0);
403 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
404 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
405 expect_init_exclusive_lock(mock_image_ctx
, mock_exclusive_lock
, 0);
409 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
412 ASSERT_EQ(0, ctx
.wait());
415 TEST_F(TestMockImageRefreshRequest
, SuccessSnapshotV2
) {
418 librbd::ImageCtx
*ictx
;
419 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
420 ASSERT_EQ(0, snap_create(*ictx
, "snap"));
422 MockRefreshImageCtx
mock_image_ctx(*ictx
);
423 MockRefreshParentRequest mock_refresh_parent_request
;
424 MockExclusiveLock mock_exclusive_lock
;
425 expect_op_work_queue(mock_image_ctx
);
426 expect_test_features(mock_image_ctx
);
429 expect_get_mutable_metadata(mock_image_ctx
, 0);
430 expect_get_flags(mock_image_ctx
, 0);
431 expect_get_flags(mock_image_ctx
, 0);
432 expect_get_group(mock_image_ctx
, 0);
433 expect_get_snapshots(mock_image_ctx
, 0);
434 expect_snap_timestamp_list(mock_image_ctx
, 0);
435 expect_snap_namespace_list(mock_image_ctx
, 0);
436 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
437 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
438 expect_init_exclusive_lock(mock_image_ctx
, mock_exclusive_lock
, 0);
440 expect_add_snap(mock_image_ctx
, "snap", ictx
->snap_ids
.begin()->second
);
443 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
446 ASSERT_EQ(0, ctx
.wait());
449 TEST_F(TestMockImageRefreshRequest
, SuccessSetSnapshotV2
) {
452 librbd::ImageCtx
*ictx
;
453 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
454 ASSERT_EQ(0, snap_create(*ictx
, "snap"));
455 ASSERT_EQ(0, librbd::snap_set(ictx
, cls::rbd::UserSnapshotNamespace(), "snap"));
457 MockRefreshImageCtx
mock_image_ctx(*ictx
);
458 MockRefreshParentRequest mock_refresh_parent_request
;
459 MockObjectMap mock_object_map
;
460 expect_op_work_queue(mock_image_ctx
);
461 expect_test_features(mock_image_ctx
);
464 expect_get_mutable_metadata(mock_image_ctx
, 0);
465 expect_get_flags(mock_image_ctx
, 0);
466 expect_get_flags(mock_image_ctx
, 0);
467 expect_get_group(mock_image_ctx
, 0);
468 expect_get_snapshots(mock_image_ctx
, 0);
469 expect_snap_timestamp_list(mock_image_ctx
, 0);
470 expect_snap_namespace_list(mock_image_ctx
, 0);
471 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
472 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
473 expect_open_object_map(mock_image_ctx
, &mock_object_map
, 0);
475 expect_add_snap(mock_image_ctx
, "snap", ictx
->snap_ids
.begin()->second
);
476 expect_get_snap_id(mock_image_ctx
, "snap", ictx
->snap_ids
.begin()->second
);
479 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
482 ASSERT_EQ(0, ctx
.wait());
485 TEST_F(TestMockImageRefreshRequest
, SuccessChild
) {
486 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
488 librbd::ImageCtx
*ictx
;
489 librbd::ImageCtx
*ictx2
= nullptr;
490 std::string clone_name
= get_temp_image_name();
492 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
493 ASSERT_EQ(0, snap_create(*ictx
, "snap"));
494 ASSERT_EQ(0, snap_protect(*ictx
, "snap"));
495 BOOST_SCOPE_EXIT_ALL((&)) {
496 if (ictx2
!= nullptr) {
500 librbd::NoOpProgressContext no_op
;
501 ASSERT_EQ(0, librbd::remove(m_ioctx
, clone_name
, "", no_op
));
502 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(), "snap"));
505 int order
= ictx
->order
;
506 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap", m_ioctx
,
507 clone_name
.c_str(), ictx
->features
, &order
, 0, 0));
509 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
511 MockRefreshImageCtx
mock_image_ctx(*ictx2
);
512 MockRefreshParentRequest
*mock_refresh_parent_request
= new MockRefreshParentRequest();
513 MockExclusiveLock mock_exclusive_lock
;
514 expect_op_work_queue(mock_image_ctx
);
515 expect_test_features(mock_image_ctx
);
518 expect_get_mutable_metadata(mock_image_ctx
, 0);
519 expect_get_flags(mock_image_ctx
, 0);
520 expect_get_group(mock_image_ctx
, 0);
521 expect_refresh_parent_is_required(*mock_refresh_parent_request
, true);
522 expect_refresh_parent_send(mock_image_ctx
, *mock_refresh_parent_request
, 0);
523 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
524 expect_init_exclusive_lock(mock_image_ctx
, mock_exclusive_lock
, 0);
526 expect_refresh_parent_apply(*mock_refresh_parent_request
);
527 expect_refresh_parent_finalize(mock_image_ctx
, *mock_refresh_parent_request
, 0);
530 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
533 ASSERT_EQ(0, ctx
.wait());
536 TEST_F(TestMockImageRefreshRequest
, SuccessChildDontOpenParent
) {
537 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
539 librbd::ImageCtx
*ictx
;
540 librbd::ImageCtx
*ictx2
= nullptr;
541 std::string clone_name
= get_temp_image_name();
543 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
544 ASSERT_EQ(0, snap_create(*ictx
, "snap"));
545 ASSERT_EQ(0, snap_protect(*ictx
, "snap"));
546 BOOST_SCOPE_EXIT_ALL((&)) {
547 if (ictx2
!= nullptr) {
551 librbd::NoOpProgressContext no_op
;
552 ASSERT_EQ(0, librbd::remove(m_ioctx
, clone_name
, "", no_op
));
553 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(), "snap"));
556 int order
= ictx
->order
;
557 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap", m_ioctx
,
558 clone_name
.c_str(), ictx
->features
, &order
, 0, 0));
560 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
562 MockRefreshImageCtx
mock_image_ctx(*ictx2
);
563 MockExclusiveLock mock_exclusive_lock
;
564 expect_op_work_queue(mock_image_ctx
);
565 expect_test_features(mock_image_ctx
);
568 expect_get_mutable_metadata(mock_image_ctx
, 0);
569 expect_get_flags(mock_image_ctx
, 0);
570 expect_get_group(mock_image_ctx
, 0);
571 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
572 expect_init_exclusive_lock(mock_image_ctx
, mock_exclusive_lock
, 0);
576 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, true, &ctx
);
579 ASSERT_EQ(0, ctx
.wait());
582 TEST_F(TestMockImageRefreshRequest
, DisableExclusiveLock
) {
583 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
585 librbd::ImageCtx
*ictx
;
586 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
588 MockRefreshImageCtx
mock_image_ctx(*ictx
);
589 MockRefreshParentRequest mock_refresh_parent_request
;
591 MockExclusiveLock
*mock_exclusive_lock
= new MockExclusiveLock();
592 mock_image_ctx
.exclusive_lock
= mock_exclusive_lock
;
594 MockObjectMap mock_object_map
;
595 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
596 mock_image_ctx
.object_map
= &mock_object_map
;
599 MockJournal mock_journal
;
600 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
601 mock_image_ctx
.journal
= &mock_journal
;
604 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
605 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
609 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
610 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
614 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
615 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
619 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
620 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_EXCLUSIVE_LOCK
,
624 expect_op_work_queue(mock_image_ctx
);
625 expect_test_features(mock_image_ctx
);
627 // verify that exclusive lock is properly handled when object map
628 // and journaling were never enabled (or active)
630 expect_get_mutable_metadata(mock_image_ctx
, 0);
631 expect_get_flags(mock_image_ctx
, 0);
632 expect_get_group(mock_image_ctx
, 0);
633 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
634 expect_shut_down_exclusive_lock(mock_image_ctx
, *mock_exclusive_lock
, 0);
637 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
640 ASSERT_EQ(0, ctx
.wait());
643 TEST_F(TestMockImageRefreshRequest
, DisableExclusiveLockWhileAcquiringLock
) {
644 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
646 librbd::ImageCtx
*ictx
;
647 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
649 MockRefreshImageCtx
mock_image_ctx(*ictx
);
650 MockRefreshParentRequest mock_refresh_parent_request
;
652 MockExclusiveLock mock_exclusive_lock
;
653 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
655 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
656 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
660 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
661 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
665 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
666 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
670 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
671 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_EXCLUSIVE_LOCK
,
675 expect_op_work_queue(mock_image_ctx
);
676 expect_test_features(mock_image_ctx
);
678 // verify that exclusive lock is properly handled when object map
679 // and journaling were never enabled (or active)
681 expect_get_mutable_metadata(mock_image_ctx
, 0);
682 expect_get_flags(mock_image_ctx
, 0);
683 expect_get_group(mock_image_ctx
, 0);
684 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
687 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, true, false, &ctx
);
690 ASSERT_EQ(-ERESTART
, ctx
.wait());
693 TEST_F(TestMockImageRefreshRequest
, JournalDisabledByPolicy
) {
694 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
696 librbd::ImageCtx
*ictx
;
697 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
699 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
700 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
704 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
705 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
709 MockRefreshImageCtx
mock_image_ctx(*ictx
);
710 MockRefreshParentRequest mock_refresh_parent_request
;
712 MockExclusiveLock mock_exclusive_lock
;
713 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
715 MockJournal mock_journal
;
717 expect_op_work_queue(mock_image_ctx
);
718 expect_test_features(mock_image_ctx
);
719 expect_is_exclusive_lock_owner(mock_exclusive_lock
, true);
722 expect_get_mutable_metadata(mock_image_ctx
, 0);
723 expect_get_flags(mock_image_ctx
, 0);
724 expect_get_group(mock_image_ctx
, 0);
725 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
727 MockJournalPolicy mock_journal_policy
;
728 expect_get_journal_policy(mock_image_ctx
, mock_journal_policy
);
729 expect_journal_disabled(mock_journal_policy
, true);
732 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
735 ASSERT_EQ(0, ctx
.wait());
738 TEST_F(TestMockImageRefreshRequest
, EnableJournalWithExclusiveLock
) {
739 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
741 librbd::ImageCtx
*ictx
;
742 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
744 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
745 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
749 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
750 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
754 MockRefreshImageCtx
mock_image_ctx(*ictx
);
755 MockRefreshParentRequest mock_refresh_parent_request
;
757 MockExclusiveLock mock_exclusive_lock
;
758 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
760 MockJournal mock_journal
;
762 expect_op_work_queue(mock_image_ctx
);
763 expect_test_features(mock_image_ctx
);
764 expect_is_exclusive_lock_owner(mock_exclusive_lock
, true);
766 // journal should be immediately opened if exclusive lock owned
768 expect_get_mutable_metadata(mock_image_ctx
, 0);
769 expect_get_flags(mock_image_ctx
, 0);
770 expect_get_group(mock_image_ctx
, 0);
771 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
773 MockJournalPolicy mock_journal_policy
;
774 expect_get_journal_policy(mock_image_ctx
, mock_journal_policy
);
775 expect_journal_disabled(mock_journal_policy
, false);
776 expect_open_journal(mock_image_ctx
, mock_journal
, 0);
779 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
782 ASSERT_EQ(0, ctx
.wait());
785 TEST_F(TestMockImageRefreshRequest
, EnableJournalWithoutExclusiveLock
) {
786 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
788 librbd::ImageCtx
*ictx
;
789 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
791 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
792 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
796 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
797 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
801 MockRefreshImageCtx
mock_image_ctx(*ictx
);
802 MockRefreshParentRequest mock_refresh_parent_request
;
804 MockExclusiveLock mock_exclusive_lock
;
805 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
807 expect_op_work_queue(mock_image_ctx
);
808 expect_test_features(mock_image_ctx
);
809 expect_is_exclusive_lock_owner(mock_exclusive_lock
, false);
811 // do not open the journal if exclusive lock is not owned
813 expect_get_mutable_metadata(mock_image_ctx
, 0);
814 expect_get_flags(mock_image_ctx
, 0);
815 expect_get_group(mock_image_ctx
, 0);
816 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
817 expect_set_require_lock(mock_image_ctx
, librbd::io::DIRECTION_BOTH
, true);
820 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
823 ASSERT_EQ(0, ctx
.wait());
826 TEST_F(TestMockImageRefreshRequest
, DisableJournal
) {
827 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
829 librbd::ImageCtx
*ictx
;
830 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
832 MockRefreshImageCtx
mock_image_ctx(*ictx
);
833 MockRefreshParentRequest mock_refresh_parent_request
;
835 MockExclusiveLock mock_exclusive_lock
;
836 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
838 MockObjectMap mock_object_map
;
839 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
840 mock_image_ctx
.object_map
= &mock_object_map
;
843 MockJournal
*mock_journal
= new MockJournal();
844 mock_image_ctx
.journal
= mock_journal
;
846 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
847 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
851 expect_op_work_queue(mock_image_ctx
);
852 expect_test_features(mock_image_ctx
);
854 // verify journal is closed if feature disabled
856 expect_get_mutable_metadata(mock_image_ctx
, 0);
857 expect_get_flags(mock_image_ctx
, 0);
858 expect_get_group(mock_image_ctx
, 0);
859 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
860 expect_block_writes(mock_image_ctx
, 0);
861 if (!mock_image_ctx
.clone_copy_on_read
) {
862 expect_set_require_lock(mock_image_ctx
, librbd::io::DIRECTION_READ
, false);
864 expect_close_journal(mock_image_ctx
, *mock_journal
, 0);
865 expect_unblock_writes(mock_image_ctx
);
868 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
871 ASSERT_EQ(0, ctx
.wait());
874 TEST_F(TestMockImageRefreshRequest
, EnableObjectMapWithExclusiveLock
) {
875 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
877 librbd::ImageCtx
*ictx
;
878 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
880 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
881 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
885 MockRefreshImageCtx
mock_image_ctx(*ictx
);
886 MockRefreshParentRequest mock_refresh_parent_request
;
888 MockExclusiveLock mock_exclusive_lock
;
889 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
891 MockObjectMap mock_object_map
;
893 expect_op_work_queue(mock_image_ctx
);
894 expect_test_features(mock_image_ctx
);
895 expect_is_exclusive_lock_owner(mock_exclusive_lock
, true);
897 // object map should be immediately opened if exclusive lock owned
899 expect_get_mutable_metadata(mock_image_ctx
, 0);
900 expect_get_flags(mock_image_ctx
, 0);
901 expect_get_group(mock_image_ctx
, 0);
902 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
903 expect_open_object_map(mock_image_ctx
, &mock_object_map
, 0);
906 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
909 ASSERT_EQ(0, ctx
.wait());
912 TEST_F(TestMockImageRefreshRequest
, EnableObjectMapWithoutExclusiveLock
) {
913 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
915 librbd::ImageCtx
*ictx
;
916 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
918 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
919 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
923 MockRefreshImageCtx
mock_image_ctx(*ictx
);
924 MockRefreshParentRequest mock_refresh_parent_request
;
926 MockExclusiveLock mock_exclusive_lock
;
927 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
929 expect_op_work_queue(mock_image_ctx
);
930 expect_test_features(mock_image_ctx
);
931 expect_is_exclusive_lock_owner(mock_exclusive_lock
, false);
933 // do not open the object map if exclusive lock is not owned
935 expect_get_mutable_metadata(mock_image_ctx
, 0);
936 expect_get_flags(mock_image_ctx
, 0);
937 expect_get_group(mock_image_ctx
, 0);
938 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
941 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
944 ASSERT_EQ(0, ctx
.wait());
947 TEST_F(TestMockImageRefreshRequest
, DisableObjectMap
) {
948 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
950 librbd::ImageCtx
*ictx
;
951 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
953 MockRefreshImageCtx
mock_image_ctx(*ictx
);
954 MockRefreshParentRequest mock_refresh_parent_request
;
956 MockExclusiveLock mock_exclusive_lock
;
957 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
959 MockObjectMap
*mock_object_map
= new MockObjectMap();
960 mock_image_ctx
.object_map
= mock_object_map
;
962 MockJournal mock_journal
;
963 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
964 mock_image_ctx
.journal
= &mock_journal
;
967 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
968 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_FAST_DIFF
,
972 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
973 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_OBJECT_MAP
,
977 expect_op_work_queue(mock_image_ctx
);
978 expect_test_features(mock_image_ctx
);
980 // verify object map is closed if feature disabled
982 expect_get_mutable_metadata(mock_image_ctx
, 0);
983 expect_get_flags(mock_image_ctx
, 0);
984 expect_get_group(mock_image_ctx
, 0);
985 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
986 expect_close_object_map(mock_image_ctx
, *mock_object_map
, 0);
989 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
992 ASSERT_EQ(0, ctx
.wait());
995 TEST_F(TestMockImageRefreshRequest
, OpenObjectMapError
) {
996 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
998 librbd::ImageCtx
*ictx
;
999 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1001 if (ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
1002 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
1006 MockRefreshImageCtx
mock_image_ctx(*ictx
);
1007 MockRefreshParentRequest mock_refresh_parent_request
;
1009 MockExclusiveLock mock_exclusive_lock
;
1010 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1012 MockObjectMap
*mock_object_map
= new MockObjectMap();
1014 expect_op_work_queue(mock_image_ctx
);
1015 expect_test_features(mock_image_ctx
);
1016 expect_is_exclusive_lock_owner(mock_exclusive_lock
, true);
1018 // object map should be immediately opened if exclusive lock owned
1020 expect_get_mutable_metadata(mock_image_ctx
, 0);
1021 expect_get_flags(mock_image_ctx
, 0);
1022 expect_get_group(mock_image_ctx
, 0);
1023 expect_refresh_parent_is_required(mock_refresh_parent_request
, false);
1024 expect_open_object_map(mock_image_ctx
, mock_object_map
, -EFBIG
);
1027 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, false, false, &ctx
);
1030 ASSERT_EQ(0, ctx
.wait());
1031 ASSERT_EQ(nullptr, mock_image_ctx
.object_map
);
1034 } // namespace image
1035 } // namespace librbd