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/io/MockObjectDispatch.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "include/stringify.h"
10 #include "common/bit_vector.hpp"
11 #include "librbd/ImageState.h"
12 #include "librbd/internal.h"
13 #include "librbd/operation/SnapshotRollbackRequest.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
21 struct MockOperationImageCtx
: public MockImageCtx
{
22 MockOperationImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
26 } // anonymous namespace
31 struct ResizeRequest
<MockOperationImageCtx
> {
32 static ResizeRequest
*s_instance
;
33 Context
*on_finish
= nullptr;
35 static ResizeRequest
* create(MockOperationImageCtx
&image_ctx
, Context
*on_finish
,
36 uint64_t new_size
, bool allow_shrink
,
37 ProgressContext
&prog_ctx
, uint64_t journal_op_tid
,
38 bool disable_journal
) {
39 ceph_assert(s_instance
!= nullptr);
40 ceph_assert(journal_op_tid
== 0);
41 ceph_assert(disable_journal
);
42 s_instance
->on_finish
= on_finish
;
50 MOCK_METHOD0(send
, void());
53 ResizeRequest
<MockOperationImageCtx
> *ResizeRequest
<MockOperationImageCtx
>::s_instance
= nullptr;
55 } // namespace operation
58 struct AsyncRequest
<MockOperationImageCtx
> : public AsyncRequest
<MockImageCtx
> {
59 MockOperationImageCtx
&m_image_ctx
;
61 AsyncRequest(MockOperationImageCtx
&image_ctx
, Context
*on_finish
)
62 : AsyncRequest
<MockImageCtx
>(image_ctx
, on_finish
), m_image_ctx(image_ctx
) {
68 // template definitions
69 #include "librbd/AsyncRequest.cc"
70 #include "librbd/AsyncObjectThrottle.cc"
71 #include "librbd/operation/Request.cc"
72 #include "librbd/operation/SnapshotRollbackRequest.cc"
78 using ::testing::InSequence
;
79 using ::testing::Return
;
80 using ::testing::WithArg
;
82 class TestMockOperationSnapshotRollbackRequest
: public TestMockFixture
{
84 typedef SnapshotRollbackRequest
<MockOperationImageCtx
> MockSnapshotRollbackRequest
;
85 typedef ResizeRequest
<MockOperationImageCtx
> MockResizeRequest
;
87 void expect_block_writes(MockOperationImageCtx
&mock_image_ctx
, int r
) {
88 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, block_writes(_
))
89 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
92 void expect_unblock_writes(MockOperationImageCtx
&mock_image_ctx
) {
93 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, unblock_writes())
97 void expect_get_image_size(MockOperationImageCtx
&mock_image_ctx
,
99 EXPECT_CALL(mock_image_ctx
, get_image_size(CEPH_NOSNAP
))
100 .WillOnce(Return(size
));
103 void expect_resize(MockOperationImageCtx
&mock_image_ctx
,
104 MockResizeRequest
&mock_resize_request
, int r
) {
105 expect_get_image_size(mock_image_ctx
, 123);
106 EXPECT_CALL(mock_resize_request
, send())
107 .WillOnce(FinishRequest(&mock_resize_request
, r
,
111 void expect_get_flags(MockOperationImageCtx
&mock_image_ctx
,
112 uint64_t snap_id
, int r
) {
113 EXPECT_CALL(mock_image_ctx
, get_flags(snap_id
, _
))
114 .WillOnce(Return(r
));
117 void expect_object_may_exist(MockOperationImageCtx
&mock_image_ctx
,
118 uint64_t object_no
, bool exists
) {
119 if (mock_image_ctx
.object_map
!= nullptr) {
120 EXPECT_CALL(*mock_image_ctx
.object_map
, object_may_exist(object_no
))
121 .WillOnce(Return(exists
));
125 void expect_get_snap_object_map(MockOperationImageCtx
&mock_image_ctx
,
126 MockObjectMap
*mock_object_map
, uint64_t snap_id
) {
127 if (mock_image_ctx
.object_map
!= nullptr) {
128 EXPECT_CALL(mock_image_ctx
, create_object_map(snap_id
))
129 .WillOnce(Return(mock_object_map
));
130 EXPECT_CALL(*mock_object_map
, open(_
))
131 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
135 void expect_rollback_object_map(MockOperationImageCtx
&mock_image_ctx
,
136 MockObjectMap
&mock_object_map
) {
137 if (mock_image_ctx
.object_map
!= nullptr) {
138 EXPECT_CALL(mock_object_map
, rollback(_
, _
))
139 .WillOnce(WithArg
<1>(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
)));
143 void expect_get_object_name(MockOperationImageCtx
&mock_image_ctx
,
144 uint64_t object_num
) {
145 EXPECT_CALL(mock_image_ctx
, get_object_name(object_num
))
146 .WillOnce(Return("object-name-" + stringify(object_num
)));
149 void expect_get_current_size(MockOperationImageCtx
&mock_image_ctx
, uint64_t size
) {
150 EXPECT_CALL(mock_image_ctx
, get_current_size())
151 .WillOnce(Return(size
));
154 void expect_rollback_snap_id(MockOperationImageCtx
&mock_image_ctx
,
155 const std::string
&oid
, int r
) {
156 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
157 selfmanaged_snap_rollback(oid
, _
))
158 .WillOnce(Return(r
));
161 void expect_rollback(MockOperationImageCtx
&mock_image_ctx
, int r
) {
162 expect_get_current_size(mock_image_ctx
, 1);
163 expect_object_may_exist(mock_image_ctx
, 0, true);
164 expect_get_object_name(mock_image_ctx
, 0);
165 expect_rollback_snap_id(mock_image_ctx
, "object-name-0", r
);
168 void expect_create_object_map(MockOperationImageCtx
&mock_image_ctx
,
169 MockObjectMap
*mock_object_map
) {
170 EXPECT_CALL(mock_image_ctx
, create_object_map(_
))
171 .WillOnce(Return(mock_object_map
));
174 void expect_open_object_map(MockOperationImageCtx
&mock_image_ctx
,
175 MockObjectMap
&mock_object_map
) {
176 EXPECT_CALL(mock_object_map
, open(_
))
177 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
180 void expect_refresh_object_map(MockOperationImageCtx
&mock_image_ctx
,
181 MockObjectMap
&mock_object_map
) {
182 if (mock_image_ctx
.object_map
!= nullptr) {
183 expect_create_object_map(mock_image_ctx
, &mock_object_map
);
184 expect_open_object_map(mock_image_ctx
, mock_object_map
);
188 void expect_invalidate_cache(MockOperationImageCtx
&mock_image_ctx
,
190 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
, invalidate_cache(_
))
191 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
194 int when_snap_rollback(MockOperationImageCtx
&mock_image_ctx
,
195 const std::string
&snap_name
,
196 uint64_t snap_id
, uint64_t snap_size
) {
197 C_SaferCond cond_ctx
;
198 librbd::NoOpProgressContext prog_ctx
;
199 MockSnapshotRollbackRequest
*req
= new MockSnapshotRollbackRequest(
200 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), snap_name
,
201 snap_id
, snap_size
, prog_ctx
);
203 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
206 return cond_ctx
.wait();
210 TEST_F(TestMockOperationSnapshotRollbackRequest
, Success
) {
211 librbd::ImageCtx
*ictx
;
212 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
214 MockOperationImageCtx
mock_image_ctx(*ictx
);
215 MockExclusiveLock mock_exclusive_lock
;
216 MockJournal mock_journal
;
217 MockObjectMap mock_object_map
;
218 MockObjectMap mock_snap_object_map
;
219 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
221 expect_op_work_queue(mock_image_ctx
);
224 MockResizeRequest mock_resize_request
;
225 expect_append_op_event(mock_image_ctx
, false, 0);
226 expect_block_writes(mock_image_ctx
, 0);
227 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
228 expect_get_flags(mock_image_ctx
, 123, 0);
229 expect_get_snap_object_map(mock_image_ctx
, &mock_snap_object_map
, 123);
230 expect_rollback_object_map(mock_image_ctx
, mock_object_map
);
231 expect_rollback(mock_image_ctx
, 0);
232 expect_refresh_object_map(mock_image_ctx
, mock_object_map
);
233 expect_invalidate_cache(mock_image_ctx
, 0);
234 expect_commit_op_event(mock_image_ctx
, 0);
235 expect_unblock_writes(mock_image_ctx
);
236 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
239 TEST_F(TestMockOperationSnapshotRollbackRequest
, BlockWritesError
) {
240 librbd::ImageCtx
*ictx
;
241 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
243 MockOperationImageCtx
mock_image_ctx(*ictx
);
244 MockExclusiveLock mock_exclusive_lock
;
245 MockJournal mock_journal
;
246 MockObjectMap mock_object_map
;
247 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
249 expect_op_work_queue(mock_image_ctx
);
252 expect_append_op_event(mock_image_ctx
, false, 0);
253 expect_block_writes(mock_image_ctx
, -EINVAL
);
254 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
255 expect_unblock_writes(mock_image_ctx
);
256 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
259 TEST_F(TestMockOperationSnapshotRollbackRequest
, SkipResize
) {
260 librbd::ImageCtx
*ictx
;
261 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
263 MockOperationImageCtx
mock_image_ctx(*ictx
);
264 MockExclusiveLock mock_exclusive_lock
;
265 MockJournal mock_journal
;
266 MockObjectMap mock_object_map
;
267 MockObjectMap mock_snap_object_map
;
268 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
270 expect_op_work_queue(mock_image_ctx
);
273 expect_append_op_event(mock_image_ctx
, false, 0);
274 expect_block_writes(mock_image_ctx
, 0);
275 expect_get_image_size(mock_image_ctx
, 345);
276 expect_get_flags(mock_image_ctx
, 123, 0);
277 expect_get_snap_object_map(mock_image_ctx
, &mock_snap_object_map
, 123);
278 expect_rollback_object_map(mock_image_ctx
, mock_object_map
);
279 expect_rollback(mock_image_ctx
, 0);
280 expect_refresh_object_map(mock_image_ctx
, mock_object_map
);
281 expect_invalidate_cache(mock_image_ctx
, 0);
282 expect_commit_op_event(mock_image_ctx
, 0);
283 expect_unblock_writes(mock_image_ctx
);
284 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx
, "snap", 123, 345));
287 TEST_F(TestMockOperationSnapshotRollbackRequest
, ResizeError
) {
288 librbd::ImageCtx
*ictx
;
289 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
291 MockOperationImageCtx
mock_image_ctx(*ictx
);
292 MockExclusiveLock mock_exclusive_lock
;
293 MockJournal mock_journal
;
294 MockObjectMap mock_object_map
;
295 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
297 expect_op_work_queue(mock_image_ctx
);
300 MockResizeRequest mock_resize_request
;
301 expect_append_op_event(mock_image_ctx
, false, 0);
302 expect_block_writes(mock_image_ctx
, 0);
303 expect_resize(mock_image_ctx
, mock_resize_request
, -EINVAL
);
304 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
305 expect_unblock_writes(mock_image_ctx
);
306 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
309 TEST_F(TestMockOperationSnapshotRollbackRequest
, RollbackObjectsError
) {
310 librbd::ImageCtx
*ictx
;
311 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
313 MockOperationImageCtx
mock_image_ctx(*ictx
);
314 MockExclusiveLock mock_exclusive_lock
;
315 MockJournal mock_journal
;
316 MockObjectMap mock_object_map
;
317 MockObjectMap mock_snap_object_map
;
318 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
320 expect_op_work_queue(mock_image_ctx
);
323 MockResizeRequest mock_resize_request
;
324 expect_append_op_event(mock_image_ctx
, false, 0);
325 expect_block_writes(mock_image_ctx
, 0);
326 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
327 expect_get_flags(mock_image_ctx
, 123, 0);
328 expect_get_snap_object_map(mock_image_ctx
, &mock_snap_object_map
, 123);
329 expect_rollback_object_map(mock_image_ctx
, mock_object_map
);
330 expect_rollback(mock_image_ctx
, -EINVAL
);
331 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
332 expect_unblock_writes(mock_image_ctx
);
333 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
336 TEST_F(TestMockOperationSnapshotRollbackRequest
, InvalidateCacheError
) {
337 librbd::ImageCtx
*ictx
;
338 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
339 REQUIRE(ictx
->cache
);
341 MockOperationImageCtx
mock_image_ctx(*ictx
);
342 MockExclusiveLock mock_exclusive_lock
;
343 MockJournal mock_journal
;
344 MockObjectMap mock_object_map
;
345 MockObjectMap mock_snap_object_map
;
346 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
348 expect_op_work_queue(mock_image_ctx
);
351 MockResizeRequest mock_resize_request
;
352 expect_append_op_event(mock_image_ctx
, false, 0);
353 expect_block_writes(mock_image_ctx
, 0);
354 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
355 expect_get_flags(mock_image_ctx
, 123, 0);
356 expect_get_snap_object_map(mock_image_ctx
, &mock_snap_object_map
, 123);
357 expect_rollback_object_map(mock_image_ctx
, mock_object_map
);
358 expect_rollback(mock_image_ctx
, 0);
359 expect_refresh_object_map(mock_image_ctx
, mock_object_map
);
360 expect_invalidate_cache(mock_image_ctx
, -EINVAL
);
361 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
362 expect_unblock_writes(mock_image_ctx
);
363 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
366 } // namespace operation
367 } // namespace librbd