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/object_map/mock/MockInvalidateRequest.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "common/bit_vector.hpp"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/object_map/RefreshRequest.h"
12 #include "librbd/object_map/LockRequest.h"
18 struct MockObjectMapImageCtx
: public MockImageCtx
{
19 MockObjectMapImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
23 } // anonymous namespace
25 namespace object_map
{
28 class LockRequest
<MockObjectMapImageCtx
> {
30 static LockRequest
*s_instance
;
31 static LockRequest
*create(MockObjectMapImageCtx
&image_ctx
, Context
*on_finish
) {
32 ceph_assert(s_instance
!= nullptr);
33 s_instance
->on_finish
= on_finish
;
37 Context
*on_finish
= nullptr;
43 MOCK_METHOD0(send
, void());
47 struct InvalidateRequest
<MockObjectMapImageCtx
> :
48 public MockInvalidateRequestBase
<MockObjectMapImageCtx
> {
51 LockRequest
<MockObjectMapImageCtx
> *LockRequest
<MockObjectMapImageCtx
>::s_instance
= nullptr;
53 } // namespace object_map
56 // template definitions
57 #include "librbd/object_map/RefreshRequest.cc"
58 #include "librbd/object_map/LockRequest.cc"
61 namespace object_map
{
64 using ::testing::DoAll
;
65 using ::testing::DoDefault
;
66 using ::testing::InSequence
;
67 using ::testing::Return
;
68 using ::testing::StrEq
;
69 using ::testing::WithArg
;
71 class TestMockObjectMapRefreshRequest
: public TestMockFixture
{
73 static const uint64_t TEST_SNAP_ID
= 123;
75 typedef RefreshRequest
<MockObjectMapImageCtx
> MockRefreshRequest
;
76 typedef LockRequest
<MockObjectMapImageCtx
> MockLockRequest
;
77 typedef InvalidateRequest
<MockObjectMapImageCtx
> MockInvalidateRequest
;
79 void expect_object_map_lock(MockObjectMapImageCtx
&mock_image_ctx
,
80 MockLockRequest
&mock_lock_request
) {
81 EXPECT_CALL(mock_lock_request
, send())
82 .WillOnce(FinishRequest(&mock_lock_request
, 0,
86 void expect_object_map_load(MockObjectMapImageCtx
&mock_image_ctx
,
87 ceph::BitVector
<2> *object_map
, uint64_t snap_id
,
89 std::string
oid(ObjectMap
<>::object_map_name(mock_image_ctx
.id
, snap_id
));
90 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
91 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_load"), _
, _
, _
));
93 expect
.WillOnce(Return(r
));
95 ceph_assert(object_map
);
96 object_map
->set_crc_enabled(false);
99 encode(*object_map
, bl
);
101 std::string
str(bl
.c_str(), bl
.length());
102 expect
.WillOnce(DoAll(WithArg
<5>(CopyInBufferlist(str
)), Return(0)));
106 void expect_get_image_size(MockObjectMapImageCtx
&mock_image_ctx
, uint64_t snap_id
,
108 EXPECT_CALL(mock_image_ctx
, get_image_size(snap_id
))
109 .WillOnce(Return(size
));
112 void expect_invalidate_request(MockObjectMapImageCtx
&mock_image_ctx
,
113 MockInvalidateRequest
&invalidate_request
,
115 EXPECT_CALL(invalidate_request
, send())
116 .WillOnce(FinishRequest(&invalidate_request
, r
,
120 void expect_truncate_request(MockObjectMapImageCtx
&mock_image_ctx
) {
121 std::string
oid(ObjectMap
<>::object_map_name(mock_image_ctx
.id
,
123 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
), truncate(oid
, 0, _
))
124 .WillOnce(Return(0));
127 void expect_object_map_resize(MockObjectMapImageCtx
&mock_image_ctx
,
128 uint64_t num_objects
, int r
) {
129 std::string
oid(ObjectMap
<>::object_map_name(mock_image_ctx
.id
,
131 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
132 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_resize"), _
, _
, _
));
133 expect
.WillOnce(Return(r
));
136 void init_object_map(MockObjectMapImageCtx
&mock_image_ctx
,
137 ceph::BitVector
<2> *object_map
) {
138 uint64_t num_objs
= Striper::get_num_objects(
139 mock_image_ctx
.layout
, mock_image_ctx
.image_ctx
->size
);
140 object_map
->resize(num_objs
);
141 for (uint64_t i
= 0; i
< num_objs
; ++i
) {
142 (*object_map
)[i
] = rand() % 3;
147 TEST_F(TestMockObjectMapRefreshRequest
, SuccessHead
) {
148 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
150 librbd::ImageCtx
*ictx
;
151 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
153 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
155 ceph::BitVector
<2> on_disk_object_map
;
156 init_object_map(mock_image_ctx
, &on_disk_object_map
);
159 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
160 ceph::BitVector
<2> object_map
;
161 MockLockRequest mock_lock_request
;
162 MockRefreshRequest
*req
= new MockRefreshRequest(
163 mock_image_ctx
, &object_map_lock
, &object_map
, CEPH_NOSNAP
, &ctx
);
166 expect_get_image_size(mock_image_ctx
, CEPH_NOSNAP
,
167 mock_image_ctx
.image_ctx
->size
);
168 expect_object_map_lock(mock_image_ctx
, mock_lock_request
);
169 expect_object_map_load(mock_image_ctx
, &on_disk_object_map
, CEPH_NOSNAP
, 0);
170 expect_get_image_size(mock_image_ctx
, CEPH_NOSNAP
,
171 mock_image_ctx
.image_ctx
->size
);
173 ASSERT_EQ(0, ctx
.wait());
175 ASSERT_EQ(on_disk_object_map
, object_map
);
178 TEST_F(TestMockObjectMapRefreshRequest
, SuccessSnapshot
) {
179 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
181 librbd::ImageCtx
*ictx
;
182 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
184 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
186 ceph::BitVector
<2> on_disk_object_map
;
187 init_object_map(mock_image_ctx
, &on_disk_object_map
);
190 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
191 ceph::BitVector
<2> object_map
;
192 MockRefreshRequest
*req
= new MockRefreshRequest(
193 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
196 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
197 mock_image_ctx
.image_ctx
->size
);
198 expect_object_map_load(mock_image_ctx
, &on_disk_object_map
, TEST_SNAP_ID
, 0);
199 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
200 mock_image_ctx
.image_ctx
->size
);
202 ASSERT_EQ(0, ctx
.wait());
204 ASSERT_EQ(on_disk_object_map
, object_map
);
207 TEST_F(TestMockObjectMapRefreshRequest
, LoadError
) {
208 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
210 librbd::ImageCtx
*ictx
;
211 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
213 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
215 ceph::BitVector
<2> on_disk_object_map
;
216 init_object_map(mock_image_ctx
, &on_disk_object_map
);
219 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
220 ceph::BitVector
<2> object_map
;
221 MockRefreshRequest
*req
= new MockRefreshRequest(
222 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
225 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
226 mock_image_ctx
.image_ctx
->size
);
227 expect_object_map_load(mock_image_ctx
, nullptr, TEST_SNAP_ID
, -ENOENT
);
229 MockInvalidateRequest invalidate_request
;
230 expect_invalidate_request(mock_image_ctx
, invalidate_request
, 0);
231 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
232 mock_image_ctx
.image_ctx
->size
);
235 ASSERT_EQ(0, ctx
.wait());
238 TEST_F(TestMockObjectMapRefreshRequest
, LoadInvalidateError
) {
239 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
241 librbd::ImageCtx
*ictx
;
242 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
244 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
246 ceph::BitVector
<2> on_disk_object_map
;
247 init_object_map(mock_image_ctx
, &on_disk_object_map
);
250 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
251 ceph::BitVector
<2> object_map
;
252 MockRefreshRequest
*req
= new MockRefreshRequest(
253 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
256 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
257 mock_image_ctx
.image_ctx
->size
);
258 expect_object_map_load(mock_image_ctx
, nullptr, TEST_SNAP_ID
, -ENOENT
);
260 MockInvalidateRequest invalidate_request
;
261 expect_invalidate_request(mock_image_ctx
, invalidate_request
, -EPERM
);
262 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
263 mock_image_ctx
.image_ctx
->size
);
266 ASSERT_EQ(-EPERM
, ctx
.wait());
269 TEST_F(TestMockObjectMapRefreshRequest
, LoadCorrupt
) {
270 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
272 librbd::ImageCtx
*ictx
;
273 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
275 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
277 ceph::BitVector
<2> on_disk_object_map
;
278 init_object_map(mock_image_ctx
, &on_disk_object_map
);
281 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
282 ceph::BitVector
<2> object_map
;
283 MockRefreshRequest
*req
= new MockRefreshRequest(
284 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
287 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
288 mock_image_ctx
.image_ctx
->size
);
289 expect_object_map_load(mock_image_ctx
, nullptr, TEST_SNAP_ID
, -EINVAL
);
291 MockInvalidateRequest invalidate_request
;
292 expect_invalidate_request(mock_image_ctx
, invalidate_request
, 0);
293 expect_truncate_request(mock_image_ctx
);
294 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), 0);
295 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
296 mock_image_ctx
.image_ctx
->size
);
299 ASSERT_EQ(0, ctx
.wait());
302 TEST_F(TestMockObjectMapRefreshRequest
, TooSmall
) {
303 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
305 librbd::ImageCtx
*ictx
;
306 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
308 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
310 ceph::BitVector
<2> on_disk_object_map
;
311 init_object_map(mock_image_ctx
, &on_disk_object_map
);
313 ceph::BitVector
<2> small_object_map
;
316 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
317 ceph::BitVector
<2> object_map
;
318 MockRefreshRequest
*req
= new MockRefreshRequest(
319 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
322 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
323 mock_image_ctx
.image_ctx
->size
);
324 expect_object_map_load(mock_image_ctx
, &small_object_map
, TEST_SNAP_ID
, 0);
326 MockInvalidateRequest invalidate_request
;
327 expect_invalidate_request(mock_image_ctx
, invalidate_request
, 0);
328 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), 0);
329 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
330 mock_image_ctx
.image_ctx
->size
);
333 ASSERT_EQ(0, ctx
.wait());
336 TEST_F(TestMockObjectMapRefreshRequest
, TooSmallInvalidateError
) {
337 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
339 librbd::ImageCtx
*ictx
;
340 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
342 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
344 ceph::BitVector
<2> on_disk_object_map
;
345 init_object_map(mock_image_ctx
, &on_disk_object_map
);
347 ceph::BitVector
<2> small_object_map
;
350 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
351 ceph::BitVector
<2> object_map
;
352 MockRefreshRequest
*req
= new MockRefreshRequest(
353 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
356 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
357 mock_image_ctx
.image_ctx
->size
);
358 expect_object_map_load(mock_image_ctx
, &small_object_map
, TEST_SNAP_ID
, 0);
360 MockInvalidateRequest invalidate_request
;
361 expect_invalidate_request(mock_image_ctx
, invalidate_request
, -EPERM
);
362 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
363 mock_image_ctx
.image_ctx
->size
);
366 ASSERT_EQ(-EPERM
, ctx
.wait());
369 TEST_F(TestMockObjectMapRefreshRequest
, TooLarge
) {
370 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
372 librbd::ImageCtx
*ictx
;
373 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
375 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
377 ceph::BitVector
<2> on_disk_object_map
;
378 init_object_map(mock_image_ctx
, &on_disk_object_map
);
380 ceph::BitVector
<2> large_object_map
;
381 large_object_map
.resize(on_disk_object_map
.size() * 2);
384 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
385 ceph::BitVector
<2> object_map
;
386 MockRefreshRequest
*req
= new MockRefreshRequest(
387 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
390 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
391 mock_image_ctx
.image_ctx
->size
);
392 expect_object_map_load(mock_image_ctx
, &large_object_map
, TEST_SNAP_ID
, 0);
393 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
394 mock_image_ctx
.image_ctx
->size
);
396 ASSERT_EQ(0, ctx
.wait());
399 TEST_F(TestMockObjectMapRefreshRequest
, ResizeError
) {
400 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
402 librbd::ImageCtx
*ictx
;
403 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
405 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
407 ceph::BitVector
<2> on_disk_object_map
;
408 init_object_map(mock_image_ctx
, &on_disk_object_map
);
410 ceph::BitVector
<2> small_object_map
;
413 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
414 ceph::BitVector
<2> object_map
;
415 MockRefreshRequest
*req
= new MockRefreshRequest(
416 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
419 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
420 mock_image_ctx
.image_ctx
->size
);
421 expect_object_map_load(mock_image_ctx
, &small_object_map
, TEST_SNAP_ID
, 0);
423 MockInvalidateRequest invalidate_request
;
424 expect_invalidate_request(mock_image_ctx
, invalidate_request
, 0);
425 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), -ESTALE
);
426 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
427 mock_image_ctx
.image_ctx
->size
);
430 ASSERT_EQ(0, ctx
.wait());
433 TEST_F(TestMockObjectMapRefreshRequest
, LargeImageError
) {
434 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
436 librbd::ImageCtx
*ictx
;
437 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
439 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
441 ceph::BitVector
<2> on_disk_object_map
;
442 init_object_map(mock_image_ctx
, &on_disk_object_map
);
445 ceph::shared_mutex object_map_lock
= ceph::make_shared_mutex("lock");
446 ceph::BitVector
<2> object_map
;
447 MockRefreshRequest
*req
= new MockRefreshRequest(
448 mock_image_ctx
, &object_map_lock
, &object_map
, TEST_SNAP_ID
, &ctx
);
451 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
452 std::numeric_limits
<int64_t>::max());
454 MockInvalidateRequest invalidate_request
;
455 expect_invalidate_request(mock_image_ctx
, invalidate_request
, 0);
458 ASSERT_EQ(-EFBIG
, ctx
.wait());
461 } // namespace object_map
462 } // namespace librbd