]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/object_map/test_mock_DiffRequest.cc
366bbb27860343f3240a59cae3df4c57696a9abb
[ceph.git] / ceph / src / test / librbd / object_map / test_mock_DiffRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
7 #include "include/rbd_types.h"
8 #include "common/ceph_mutex.h"
9 #include "librbd/object_map/DiffRequest.h"
10 #include "gtest/gtest.h"
11 #include "gmock/gmock.h"
12
13 namespace librbd {
14 namespace {
15
16 struct MockTestImageCtx : public MockImageCtx {
17 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
18 }
19 };
20
21 } // anonymous namespace
22 } // namespace librbd
23
24 #include "librbd/object_map/DiffRequest.cc"
25
26 using ::testing::_;
27 using ::testing::Invoke;
28 using ::testing::InSequence;
29 using ::testing::StrEq;
30 using ::testing::WithArg;
31
32 namespace librbd {
33 namespace object_map {
34
35 class TestMockObjectMapDiffRequest : public TestMockFixture {
36 public:
37 typedef DiffRequest<MockTestImageCtx> MockDiffRequest;
38
39 void SetUp() override {
40 TestMockFixture::SetUp();
41
42 ASSERT_EQ(0, open_image(m_image_name, &m_image_ctx));
43 }
44
45 void expect_get_flags(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
46 int32_t flags, int r) {
47 EXPECT_CALL(mock_image_ctx, get_flags(snap_id, _))
48 .WillOnce(WithArg<1>(Invoke([flags, r](uint64_t *out_flags) {
49 *out_flags = flags;
50 return r;
51 })));
52 }
53
54 template <typename Lambda>
55 void expect_load_map(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
56 const BitVector<2>& object_map, int r,
57 Lambda&& lambda) {
58 std::string snap_oid(ObjectMap<>::object_map_name(mock_image_ctx.id,
59 snap_id));
60 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
61 exec(snap_oid, _, StrEq("rbd"), StrEq("object_map_load"), _,
62 _, _))
63 .WillOnce(WithArg<5>(Invoke([object_map, r, lambda=std::move(lambda)]
64 (bufferlist* out_bl) {
65 lambda();
66
67 auto out_object_map{object_map};
68 out_object_map.set_crc_enabled(false);
69 encode(out_object_map, *out_bl);
70 return r;
71 })));
72 }
73
74 void expect_load_map(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
75 const BitVector<2>& object_map, int r) {
76 expect_load_map(mock_image_ctx, snap_id, object_map, r, [](){});
77 }
78
79 librbd::ImageCtx* m_image_ctx = nullptr;
80 BitVector<2> m_object_diff_state;
81 };
82
83 TEST_F(TestMockObjectMapDiffRequest, InvalidStartSnap) {
84 MockTestImageCtx mock_image_ctx(*m_image_ctx);
85
86 InSequence seq;
87
88 C_SaferCond ctx;
89 auto req = new MockDiffRequest(&mock_image_ctx, CEPH_NOSNAP, 0,
90 &m_object_diff_state, &ctx);
91 req->send();
92 ASSERT_EQ(-EINVAL, ctx.wait());
93 }
94
95 TEST_F(TestMockObjectMapDiffRequest, StartEndSnapEqual) {
96 MockTestImageCtx mock_image_ctx(*m_image_ctx);
97
98 InSequence seq;
99
100 C_SaferCond ctx;
101 auto req = new MockDiffRequest(&mock_image_ctx, 1, 1,
102 &m_object_diff_state, &ctx);
103 req->send();
104 ASSERT_EQ(0, ctx.wait());
105 ASSERT_EQ(0U, m_object_diff_state.size());
106 }
107
108 TEST_F(TestMockObjectMapDiffRequest, FastDiffDisabled) {
109 // negative test -- object-map implicitly enables fast-diff
110 REQUIRE(!is_feature_enabled(RBD_FEATURE_OBJECT_MAP));
111
112 MockTestImageCtx mock_image_ctx(*m_image_ctx);
113
114 InSequence seq;
115
116 C_SaferCond ctx;
117 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
118 &m_object_diff_state, &ctx);
119 req->send();
120 ASSERT_EQ(-EINVAL, ctx.wait());
121 }
122
123 TEST_F(TestMockObjectMapDiffRequest, FastDiffInvalid) {
124 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
125
126 MockTestImageCtx mock_image_ctx(*m_image_ctx);
127 mock_image_ctx.snap_info = {
128 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
129 };
130
131 InSequence seq;
132 expect_get_flags(mock_image_ctx, 1U, RBD_FLAG_FAST_DIFF_INVALID, 0);
133
134 C_SaferCond ctx;
135 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
136 &m_object_diff_state, &ctx);
137 req->send();
138 ASSERT_EQ(-EINVAL, ctx.wait());
139 }
140
141 TEST_F(TestMockObjectMapDiffRequest, FullDelta) {
142 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
143
144 uint32_t object_count = 5;
145 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
146
147 MockTestImageCtx mock_image_ctx(*m_image_ctx);
148 mock_image_ctx.snap_info = {
149 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
150 {}, {}, {}}},
151 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
152 {}, {}, {}}}
153 };
154
155 InSequence seq;
156
157 expect_get_flags(mock_image_ctx, 1U, 0, 0);
158
159 BitVector<2> object_map_1;
160 object_map_1.resize(object_count);
161 object_map_1[1] = OBJECT_EXISTS_CLEAN;
162 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
163
164 expect_get_flags(mock_image_ctx, 2U, 0, 0);
165
166 BitVector<2> object_map_2;
167 object_map_2.resize(object_count);
168 object_map_2[1] = OBJECT_EXISTS_CLEAN;
169 object_map_2[2] = OBJECT_EXISTS;
170 object_map_2[3] = OBJECT_EXISTS;
171 expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
172
173 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
174
175 BitVector<2> object_map_head;
176 object_map_head.resize(object_count);
177 object_map_head[1] = OBJECT_EXISTS_CLEAN;
178 object_map_head[2] = OBJECT_EXISTS_CLEAN;
179 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
180
181 C_SaferCond ctx;
182 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
183 &m_object_diff_state, &ctx);
184 req->send();
185 ASSERT_EQ(0, ctx.wait());
186
187 BitVector<2> expected_diff_state;
188 expected_diff_state.resize(object_count);
189 expected_diff_state[1] = DIFF_STATE_UPDATED;
190 expected_diff_state[2] = DIFF_STATE_UPDATED;
191 expected_diff_state[3] = DIFF_STATE_HOLE;
192 ASSERT_EQ(expected_diff_state, m_object_diff_state);
193 }
194
195 TEST_F(TestMockObjectMapDiffRequest, IntermediateDelta) {
196 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
197
198 uint32_t object_count = 5;
199 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
200
201 MockTestImageCtx mock_image_ctx(*m_image_ctx);
202 mock_image_ctx.snap_info = {
203 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
204 {}, {}, {}}},
205 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
206 {}, {}, {}}}
207 };
208
209 InSequence seq;
210
211 expect_get_flags(mock_image_ctx, 1U, 0, 0);
212
213 BitVector<2> object_map_1;
214 object_map_1.resize(object_count);
215 object_map_1[1] = OBJECT_EXISTS_CLEAN;
216 object_map_1[2] = OBJECT_EXISTS_CLEAN;
217 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
218
219 expect_get_flags(mock_image_ctx, 2U, 0, 0);
220
221 BitVector<2> object_map_2;
222 object_map_2.resize(object_count);
223 object_map_2[1] = OBJECT_EXISTS_CLEAN;
224 object_map_2[2] = OBJECT_EXISTS;
225 object_map_2[3] = OBJECT_EXISTS;
226 expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
227
228 C_SaferCond ctx;
229 auto req = new MockDiffRequest(&mock_image_ctx, 1, 2,
230 &m_object_diff_state, &ctx);
231 req->send();
232 ASSERT_EQ(0, ctx.wait());
233
234 BitVector<2> expected_diff_state;
235 expected_diff_state.resize(object_count);
236 expected_diff_state[2] = DIFF_STATE_UPDATED;
237 expected_diff_state[3] = DIFF_STATE_UPDATED;
238 ASSERT_EQ(expected_diff_state, m_object_diff_state);
239 }
240
241 TEST_F(TestMockObjectMapDiffRequest, EndDelta) {
242 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
243
244 uint32_t object_count = 5;
245 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
246
247 MockTestImageCtx mock_image_ctx(*m_image_ctx);
248 mock_image_ctx.snap_info = {
249 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
250 {}, {}, {}}},
251 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
252 {}, {}, {}}}
253 };
254
255 InSequence seq;
256
257 expect_get_flags(mock_image_ctx, 2U, 0, 0);
258
259 BitVector<2> object_map_2;
260 object_map_2.resize(object_count);
261 object_map_2[1] = OBJECT_EXISTS_CLEAN;
262 object_map_2[2] = OBJECT_EXISTS;
263 object_map_2[3] = OBJECT_EXISTS;
264 expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
265
266 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
267
268 BitVector<2> object_map_head;
269 object_map_head.resize(object_count);
270 object_map_head[1] = OBJECT_EXISTS_CLEAN;
271 object_map_head[2] = OBJECT_EXISTS_CLEAN;
272 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
273
274 C_SaferCond ctx;
275 auto req = new MockDiffRequest(&mock_image_ctx, 2, CEPH_NOSNAP,
276 &m_object_diff_state, &ctx);
277 req->send();
278 ASSERT_EQ(0, ctx.wait());
279
280 BitVector<2> expected_diff_state;
281 expected_diff_state.resize(object_count);
282 expected_diff_state[3] = DIFF_STATE_HOLE;
283 ASSERT_EQ(expected_diff_state, m_object_diff_state);
284 }
285
286 TEST_F(TestMockObjectMapDiffRequest, StartSnapDNE) {
287 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
288
289 uint32_t object_count = 5;
290 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
291
292 MockTestImageCtx mock_image_ctx(*m_image_ctx);
293 mock_image_ctx.snap_info = {
294 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
295 {}, {}, {}}}
296 };
297
298 InSequence seq;
299
300 C_SaferCond ctx;
301 auto req = new MockDiffRequest(&mock_image_ctx, 1, CEPH_NOSNAP,
302 &m_object_diff_state, &ctx);
303 req->send();
304 ASSERT_EQ(-ENOENT, ctx.wait());
305 }
306
307 TEST_F(TestMockObjectMapDiffRequest, EndSnapDNE) {
308 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
309
310 uint32_t object_count = 5;
311 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
312
313 MockTestImageCtx mock_image_ctx(*m_image_ctx);
314 mock_image_ctx.snap_info = {
315 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
316 {}, {}, {}}}
317 };
318
319 InSequence seq;
320
321 expect_get_flags(mock_image_ctx, 1U, 0, 0);
322
323 BitVector<2> object_map_1;
324 object_map_1.resize(object_count);
325 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
326
327 C_SaferCond ctx;
328 auto req = new MockDiffRequest(&mock_image_ctx, 1, 2,
329 &m_object_diff_state, &ctx);
330 req->send();
331 ASSERT_EQ(-ENOENT, ctx.wait());
332 }
333
334 TEST_F(TestMockObjectMapDiffRequest, IntermediateSnapDNE) {
335 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
336
337 uint32_t object_count = 5;
338 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
339
340 MockTestImageCtx mock_image_ctx(*m_image_ctx);
341 mock_image_ctx.snap_info = {
342 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
343 {}, {}, {}}},
344 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
345 {}, {}, {}}}
346 };
347
348 InSequence seq;
349
350 expect_get_flags(mock_image_ctx, 1U, 0, 0);
351
352 BitVector<2> object_map_1;
353 object_map_1.resize(object_count);
354 object_map_1[1] = OBJECT_EXISTS_CLEAN;
355 expect_load_map(mock_image_ctx, 1U, object_map_1, 0,
356 [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); });
357
358 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
359
360 BitVector<2> object_map_head;
361 object_map_head.resize(object_count);
362 object_map_head[1] = OBJECT_EXISTS_CLEAN;
363 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
364
365 C_SaferCond ctx;
366 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
367 &m_object_diff_state, &ctx);
368 req->send();
369 ASSERT_EQ(0, ctx.wait());
370
371 BitVector<2> expected_diff_state;
372 expected_diff_state.resize(object_count);
373 expected_diff_state[1] = DIFF_STATE_UPDATED;
374 ASSERT_EQ(expected_diff_state, m_object_diff_state);
375 }
376
377 TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapDNE) {
378 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
379
380 uint32_t object_count = 5;
381 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
382
383 MockTestImageCtx mock_image_ctx(*m_image_ctx);
384
385 InSequence seq;
386
387 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
388
389 BitVector<2> object_map_head;
390 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, -ENOENT);
391
392 C_SaferCond ctx;
393 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
394 &m_object_diff_state, &ctx);
395 req->send();
396 ASSERT_EQ(-ENOENT, ctx.wait());
397 }
398
399 TEST_F(TestMockObjectMapDiffRequest, LoadIntermediateObjectMapDNE) {
400 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
401
402 uint32_t object_count = 5;
403 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
404
405 MockTestImageCtx mock_image_ctx(*m_image_ctx);
406 mock_image_ctx.snap_info = {
407 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
408 {}, {}, {}}}
409 };
410
411 InSequence seq;
412
413 expect_get_flags(mock_image_ctx, 1U, 0, 0);
414
415 BitVector<2> object_map_1;
416 expect_load_map(mock_image_ctx, 1U, object_map_1, -ENOENT);
417
418 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
419
420 BitVector<2> object_map_head;
421 object_map_head.resize(object_count);
422 object_map_head[1] = OBJECT_EXISTS_CLEAN;
423 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
424
425 C_SaferCond ctx;
426 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
427 &m_object_diff_state, &ctx);
428 req->send();
429 ASSERT_EQ(0, ctx.wait());
430
431 BitVector<2> expected_diff_state;
432 expected_diff_state.resize(object_count);
433 expected_diff_state[1] = DIFF_STATE_UPDATED;
434 ASSERT_EQ(expected_diff_state, m_object_diff_state);
435 }
436
437 TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapError) {
438 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
439
440 uint32_t object_count = 5;
441 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
442
443 MockTestImageCtx mock_image_ctx(*m_image_ctx);
444 mock_image_ctx.snap_info = {
445 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
446 {}, {}, {}}}
447 };
448
449 InSequence seq;
450
451 expect_get_flags(mock_image_ctx, 1U, 0, 0);
452
453 BitVector<2> object_map_1;
454 expect_load_map(mock_image_ctx, 1U, object_map_1, -EPERM);
455
456 C_SaferCond ctx;
457 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
458 &m_object_diff_state, &ctx);
459 req->send();
460 ASSERT_EQ(-EPERM, ctx.wait());
461 }
462
463 TEST_F(TestMockObjectMapDiffRequest, ObjectMapTooSmall) {
464 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
465
466 uint32_t object_count = 5;
467 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
468
469 MockTestImageCtx mock_image_ctx(*m_image_ctx);
470 mock_image_ctx.snap_info = {
471 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
472 {}, {}, {}}}
473 };
474
475 InSequence seq;
476
477 expect_get_flags(mock_image_ctx, 1U, 0, 0);
478
479 BitVector<2> object_map_1;
480 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
481
482 C_SaferCond ctx;
483 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
484 &m_object_diff_state, &ctx);
485 req->send();
486 ASSERT_EQ(-EINVAL, ctx.wait());
487 }
488
489 } // namespace object_map
490 } // librbd