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 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
));
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
) {
114 EXPECT_CALL(invalidate_request
, send())
115 .WillOnce(FinishRequest(&invalidate_request
, 0,
119 void expect_truncate_request(MockObjectMapImageCtx
&mock_image_ctx
) {
120 std::string
oid(ObjectMap
<>::object_map_name(mock_image_ctx
.id
,
122 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
), truncate(oid
, 0, _
))
123 .WillOnce(Return(0));
126 void expect_object_map_resize(MockObjectMapImageCtx
&mock_image_ctx
,
127 uint64_t num_objects
, int r
) {
128 std::string
oid(ObjectMap
<>::object_map_name(mock_image_ctx
.id
,
130 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
131 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_resize"), _
, _
, _
));
132 expect
.WillOnce(Return(r
));
135 void init_object_map(MockObjectMapImageCtx
&mock_image_ctx
,
136 ceph::BitVector
<2> *object_map
) {
137 uint64_t num_objs
= Striper::get_num_objects(
138 mock_image_ctx
.layout
, mock_image_ctx
.image_ctx
->size
);
139 object_map
->resize(num_objs
);
140 for (uint64_t i
= 0; i
< num_objs
; ++i
) {
141 (*object_map
)[i
] = rand() % 3;
146 TEST_F(TestMockObjectMapRefreshRequest
, SuccessHead
) {
147 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
149 librbd::ImageCtx
*ictx
;
150 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
152 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
154 ceph::BitVector
<2> on_disk_object_map
;
155 init_object_map(mock_image_ctx
, &on_disk_object_map
);
158 ceph::BitVector
<2> object_map
;
159 MockLockRequest mock_lock_request
;
160 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
164 expect_get_image_size(mock_image_ctx
, CEPH_NOSNAP
,
165 mock_image_ctx
.image_ctx
->size
);
166 expect_object_map_lock(mock_image_ctx
, mock_lock_request
);
167 expect_object_map_load(mock_image_ctx
, &on_disk_object_map
, CEPH_NOSNAP
, 0);
168 expect_get_image_size(mock_image_ctx
, CEPH_NOSNAP
,
169 mock_image_ctx
.image_ctx
->size
);
171 ASSERT_EQ(0, ctx
.wait());
173 ASSERT_EQ(on_disk_object_map
, object_map
);
176 TEST_F(TestMockObjectMapRefreshRequest
, SuccessSnapshot
) {
177 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
179 librbd::ImageCtx
*ictx
;
180 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
182 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
184 ceph::BitVector
<2> on_disk_object_map
;
185 init_object_map(mock_image_ctx
, &on_disk_object_map
);
188 ceph::BitVector
<2> object_map
;
189 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
193 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
194 mock_image_ctx
.image_ctx
->size
);
195 expect_object_map_load(mock_image_ctx
, &on_disk_object_map
, TEST_SNAP_ID
, 0);
196 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
197 mock_image_ctx
.image_ctx
->size
);
199 ASSERT_EQ(0, ctx
.wait());
201 ASSERT_EQ(on_disk_object_map
, object_map
);
204 TEST_F(TestMockObjectMapRefreshRequest
, LoadError
) {
205 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
207 librbd::ImageCtx
*ictx
;
208 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
210 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
212 ceph::BitVector
<2> on_disk_object_map
;
213 init_object_map(mock_image_ctx
, &on_disk_object_map
);
216 ceph::BitVector
<2> object_map
;
217 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
221 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
222 mock_image_ctx
.image_ctx
->size
);
223 expect_object_map_load(mock_image_ctx
, nullptr, TEST_SNAP_ID
, -ENOENT
);
225 MockInvalidateRequest invalidate_request
;
226 expect_invalidate_request(mock_image_ctx
, invalidate_request
);
227 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
228 mock_image_ctx
.image_ctx
->size
);
231 ASSERT_EQ(0, ctx
.wait());
234 TEST_F(TestMockObjectMapRefreshRequest
, LoadCorrupt
) {
235 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
237 librbd::ImageCtx
*ictx
;
238 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
240 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
242 ceph::BitVector
<2> on_disk_object_map
;
243 init_object_map(mock_image_ctx
, &on_disk_object_map
);
246 ceph::BitVector
<2> object_map
;
247 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
251 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
252 mock_image_ctx
.image_ctx
->size
);
253 expect_object_map_load(mock_image_ctx
, nullptr, TEST_SNAP_ID
, -EINVAL
);
255 MockInvalidateRequest invalidate_request
;
256 expect_invalidate_request(mock_image_ctx
, invalidate_request
);
257 expect_truncate_request(mock_image_ctx
);
258 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), 0);
259 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
260 mock_image_ctx
.image_ctx
->size
);
263 ASSERT_EQ(0, ctx
.wait());
266 TEST_F(TestMockObjectMapRefreshRequest
, TooSmall
) {
267 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
269 librbd::ImageCtx
*ictx
;
270 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
272 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
274 ceph::BitVector
<2> on_disk_object_map
;
275 init_object_map(mock_image_ctx
, &on_disk_object_map
);
277 ceph::BitVector
<2> small_object_map
;
280 ceph::BitVector
<2> object_map
;
281 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
285 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
286 mock_image_ctx
.image_ctx
->size
);
287 expect_object_map_load(mock_image_ctx
, &small_object_map
, TEST_SNAP_ID
, 0);
289 MockInvalidateRequest invalidate_request
;
290 expect_invalidate_request(mock_image_ctx
, invalidate_request
);
291 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), 0);
292 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
293 mock_image_ctx
.image_ctx
->size
);
296 ASSERT_EQ(0, ctx
.wait());
299 TEST_F(TestMockObjectMapRefreshRequest
, TooLarge
) {
300 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
302 librbd::ImageCtx
*ictx
;
303 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
305 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
307 ceph::BitVector
<2> on_disk_object_map
;
308 init_object_map(mock_image_ctx
, &on_disk_object_map
);
310 ceph::BitVector
<2> large_object_map
;
311 large_object_map
.resize(on_disk_object_map
.size() * 2);
314 ceph::BitVector
<2> object_map
;
315 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
319 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
320 mock_image_ctx
.image_ctx
->size
);
321 expect_object_map_load(mock_image_ctx
, &large_object_map
, TEST_SNAP_ID
, 0);
322 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
323 mock_image_ctx
.image_ctx
->size
);
325 ASSERT_EQ(0, ctx
.wait());
328 TEST_F(TestMockObjectMapRefreshRequest
, ResizeError
) {
329 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
331 librbd::ImageCtx
*ictx
;
332 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
334 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
336 ceph::BitVector
<2> on_disk_object_map
;
337 init_object_map(mock_image_ctx
, &on_disk_object_map
);
339 ceph::BitVector
<2> small_object_map
;
342 ceph::BitVector
<2> object_map
;
343 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
347 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
348 mock_image_ctx
.image_ctx
->size
);
349 expect_object_map_load(mock_image_ctx
, &small_object_map
, TEST_SNAP_ID
, 0);
351 MockInvalidateRequest invalidate_request
;
352 expect_invalidate_request(mock_image_ctx
, invalidate_request
);
353 expect_object_map_resize(mock_image_ctx
, on_disk_object_map
.size(), -ESTALE
);
354 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
355 mock_image_ctx
.image_ctx
->size
);
358 ASSERT_EQ(0, ctx
.wait());
361 TEST_F(TestMockObjectMapRefreshRequest
, LargeImageError
) {
362 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
364 librbd::ImageCtx
*ictx
;
365 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
367 MockObjectMapImageCtx
mock_image_ctx(*ictx
);
369 ceph::BitVector
<2> on_disk_object_map
;
370 init_object_map(mock_image_ctx
, &on_disk_object_map
);
373 ceph::BitVector
<2> object_map
;
374 MockRefreshRequest
*req
= new MockRefreshRequest(mock_image_ctx
, &object_map
,
378 expect_get_image_size(mock_image_ctx
, TEST_SNAP_ID
,
379 std::numeric_limits
<int64_t>::max());
381 MockInvalidateRequest invalidate_request
;
382 expect_invalidate_request(mock_image_ctx
, invalidate_request
);
385 ASSERT_EQ(-EFBIG
, ctx
.wait());
388 } // namespace object_map
389 } // namespace librbd