1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/stringify.h"
5 #include "test/librbd/test_mock_fixture.h"
6 #include "test/librbd/test_support.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockOperations.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "librbd/image/ListWatchersRequest.h"
12 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
13 #include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
14 #include "librbd/mirror/snapshot/PromoteRequest.h"
15 #include "librbd/mirror/snapshot/Utils.h"
21 struct MockTestImageCtx
: public MockImageCtx
{
22 explicit MockTestImageCtx(librbd::ImageCtx
& image_ctx
) : MockImageCtx(image_ctx
) {
26 } // anonymous namespace
31 struct ListWatchersRequest
<MockTestImageCtx
> {
32 std::list
<obj_watch_t
> *watchers
;
33 Context
* on_finish
= nullptr;
34 static ListWatchersRequest
* s_instance
;
35 static ListWatchersRequest
*create(MockTestImageCtx
&image_ctx
, int flags
,
36 std::list
<obj_watch_t
> *watchers
,
38 ceph_assert(s_instance
!= nullptr);
39 s_instance
->watchers
= watchers
;
40 s_instance
->on_finish
= on_finish
;
44 MOCK_METHOD0(send
, void());
46 ListWatchersRequest() {
51 ListWatchersRequest
<MockTestImageCtx
>* ListWatchersRequest
<MockTestImageCtx
>::s_instance
= nullptr;
62 static Mock
* s_instance
;
68 MOCK_METHOD5(can_create_primary_snapshot
,
69 bool(librbd::MockTestImageCtx
*, bool, bool, bool*, uint64_t *));
72 Mock
*Mock::s_instance
= nullptr;
74 } // anonymous namespace
76 template<> bool can_create_primary_snapshot(librbd::MockTestImageCtx
*image_ctx
,
77 bool demoted
, bool force
,
78 bool* requires_orphan
,
79 uint64_t *rollback_snap_id
) {
80 return Mock::s_instance
->can_create_primary_snapshot(image_ctx
, demoted
,
81 force
, requires_orphan
,
88 struct CreateNonPrimaryRequest
<MockTestImageCtx
> {
89 std::string primary_mirror_uuid
;
90 uint64_t primary_snap_id
= CEPH_NOSNAP
;
91 Context
* on_finish
= nullptr;
92 static CreateNonPrimaryRequest
* s_instance
;
93 static CreateNonPrimaryRequest
*create(MockTestImageCtx
*image_ctx
,
95 const std::string
&primary_mirror_uuid
,
96 uint64_t primary_snap_id
,
98 const ImageState
&image_state
,
100 Context
*on_finish
) {
101 ceph_assert(s_instance
!= nullptr);
102 s_instance
->primary_mirror_uuid
= primary_mirror_uuid
;
103 s_instance
->primary_snap_id
= primary_snap_id
;
104 s_instance
->on_finish
= on_finish
;
108 MOCK_METHOD0(send
, void());
110 CreateNonPrimaryRequest() {
115 CreateNonPrimaryRequest
<MockTestImageCtx
>* CreateNonPrimaryRequest
<MockTestImageCtx
>::s_instance
= nullptr;
118 struct CreatePrimaryRequest
<MockTestImageCtx
> {
119 bool demoted
= false;
121 Context
* on_finish
= nullptr;
122 static CreatePrimaryRequest
* s_instance
;
123 static CreatePrimaryRequest
*create(MockTestImageCtx
*image_ctx
,
124 const std::string
& global_image_id
,
125 uint64_t clean_since_snap_id
,
126 uint32_t flags
, uint64_t *snap_id
,
127 Context
*on_finish
) {
128 ceph_assert(s_instance
!= nullptr);
129 s_instance
->demoted
= ((flags
& CREATE_PRIMARY_FLAG_DEMOTED
) != 0);
130 s_instance
->force
= ((flags
& CREATE_PRIMARY_FLAG_FORCE
) != 0);
131 s_instance
->on_finish
= on_finish
;
135 MOCK_METHOD0(send
, void());
137 CreatePrimaryRequest() {
142 CreatePrimaryRequest
<MockTestImageCtx
>* CreatePrimaryRequest
<MockTestImageCtx
>::s_instance
= nullptr;
144 } // namespace snapshot
145 } // namespace mirror
146 } // namespace librbd
148 // template definitions
149 #include "librbd/mirror/snapshot/PromoteRequest.cc"
150 template class librbd::mirror::snapshot::PromoteRequest
<librbd::MockTestImageCtx
>;
157 using ::testing::DoAll
;
158 using ::testing::InSequence
;
159 using ::testing::Invoke
;
160 using ::testing::Return
;
161 using ::testing::StrEq
;
162 using ::testing::WithArg
;
163 using ::testing::WithArgs
;
165 class TestMockMirrorSnapshotPromoteRequest
: public TestMockFixture
{
167 typedef librbd::image::ListWatchersRequest
<MockTestImageCtx
> MockListWatchersRequest
;
168 typedef PromoteRequest
<MockTestImageCtx
> MockPromoteRequest
;
169 typedef CreateNonPrimaryRequest
<MockTestImageCtx
> MockCreateNonPrimaryRequest
;
170 typedef CreatePrimaryRequest
<MockTestImageCtx
> MockCreatePrimaryRequest
;
171 typedef util::Mock MockUtils
;
173 void expect_can_create_primary_snapshot(MockUtils
&mock_utils
, bool force
,
174 bool requires_orphan
,
175 uint64_t rollback_snap_id
,
177 EXPECT_CALL(mock_utils
,
178 can_create_primary_snapshot(_
, false, force
, _
, _
))
180 WithArgs
<3,4 >(Invoke(
181 [requires_orphan
, rollback_snap_id
]
182 (bool* orphan
, uint64_t *snap_id
) {
183 *orphan
= requires_orphan
;
184 *snap_id
= rollback_snap_id
;
189 void expect_create_orphan_snapshot(
190 MockTestImageCtx
&mock_image_ctx
,
191 MockCreateNonPrimaryRequest
&mock_create_non_primary_request
, int r
) {
192 EXPECT_CALL(mock_create_non_primary_request
, send())
194 Invoke([&mock_image_ctx
, &mock_create_non_primary_request
, r
]() {
195 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
196 mock_create_non_primary_request
.on_finish
, r
);
200 void expect_list_watchers(
201 MockTestImageCtx
&mock_image_ctx
,
202 MockListWatchersRequest
&mock_list_watchers_request
,
203 const std::list
<obj_watch_t
> &watchers
, int r
) {
204 EXPECT_CALL(mock_list_watchers_request
, send())
206 Invoke([&mock_image_ctx
, &mock_list_watchers_request
, watchers
, r
]() {
207 *mock_list_watchers_request
.watchers
= watchers
;
208 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
209 mock_list_watchers_request
.on_finish
, r
);
213 void expect_acquire_lock(MockTestImageCtx
&mock_image_ctx
, int r
) {
214 if (mock_image_ctx
.exclusive_lock
== nullptr) {
217 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, is_lock_owner())
218 .WillOnce(Return(false));
219 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, block_requests(_
));
220 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, acquire_lock(_
))
221 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
223 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, is_lock_owner())
224 .WillOnce(Return(true));
228 void expect_get_snap_info(MockTestImageCtx
&mock_image_ctx
,
229 uint64_t snap_id
, const SnapInfo
* snap_info
) {
230 EXPECT_CALL(mock_image_ctx
, get_snap_info(snap_id
))
231 .WillOnce(Return(snap_info
));
234 void expect_rollback(MockTestImageCtx
&mock_image_ctx
, uint64_t snap_id
,
235 const SnapInfo
* snap_info
, int r
) {
236 expect_get_snap_info(mock_image_ctx
, snap_id
, snap_info
);
237 EXPECT_CALL(*mock_image_ctx
.operations
,
238 execute_snap_rollback(snap_info
->snap_namespace
,
239 snap_info
->name
, _
, _
))
240 .WillOnce(WithArg
<3>(CompleteContext(
241 r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
244 void expect_create_promote_snapshot(
245 MockTestImageCtx
&mock_image_ctx
,
246 MockCreatePrimaryRequest
&mock_create_primary_request
, int r
) {
247 EXPECT_CALL(mock_create_primary_request
, send())
249 Invoke([&mock_image_ctx
, &mock_create_primary_request
, r
]() {
250 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
251 mock_create_primary_request
.on_finish
, r
);
255 void expect_release_lock(MockTestImageCtx
&mock_image_ctx
, int r
) {
256 if (mock_image_ctx
.exclusive_lock
== nullptr) {
259 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, unblock_requests());
260 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, release_lock(_
))
261 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
265 TEST_F(TestMockMirrorSnapshotPromoteRequest
, Success
) {
268 librbd::ImageCtx
*ictx
;
269 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
271 MockTestImageCtx
mock_image_ctx(*ictx
);
275 MockUtils mock_utils
;
276 expect_can_create_primary_snapshot(mock_utils
, true, false, CEPH_NOSNAP
,
278 MockCreatePrimaryRequest mock_create_primary_request
;
279 expect_create_promote_snapshot(mock_image_ctx
, mock_create_primary_request
,
282 auto req
= new MockPromoteRequest(&mock_image_ctx
, "gid", &ctx
);
284 ASSERT_EQ(0, ctx
.wait());
287 TEST_F(TestMockMirrorSnapshotPromoteRequest
, SuccessForce
) {
290 librbd::ImageCtx
*ictx
;
291 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
293 MockTestImageCtx
mock_image_ctx(*ictx
);
294 expect_op_work_queue(mock_image_ctx
);
296 MockExclusiveLock mock_exclusive_lock
;
297 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
298 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
303 MockUtils mock_utils
;
304 expect_can_create_primary_snapshot(mock_utils
, true, true, CEPH_NOSNAP
, true);
305 MockCreateNonPrimaryRequest mock_create_non_primary_request
;
306 expect_create_orphan_snapshot(mock_image_ctx
, mock_create_non_primary_request
,
308 MockListWatchersRequest mock_list_watchers_request
;
309 expect_list_watchers(mock_image_ctx
, mock_list_watchers_request
, {}, 0);
310 expect_acquire_lock(mock_image_ctx
, 0);
312 SnapInfo snap_info
= {"snap", cls::rbd::MirrorSnapshotNamespace
{}, 0,
314 MockCreatePrimaryRequest mock_create_primary_request
;
315 expect_create_promote_snapshot(mock_image_ctx
, mock_create_primary_request
,
317 expect_release_lock(mock_image_ctx
, 0);
320 auto req
= new MockPromoteRequest(&mock_image_ctx
, "gid", &ctx
);
322 ASSERT_EQ(0, ctx
.wait());
325 TEST_F(TestMockMirrorSnapshotPromoteRequest
, SuccessRollback
) {
328 librbd::ImageCtx
*ictx
;
329 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
331 MockTestImageCtx
mock_image_ctx(*ictx
);
332 expect_op_work_queue(mock_image_ctx
);
334 MockExclusiveLock mock_exclusive_lock
;
335 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
336 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
341 MockUtils mock_utils
;
342 expect_can_create_primary_snapshot(mock_utils
, true, false, 123, true);
343 MockCreateNonPrimaryRequest mock_create_non_primary_request
;
344 expect_create_orphan_snapshot(mock_image_ctx
, mock_create_non_primary_request
,
346 MockListWatchersRequest mock_list_watchers_request
;
347 expect_list_watchers(mock_image_ctx
, mock_list_watchers_request
, {}, 0);
348 expect_acquire_lock(mock_image_ctx
, 0);
350 SnapInfo snap_info
= {"snap", cls::rbd::MirrorSnapshotNamespace
{}, 0,
352 expect_rollback(mock_image_ctx
, 123, &snap_info
, 0);
353 MockCreatePrimaryRequest mock_create_primary_request
;
354 expect_create_promote_snapshot(mock_image_ctx
, mock_create_primary_request
,
356 expect_release_lock(mock_image_ctx
, 0);
359 auto req
= new MockPromoteRequest(&mock_image_ctx
, "gid", &ctx
);
361 ASSERT_EQ(0, ctx
.wait());
364 TEST_F(TestMockMirrorSnapshotPromoteRequest
, ErrorCannotRollback
) {
367 librbd::ImageCtx
*ictx
;
368 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
370 MockTestImageCtx
mock_image_ctx(*ictx
);
371 expect_op_work_queue(mock_image_ctx
);
375 MockUtils mock_utils
;
376 expect_can_create_primary_snapshot(mock_utils
, true, false, CEPH_NOSNAP
,
380 auto req
= new MockPromoteRequest(&mock_image_ctx
, "gid", &ctx
);
382 ASSERT_EQ(-EINVAL
, ctx
.wait());
385 } // namespace snapshot
386 } // namespace mirror
387 } // namespace librbd