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/librados_test_stub/MockTestMemIoCtxImpl.h"
8 #include "include/stringify.h"
9 #include "common/bit_vector.hpp"
10 #include "librbd/ImageState.h"
11 #include "librbd/internal.h"
12 #include "librbd/operation/SnapshotRollbackRequest.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
20 struct MockOperationImageCtx
: public MockImageCtx
{
21 MockOperationImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
25 } // anonymous namespace
30 struct ResizeRequest
<MockOperationImageCtx
> {
31 static ResizeRequest
*s_instance
;
32 Context
*on_finish
= nullptr;
34 static ResizeRequest
* create(MockOperationImageCtx
&image_ctx
, Context
*on_finish
,
35 uint64_t new_size
, bool allow_shrink
,
36 ProgressContext
&prog_ctx
, uint64_t journal_op_tid
,
37 bool disable_journal
) {
38 assert(s_instance
!= nullptr);
39 assert(journal_op_tid
== 0);
40 assert(disable_journal
);
41 s_instance
->on_finish
= on_finish
;
49 MOCK_METHOD0(send
, void());
52 ResizeRequest
<MockOperationImageCtx
> *ResizeRequest
<MockOperationImageCtx
>::s_instance
= nullptr;
54 } // namespace operation
57 struct AsyncRequest
<MockOperationImageCtx
> : public AsyncRequest
<MockImageCtx
> {
58 MockOperationImageCtx
&m_image_ctx
;
60 AsyncRequest(MockOperationImageCtx
&image_ctx
, Context
*on_finish
)
61 : AsyncRequest
<MockImageCtx
>(image_ctx
, on_finish
), m_image_ctx(image_ctx
) {
67 // template definitions
68 #include "librbd/AsyncRequest.cc"
69 #include "librbd/AsyncObjectThrottle.cc"
70 #include "librbd/operation/Request.cc"
71 #include "librbd/operation/SnapshotRollbackRequest.cc"
77 using ::testing::InSequence
;
78 using ::testing::Return
;
79 using ::testing::WithArg
;
81 class TestMockOperationSnapshotRollbackRequest
: public TestMockFixture
{
83 typedef SnapshotRollbackRequest
<MockOperationImageCtx
> MockSnapshotRollbackRequest
;
84 typedef ResizeRequest
<MockOperationImageCtx
> MockResizeRequest
;
86 void expect_block_writes(MockOperationImageCtx
&mock_image_ctx
, int r
) {
87 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, block_writes(_
))
88 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
91 void expect_unblock_writes(MockOperationImageCtx
&mock_image_ctx
) {
92 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, unblock_writes())
96 void expect_get_image_size(MockOperationImageCtx
&mock_image_ctx
,
98 EXPECT_CALL(mock_image_ctx
, get_image_size(CEPH_NOSNAP
))
99 .WillOnce(Return(size
));
102 void expect_resize(MockOperationImageCtx
&mock_image_ctx
,
103 MockResizeRequest
&mock_resize_request
, int r
) {
104 expect_get_image_size(mock_image_ctx
, 123);
105 EXPECT_CALL(mock_resize_request
, send())
106 .WillOnce(FinishRequest(&mock_resize_request
, r
,
110 void expect_rollback_object_map(MockOperationImageCtx
&mock_image_ctx
,
111 MockObjectMap
&mock_object_map
) {
112 if (mock_image_ctx
.object_map
!= nullptr) {
113 EXPECT_CALL(mock_object_map
, rollback(_
, _
))
114 .WillOnce(WithArg
<1>(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
)));
118 void expect_get_object_name(MockOperationImageCtx
&mock_image_ctx
,
119 uint64_t object_num
) {
120 EXPECT_CALL(mock_image_ctx
, get_object_name(object_num
))
121 .WillOnce(Return("object-name-" + stringify(object_num
)));
124 void expect_get_current_size(MockOperationImageCtx
&mock_image_ctx
, uint64_t size
) {
125 EXPECT_CALL(mock_image_ctx
, get_current_size())
126 .WillOnce(Return(size
));
129 void expect_rollback_snap_id(MockOperationImageCtx
&mock_image_ctx
,
130 const std::string
&oid
, int r
) {
131 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
132 selfmanaged_snap_rollback(oid
, _
))
133 .WillOnce(Return(r
));
136 void expect_rollback(MockOperationImageCtx
&mock_image_ctx
, int r
) {
137 expect_get_current_size(mock_image_ctx
, 1);
138 expect_get_object_name(mock_image_ctx
, 0);
139 expect_rollback_snap_id(mock_image_ctx
, "object-name-0", r
);
142 void expect_create_object_map(MockOperationImageCtx
&mock_image_ctx
,
143 MockObjectMap
*mock_object_map
) {
144 EXPECT_CALL(mock_image_ctx
, create_object_map(_
))
145 .WillOnce(Return(mock_object_map
));
148 void expect_open_object_map(MockOperationImageCtx
&mock_image_ctx
,
149 MockObjectMap
&mock_object_map
) {
150 EXPECT_CALL(mock_object_map
, open(_
))
151 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
154 void expect_refresh_object_map(MockOperationImageCtx
&mock_image_ctx
,
155 MockObjectMap
&mock_object_map
) {
156 if (mock_image_ctx
.object_map
!= nullptr) {
157 expect_create_object_map(mock_image_ctx
, &mock_object_map
);
158 expect_open_object_map(mock_image_ctx
, mock_object_map
);
162 void expect_invalidate_cache(MockOperationImageCtx
&mock_image_ctx
, int r
) {
163 if (mock_image_ctx
.object_cacher
!= nullptr) {
164 EXPECT_CALL(mock_image_ctx
, invalidate_cache(true, _
))
165 .WillOnce(WithArg
<1>(CompleteContext(r
, static_cast<ContextWQ
*>(NULL
))));
169 int when_snap_rollback(MockOperationImageCtx
&mock_image_ctx
,
170 const std::string
&snap_name
,
171 uint64_t snap_id
, uint64_t snap_size
) {
172 C_SaferCond cond_ctx
;
173 librbd::NoOpProgressContext prog_ctx
;
174 MockSnapshotRollbackRequest
*req
= new MockSnapshotRollbackRequest(
175 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), snap_name
,
176 snap_id
, snap_size
, prog_ctx
);
178 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
181 return cond_ctx
.wait();
185 TEST_F(TestMockOperationSnapshotRollbackRequest
, Success
) {
186 librbd::ImageCtx
*ictx
;
187 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
189 MockOperationImageCtx
mock_image_ctx(*ictx
);
190 MockExclusiveLock mock_exclusive_lock
;
191 MockJournal mock_journal
;
192 MockObjectMap
*mock_object_map
= new MockObjectMap();
193 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
195 expect_op_work_queue(mock_image_ctx
);
198 MockResizeRequest mock_resize_request
;
199 expect_append_op_event(mock_image_ctx
, false, 0);
200 expect_block_writes(mock_image_ctx
, 0);
201 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
202 expect_rollback_object_map(mock_image_ctx
, *mock_object_map
);
203 expect_rollback(mock_image_ctx
, 0);
204 expect_refresh_object_map(mock_image_ctx
, *mock_object_map
);
205 expect_invalidate_cache(mock_image_ctx
, 0);
206 expect_commit_op_event(mock_image_ctx
, 0);
207 expect_unblock_writes(mock_image_ctx
);
208 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
211 TEST_F(TestMockOperationSnapshotRollbackRequest
, BlockWritesError
) {
212 librbd::ImageCtx
*ictx
;
213 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
215 MockOperationImageCtx
mock_image_ctx(*ictx
);
216 MockExclusiveLock mock_exclusive_lock
;
217 MockJournal mock_journal
;
218 MockObjectMap mock_object_map
;
219 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
221 expect_op_work_queue(mock_image_ctx
);
224 expect_append_op_event(mock_image_ctx
, false, 0);
225 expect_block_writes(mock_image_ctx
, -EINVAL
);
226 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
227 expect_unblock_writes(mock_image_ctx
);
228 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
231 TEST_F(TestMockOperationSnapshotRollbackRequest
, SkipResize
) {
232 librbd::ImageCtx
*ictx
;
233 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
235 MockOperationImageCtx
mock_image_ctx(*ictx
);
236 MockExclusiveLock mock_exclusive_lock
;
237 MockJournal mock_journal
;
238 MockObjectMap
*mock_object_map
= new MockObjectMap();
239 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
241 expect_op_work_queue(mock_image_ctx
);
244 expect_append_op_event(mock_image_ctx
, false, 0);
245 expect_block_writes(mock_image_ctx
, 0);
246 expect_get_image_size(mock_image_ctx
, 345);
247 expect_rollback_object_map(mock_image_ctx
, *mock_object_map
);
248 expect_rollback(mock_image_ctx
, 0);
249 expect_refresh_object_map(mock_image_ctx
, *mock_object_map
);
250 expect_invalidate_cache(mock_image_ctx
, 0);
251 expect_commit_op_event(mock_image_ctx
, 0);
252 expect_unblock_writes(mock_image_ctx
);
253 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx
, "snap", 123, 345));
256 TEST_F(TestMockOperationSnapshotRollbackRequest
, ResizeError
) {
257 librbd::ImageCtx
*ictx
;
258 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
260 MockOperationImageCtx
mock_image_ctx(*ictx
);
261 MockExclusiveLock mock_exclusive_lock
;
262 MockJournal mock_journal
;
263 MockObjectMap mock_object_map
;
264 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
266 expect_op_work_queue(mock_image_ctx
);
269 MockResizeRequest mock_resize_request
;
270 expect_append_op_event(mock_image_ctx
, false, 0);
271 expect_block_writes(mock_image_ctx
, 0);
272 expect_resize(mock_image_ctx
, mock_resize_request
, -EINVAL
);
273 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
274 expect_unblock_writes(mock_image_ctx
);
275 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
278 TEST_F(TestMockOperationSnapshotRollbackRequest
, RollbackObjectsError
) {
279 librbd::ImageCtx
*ictx
;
280 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
282 MockOperationImageCtx
mock_image_ctx(*ictx
);
283 MockExclusiveLock mock_exclusive_lock
;
284 MockJournal mock_journal
;
285 MockObjectMap mock_object_map
;
286 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
288 expect_op_work_queue(mock_image_ctx
);
291 MockResizeRequest mock_resize_request
;
292 expect_append_op_event(mock_image_ctx
, false, 0);
293 expect_block_writes(mock_image_ctx
, 0);
294 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
295 expect_rollback_object_map(mock_image_ctx
, mock_object_map
);
296 expect_rollback(mock_image_ctx
, -EINVAL
);
297 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
298 expect_unblock_writes(mock_image_ctx
);
299 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
302 TEST_F(TestMockOperationSnapshotRollbackRequest
, InvalidateCacheError
) {
303 librbd::ImageCtx
*ictx
;
304 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
305 REQUIRE(ictx
->cache
);
307 MockOperationImageCtx
mock_image_ctx(*ictx
);
308 MockExclusiveLock mock_exclusive_lock
;
309 MockJournal mock_journal
;
310 MockObjectMap
*mock_object_map
= new MockObjectMap();
311 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
313 expect_op_work_queue(mock_image_ctx
);
316 MockResizeRequest mock_resize_request
;
317 expect_append_op_event(mock_image_ctx
, false, 0);
318 expect_block_writes(mock_image_ctx
, 0);
319 expect_resize(mock_image_ctx
, mock_resize_request
, 0);
320 expect_rollback_object_map(mock_image_ctx
, *mock_object_map
);
321 expect_rollback(mock_image_ctx
, 0);
322 expect_refresh_object_map(mock_image_ctx
, *mock_object_map
);
323 expect_invalidate_cache(mock_image_ctx
, -EINVAL
);
324 expect_commit_op_event(mock_image_ctx
, -EINVAL
);
325 expect_unblock_writes(mock_image_ctx
);
326 ASSERT_EQ(-EINVAL
, when_snap_rollback(mock_image_ctx
, "snap", 123, 0));
329 } // namespace operation
330 } // namespace librbd