]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/object_map/test_mock_DiffRequest.cc
update source to Ceph Pacific 16.2.2
[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_DATA_UPDATED;
190 expected_diff_state[2] = DIFF_STATE_DATA_UPDATED;
191 expected_diff_state[3] = DIFF_STATE_HOLE_UPDATED;
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[1] = DIFF_STATE_DATA;
237 expected_diff_state[2] = DIFF_STATE_DATA_UPDATED;
238 expected_diff_state[3] = DIFF_STATE_DATA_UPDATED;
239 ASSERT_EQ(expected_diff_state, m_object_diff_state);
240 }
241
242 TEST_F(TestMockObjectMapDiffRequest, EndDelta) {
243 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
244
245 uint32_t object_count = 5;
246 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
247
248 MockTestImageCtx mock_image_ctx(*m_image_ctx);
249 mock_image_ctx.snap_info = {
250 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
251 {}, {}, {}}},
252 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
253 {}, {}, {}}}
254 };
255
256 InSequence seq;
257
258 expect_get_flags(mock_image_ctx, 2U, 0, 0);
259
260 BitVector<2> object_map_2;
261 object_map_2.resize(object_count);
262 object_map_2[1] = OBJECT_EXISTS_CLEAN;
263 object_map_2[2] = OBJECT_EXISTS;
264 object_map_2[3] = OBJECT_EXISTS;
265 expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
266
267 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
268
269 BitVector<2> object_map_head;
270 object_map_head.resize(object_count);
271 object_map_head[1] = OBJECT_EXISTS_CLEAN;
272 object_map_head[2] = OBJECT_EXISTS_CLEAN;
273 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
274
275 C_SaferCond ctx;
276 auto req = new MockDiffRequest(&mock_image_ctx, 2, CEPH_NOSNAP,
277 &m_object_diff_state, &ctx);
278 req->send();
279 ASSERT_EQ(0, ctx.wait());
280
281 BitVector<2> expected_diff_state;
282 expected_diff_state.resize(object_count);
283 expected_diff_state[1] = DIFF_STATE_DATA;
284 expected_diff_state[2] = DIFF_STATE_DATA_UPDATED;
285 expected_diff_state[3] = DIFF_STATE_HOLE_UPDATED;
286 ASSERT_EQ(expected_diff_state, m_object_diff_state);
287 }
288
289 TEST_F(TestMockObjectMapDiffRequest, StartSnapDNE) {
290 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
291
292 uint32_t object_count = 5;
293 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
294
295 MockTestImageCtx mock_image_ctx(*m_image_ctx);
296 mock_image_ctx.snap_info = {
297 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
298 {}, {}, {}}}
299 };
300
301 InSequence seq;
302
303 C_SaferCond ctx;
304 auto req = new MockDiffRequest(&mock_image_ctx, 1, CEPH_NOSNAP,
305 &m_object_diff_state, &ctx);
306 req->send();
307 ASSERT_EQ(-ENOENT, ctx.wait());
308 }
309
310 TEST_F(TestMockObjectMapDiffRequest, EndSnapDNE) {
311 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
312
313 uint32_t object_count = 5;
314 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
315
316 MockTestImageCtx mock_image_ctx(*m_image_ctx);
317 mock_image_ctx.snap_info = {
318 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
319 {}, {}, {}}}
320 };
321
322 InSequence seq;
323
324 expect_get_flags(mock_image_ctx, 1U, 0, 0);
325
326 BitVector<2> object_map_1;
327 object_map_1.resize(object_count);
328 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
329
330 C_SaferCond ctx;
331 auto req = new MockDiffRequest(&mock_image_ctx, 1, 2,
332 &m_object_diff_state, &ctx);
333 req->send();
334 ASSERT_EQ(-ENOENT, ctx.wait());
335 }
336
337 TEST_F(TestMockObjectMapDiffRequest, IntermediateSnapDNE) {
338 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
339
340 uint32_t object_count = 5;
341 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
342
343 MockTestImageCtx mock_image_ctx(*m_image_ctx);
344 mock_image_ctx.snap_info = {
345 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
346 {}, {}, {}}},
347 {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
348 {}, {}, {}}}
349 };
350
351 InSequence seq;
352
353 expect_get_flags(mock_image_ctx, 1U, 0, 0);
354
355 BitVector<2> object_map_1;
356 object_map_1.resize(object_count);
357 object_map_1[1] = OBJECT_EXISTS_CLEAN;
358 expect_load_map(mock_image_ctx, 1U, object_map_1, 0,
359 [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); });
360
361 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
362
363 BitVector<2> object_map_head;
364 object_map_head.resize(object_count);
365 object_map_head[1] = OBJECT_EXISTS_CLEAN;
366 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
367
368 C_SaferCond ctx;
369 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
370 &m_object_diff_state, &ctx);
371 req->send();
372 ASSERT_EQ(0, ctx.wait());
373
374 BitVector<2> expected_diff_state;
375 expected_diff_state.resize(object_count);
376 expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
377 ASSERT_EQ(expected_diff_state, m_object_diff_state);
378 }
379
380 TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapDNE) {
381 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
382
383 uint32_t object_count = 5;
384 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
385
386 MockTestImageCtx mock_image_ctx(*m_image_ctx);
387
388 InSequence seq;
389
390 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
391
392 BitVector<2> object_map_head;
393 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, -ENOENT);
394
395 C_SaferCond ctx;
396 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
397 &m_object_diff_state, &ctx);
398 req->send();
399 ASSERT_EQ(-ENOENT, ctx.wait());
400 }
401
402 TEST_F(TestMockObjectMapDiffRequest, LoadIntermediateObjectMapDNE) {
403 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
404
405 uint32_t object_count = 5;
406 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
407
408 MockTestImageCtx mock_image_ctx(*m_image_ctx);
409 mock_image_ctx.snap_info = {
410 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
411 {}, {}, {}}}
412 };
413
414 InSequence seq;
415
416 expect_get_flags(mock_image_ctx, 1U, 0, 0);
417
418 BitVector<2> object_map_1;
419 expect_load_map(mock_image_ctx, 1U, object_map_1, -ENOENT);
420
421 expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
422
423 BitVector<2> object_map_head;
424 object_map_head.resize(object_count);
425 object_map_head[1] = OBJECT_EXISTS_CLEAN;
426 expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
427
428 C_SaferCond ctx;
429 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
430 &m_object_diff_state, &ctx);
431 req->send();
432 ASSERT_EQ(0, ctx.wait());
433
434 BitVector<2> expected_diff_state;
435 expected_diff_state.resize(object_count);
436 expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
437 ASSERT_EQ(expected_diff_state, m_object_diff_state);
438 }
439
440 TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapError) {
441 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
442
443 uint32_t object_count = 5;
444 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
445
446 MockTestImageCtx mock_image_ctx(*m_image_ctx);
447 mock_image_ctx.snap_info = {
448 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
449 {}, {}, {}}}
450 };
451
452 InSequence seq;
453
454 expect_get_flags(mock_image_ctx, 1U, 0, 0);
455
456 BitVector<2> object_map_1;
457 expect_load_map(mock_image_ctx, 1U, object_map_1, -EPERM);
458
459 C_SaferCond ctx;
460 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
461 &m_object_diff_state, &ctx);
462 req->send();
463 ASSERT_EQ(-EPERM, ctx.wait());
464 }
465
466 TEST_F(TestMockObjectMapDiffRequest, ObjectMapTooSmall) {
467 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
468
469 uint32_t object_count = 5;
470 m_image_ctx->size = object_count * (1 << m_image_ctx->order);
471
472 MockTestImageCtx mock_image_ctx(*m_image_ctx);
473 mock_image_ctx.snap_info = {
474 {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
475 {}, {}, {}}}
476 };
477
478 InSequence seq;
479
480 expect_get_flags(mock_image_ctx, 1U, 0, 0);
481
482 BitVector<2> object_map_1;
483 expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
484
485 C_SaferCond ctx;
486 auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
487 &m_object_diff_state, &ctx);
488 req->send();
489 ASSERT_EQ(-EINVAL, ctx.wait());
490 }
491
492 } // namespace object_map
493 } // librbd