]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ImageRequest.cc
d1390bcf85d85eeae893a75c75eb84cf270bf81a
[ceph.git] / ceph / src / test / librbd / io / test_mock_ImageRequest.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/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/MockJournal.h"
8 #include "test/librbd/mock/cache/MockImageCache.h"
9 #include "librbd/io/ImageRequest.h"
10 #include "librbd/io/ObjectDispatchSpec.h"
11 #include "librbd/io/Utils.h"
12
13 namespace librbd {
14 namespace {
15
16 struct MockTestImageCtx;
17
18 struct MockTestJournal : public MockJournal {
19 MOCK_METHOD4(append_write_event, uint64_t(uint64_t, size_t,
20 const bufferlist &, bool));
21 MOCK_METHOD5(append_io_event_mock, uint64_t(const journal::EventEntry&,
22 uint64_t, size_t, bool, int));
23 uint64_t append_io_event(journal::EventEntry &&event_entry,
24 uint64_t offset, size_t length,
25 bool flush_entry, int filter_ret_val) {
26 // googlemock doesn't support move semantics
27 return append_io_event_mock(event_entry, offset, length, flush_entry,
28 filter_ret_val);
29 }
30
31 MOCK_METHOD2(commit_io_event, void(uint64_t, int));
32 };
33
34 struct MockTestImageCtx : public MockImageCtx {
35 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
36 }
37
38 MockTestJournal* journal;
39 };
40
41 } // anonymous namespace
42
43 namespace util {
44
45 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
46 return image_ctx->image_ctx;
47 }
48
49 } // namespace util
50 } // namespace librbd
51
52 #include "librbd/io/ImageRequest.cc"
53
54 namespace librbd {
55 namespace io {
56
57 namespace util {
58
59 template<>
60 void file_to_extents(
61 MockTestImageCtx *image_ctx, uint64_t offset, uint64_t length,
62 uint64_t buffer_offset,
63 striper::LightweightObjectExtents *object_extents) {
64 Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length,
65 0, buffer_offset, object_extents);
66 }
67
68 template <> void extent_to_file(
69 MockTestImageCtx* image_ctx, uint64_t object_no, uint64_t offset,
70 uint64_t length,
71 std::vector<std::pair<uint64_t, uint64_t> >& extents) {
72 Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no,
73 offset, length, extents);
74 }
75
76 } // namespace util
77
78 using ::testing::_;
79 using ::testing::InSequence;
80 using ::testing::Invoke;
81 using ::testing::Return;
82 using ::testing::WithArg;
83 using ::testing::WithoutArgs;
84 using ::testing::Exactly;
85
86 struct TestMockIoImageRequest : public TestMockFixture {
87 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
88 typedef ImageReadRequest<librbd::MockTestImageCtx> MockImageReadRequest;
89 typedef ImageWriteRequest<librbd::MockTestImageCtx> MockImageWriteRequest;
90 typedef ImageDiscardRequest<librbd::MockTestImageCtx> MockImageDiscardRequest;
91 typedef ImageFlushRequest<librbd::MockTestImageCtx> MockImageFlushRequest;
92 typedef ImageWriteSameRequest<librbd::MockTestImageCtx> MockImageWriteSameRequest;
93 typedef ImageCompareAndWriteRequest<librbd::MockTestImageCtx> MockImageCompareAndWriteRequest;
94 typedef ImageListSnapsRequest<librbd::MockTestImageCtx> MockImageListSnapsRequest;
95
96 void expect_is_journal_appending(MockTestJournal &mock_journal, bool appending) {
97 EXPECT_CALL(mock_journal, is_journal_appending())
98 .WillOnce(Return(appending));
99 }
100
101 void expect_get_modify_timestamp(MockTestImageCtx &mock_image_ctx,
102 bool needs_update) {
103 if (needs_update) {
104 mock_image_ctx.mtime_update_interval = 5;
105 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
106 .WillOnce(Return(ceph_clock_now() - utime_t(10,0)));
107 } else {
108 mock_image_ctx.mtime_update_interval = 600;
109 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
110 .WillOnce(Return(ceph_clock_now()));
111 }
112 }
113
114 void expect_object_discard_request(MockTestImageCtx &mock_image_ctx,
115 uint64_t object_no, uint64_t offset,
116 uint32_t length, int r) {
117 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
118 .WillOnce(Invoke([&mock_image_ctx, object_no, offset, length, r]
119 (ObjectDispatchSpec* spec) {
120 auto* discard_spec = boost::get<ObjectDispatchSpec::DiscardRequest>(&spec->request);
121 ASSERT_TRUE(discard_spec != nullptr);
122 ASSERT_EQ(object_no, discard_spec->object_no);
123 ASSERT_EQ(offset, discard_spec->object_off);
124 ASSERT_EQ(length, discard_spec->object_len);
125
126 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
127 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
128 }));
129 }
130
131 void expect_object_request_send(MockTestImageCtx &mock_image_ctx,
132 int r) {
133 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
134 .WillOnce(Invoke([&mock_image_ctx, r](ObjectDispatchSpec* spec) {
135 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
136 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
137 }));
138 }
139
140 void expect_object_list_snaps_request(MockTestImageCtx &mock_image_ctx,
141 uint64_t object_no,
142 const SnapshotDelta& snap_delta,
143 int r) {
144 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
145 .WillOnce(
146 Invoke([&mock_image_ctx, object_no, snap_delta, r]
147 (ObjectDispatchSpec* spec) {
148 auto request = boost::get<
149 librbd::io::ObjectDispatchSpec::ListSnapsRequest>(
150 &spec->request);
151 ASSERT_TRUE(request != nullptr);
152 ASSERT_EQ(object_no, request->object_no);
153
154 *request->snapshot_delta = snap_delta;
155 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
156 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
157 }));
158 }
159 };
160
161 TEST_F(TestMockIoImageRequest, AioWriteModifyTimestamp) {
162 REQUIRE_FORMAT_V2();
163
164 librbd::ImageCtx *ictx;
165 ASSERT_EQ(0, open_image(m_image_name, &ictx));
166
167 MockTestImageCtx mock_image_ctx(*ictx);
168 MockTestJournal mock_journal;
169 mock_image_ctx.journal = &mock_journal;
170
171 mock_image_ctx.mtime_update_interval = 5;
172
173 utime_t dummy = ceph_clock_now();
174 dummy -= utime_t(10,0);
175
176 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
177 .Times(Exactly(3))
178 .WillOnce(Return(dummy))
179 .WillOnce(Return(dummy))
180 .WillOnce(Return(dummy + utime_t(10,0)));
181
182 EXPECT_CALL(mock_image_ctx, set_modify_timestamp(_))
183 .Times(Exactly(1));
184
185 InSequence seq;
186 expect_is_journal_appending(mock_journal, false);
187 expect_object_request_send(mock_image_ctx, 0);
188
189 C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2;
190 AioCompletion *aio_comp_1 = AioCompletion::create_and_start(
191 &aio_comp_ctx_1, ictx, AIO_TYPE_WRITE);
192
193 AioCompletion *aio_comp_2 = AioCompletion::create_and_start(
194 &aio_comp_ctx_2, ictx, AIO_TYPE_WRITE);
195
196 bufferlist bl;
197 bl.append("1");
198 MockImageWriteRequest mock_aio_image_write_1(
199 mock_image_ctx, aio_comp_1, {{0, 1}}, std::move(bl),
200 mock_image_ctx.get_data_io_context(), 0, {});
201 {
202 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
203 mock_aio_image_write_1.send();
204 }
205 ASSERT_EQ(0, aio_comp_ctx_1.wait());
206
207 expect_is_journal_appending(mock_journal, false);
208 expect_object_request_send(mock_image_ctx, 0);
209
210 bl.append("1");
211 MockImageWriteRequest mock_aio_image_write_2(
212 mock_image_ctx, aio_comp_2, {{0, 1}}, std::move(bl),
213 mock_image_ctx.get_data_io_context(), 0, {});
214 {
215 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
216 mock_aio_image_write_2.send();
217 }
218 ASSERT_EQ(0, aio_comp_ctx_2.wait());
219 }
220
221 TEST_F(TestMockIoImageRequest, AioReadAccessTimestamp) {
222 REQUIRE_FORMAT_V2();
223
224 librbd::ImageCtx *ictx;
225 ASSERT_EQ(0, open_image(m_image_name, &ictx));
226
227 MockTestImageCtx mock_image_ctx(*ictx);
228 MockTestJournal mock_journal;
229 mock_image_ctx.journal = &mock_journal;
230
231 mock_image_ctx.atime_update_interval = 5;
232
233 utime_t dummy = ceph_clock_now();
234 dummy -= utime_t(10,0);
235
236 EXPECT_CALL(mock_image_ctx, get_access_timestamp())
237 .Times(Exactly(3))
238 .WillOnce(Return(dummy))
239 .WillOnce(Return(dummy))
240 .WillOnce(Return(dummy + utime_t(10,0)));
241
242 EXPECT_CALL(mock_image_ctx, set_access_timestamp(_))
243 .Times(Exactly(1));
244
245 InSequence seq;
246 expect_object_request_send(mock_image_ctx, 0);
247
248 C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2;
249 AioCompletion *aio_comp_1 = AioCompletion::create_and_start(
250 &aio_comp_ctx_1, ictx, AIO_TYPE_READ);
251
252
253 ReadResult rr;
254 MockImageReadRequest mock_aio_image_read_1(
255 mock_image_ctx, aio_comp_1, {{0, 1}}, std::move(rr),
256 mock_image_ctx.get_data_io_context(), 0, 0, {});
257 {
258 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
259 mock_aio_image_read_1.send();
260 }
261 ASSERT_EQ(1, aio_comp_ctx_1.wait());
262
263 AioCompletion *aio_comp_2 = AioCompletion::create_and_start(
264 &aio_comp_ctx_2, ictx, AIO_TYPE_READ);
265 expect_object_request_send(mock_image_ctx, 0);
266
267 MockImageReadRequest mock_aio_image_read_2(
268 mock_image_ctx, aio_comp_2, {{0, 1}}, std::move(rr),
269 mock_image_ctx.get_data_io_context(), 0, 0, {});
270 {
271 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
272 mock_aio_image_read_2.send();
273 }
274 ASSERT_EQ(1, aio_comp_ctx_2.wait());
275 }
276
277 TEST_F(TestMockIoImageRequest, PartialDiscard) {
278 librbd::ImageCtx *ictx;
279 ASSERT_EQ(0, open_image(m_image_name, &ictx));
280 ictx->discard_granularity_bytes = 0;
281
282 MockTestImageCtx mock_image_ctx(*ictx);
283 mock_image_ctx.journal = nullptr;
284
285 InSequence seq;
286 expect_get_modify_timestamp(mock_image_ctx, false);
287 expect_object_discard_request(mock_image_ctx, 0, 16, 63, 0);
288 expect_object_discard_request(mock_image_ctx, 0, 84, 100, 0);
289
290 C_SaferCond aio_comp_ctx;
291 AioCompletion *aio_comp = AioCompletion::create_and_start(
292 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
293 MockImageDiscardRequest mock_aio_image_discard(
294 mock_image_ctx, aio_comp, {{16, 63}, {84, 100}},
295 ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {});
296 {
297 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
298 mock_aio_image_discard.send();
299 }
300 ASSERT_EQ(0, aio_comp_ctx.wait());
301 }
302
303 TEST_F(TestMockIoImageRequest, TailDiscard) {
304 librbd::ImageCtx *ictx;
305 ASSERT_EQ(0, open_image(m_image_name, &ictx));
306 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
307 ictx->discard_granularity_bytes = 2 * ictx->layout.object_size;
308
309 MockTestImageCtx mock_image_ctx(*ictx);
310 mock_image_ctx.journal = nullptr;
311
312 InSequence seq;
313 expect_get_modify_timestamp(mock_image_ctx, false);
314 expect_object_discard_request(
315 mock_image_ctx, 0, ictx->layout.object_size - 1024, 1024, 0);
316
317 C_SaferCond aio_comp_ctx;
318 AioCompletion *aio_comp = AioCompletion::create_and_start(
319 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
320 MockImageDiscardRequest mock_aio_image_discard(
321 mock_image_ctx, aio_comp,
322 {{ictx->layout.object_size - 1024, 1024}},
323 ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {});
324 {
325 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
326 mock_aio_image_discard.send();
327 }
328 ASSERT_EQ(0, aio_comp_ctx.wait());
329 }
330
331 TEST_F(TestMockIoImageRequest, DiscardGranularity) {
332 librbd::ImageCtx *ictx;
333 ASSERT_EQ(0, open_image(m_image_name, &ictx));
334 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
335 ictx->discard_granularity_bytes = 32;
336
337 MockTestImageCtx mock_image_ctx(*ictx);
338 mock_image_ctx.journal = nullptr;
339
340 InSequence seq;
341 expect_get_modify_timestamp(mock_image_ctx, false);
342 expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0);
343 expect_object_discard_request(mock_image_ctx, 0, 96, 64, 0);
344 expect_object_discard_request(
345 mock_image_ctx, 0, ictx->layout.object_size - 32, 32, 0);
346
347 C_SaferCond aio_comp_ctx;
348 AioCompletion *aio_comp = AioCompletion::create_and_start(
349 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
350 MockImageDiscardRequest mock_aio_image_discard(
351 mock_image_ctx, aio_comp,
352 {{16, 63}, {96, 31}, {84, 100}, {ictx->layout.object_size - 33, 33}},
353 ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {});
354 {
355 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
356 mock_aio_image_discard.send();
357 }
358 ASSERT_EQ(0, aio_comp_ctx.wait());
359 }
360
361 TEST_F(TestMockIoImageRequest, AioWriteJournalAppendDisabled) {
362 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
363
364 librbd::ImageCtx *ictx;
365 ASSERT_EQ(0, open_image(m_image_name, &ictx));
366
367 MockTestImageCtx mock_image_ctx(*ictx);
368 MockTestJournal mock_journal;
369 mock_image_ctx.journal = &mock_journal;
370
371 InSequence seq;
372 expect_get_modify_timestamp(mock_image_ctx, false);
373 expect_is_journal_appending(mock_journal, false);
374 expect_object_request_send(mock_image_ctx, 0);
375
376 C_SaferCond aio_comp_ctx;
377 AioCompletion *aio_comp = AioCompletion::create_and_start(
378 &aio_comp_ctx, ictx, AIO_TYPE_WRITE);
379
380 bufferlist bl;
381 bl.append("1");
382 MockImageWriteRequest mock_aio_image_write(
383 mock_image_ctx, aio_comp, {{0, 1}}, std::move(bl),
384 mock_image_ctx.get_data_io_context(), 0, {});
385 {
386 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
387 mock_aio_image_write.send();
388 }
389 ASSERT_EQ(0, aio_comp_ctx.wait());
390 }
391
392 TEST_F(TestMockIoImageRequest, AioDiscardJournalAppendDisabled) {
393 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
394
395 librbd::ImageCtx *ictx;
396 ASSERT_EQ(0, open_image(m_image_name, &ictx));
397 ictx->discard_granularity_bytes = 0;
398
399 MockTestImageCtx mock_image_ctx(*ictx);
400 MockTestJournal mock_journal;
401 mock_image_ctx.journal = &mock_journal;
402
403 InSequence seq;
404 expect_get_modify_timestamp(mock_image_ctx, false);
405 expect_is_journal_appending(mock_journal, false);
406 expect_object_request_send(mock_image_ctx, 0);
407
408 C_SaferCond aio_comp_ctx;
409 AioCompletion *aio_comp = AioCompletion::create_and_start(
410 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
411 MockImageDiscardRequest mock_aio_image_discard(
412 mock_image_ctx, aio_comp, {{0, 1}}, ictx->discard_granularity_bytes,
413 mock_image_ctx.get_data_io_context(), {});
414 {
415 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
416 mock_aio_image_discard.send();
417 }
418 ASSERT_EQ(0, aio_comp_ctx.wait());
419 }
420
421 TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) {
422 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
423
424 librbd::ImageCtx *ictx;
425 ASSERT_EQ(0, open_image(m_image_name, &ictx));
426
427 MockTestImageCtx mock_image_ctx(*ictx);
428 MockTestJournal mock_journal;
429 mock_image_ctx.journal = &mock_journal;
430
431 expect_op_work_queue(mock_image_ctx);
432
433 InSequence seq;
434 expect_is_journal_appending(mock_journal, false);
435 expect_object_request_send(mock_image_ctx, 0);
436
437 C_SaferCond aio_comp_ctx;
438 AioCompletion *aio_comp = AioCompletion::create_and_start(
439 &aio_comp_ctx, ictx, AIO_TYPE_FLUSH);
440 MockImageFlushRequest mock_aio_image_flush(mock_image_ctx, aio_comp,
441 FLUSH_SOURCE_USER, {});
442 {
443 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
444 mock_aio_image_flush.send();
445 }
446 ASSERT_EQ(0, aio_comp_ctx.wait());
447 }
448
449 TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) {
450 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
451
452 librbd::ImageCtx *ictx;
453 ASSERT_EQ(0, open_image(m_image_name, &ictx));
454
455 MockTestImageCtx mock_image_ctx(*ictx);
456 MockTestJournal mock_journal;
457 mock_image_ctx.journal = &mock_journal;
458
459 InSequence seq;
460 expect_get_modify_timestamp(mock_image_ctx, false);
461 expect_is_journal_appending(mock_journal, false);
462 expect_object_request_send(mock_image_ctx, 0);
463
464 C_SaferCond aio_comp_ctx;
465 AioCompletion *aio_comp = AioCompletion::create_and_start(
466 &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME);
467
468 bufferlist bl;
469 bl.append("1");
470 MockImageWriteSameRequest mock_aio_image_writesame(
471 mock_image_ctx, aio_comp, {{0, 1}}, std::move(bl),
472 mock_image_ctx.get_data_io_context(), 0, {});
473 {
474 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
475 mock_aio_image_writesame.send();
476 }
477 ASSERT_EQ(0, aio_comp_ctx.wait());
478 }
479
480 TEST_F(TestMockIoImageRequest, AioCompareAndWriteJournalAppendDisabled) {
481 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
482
483 librbd::ImageCtx *ictx;
484 ASSERT_EQ(0, open_image(m_image_name, &ictx));
485
486 MockTestImageCtx mock_image_ctx(*ictx);
487 MockTestJournal mock_journal;
488 mock_image_ctx.journal = &mock_journal;
489
490 InSequence seq;
491 expect_get_modify_timestamp(mock_image_ctx, false);
492 expect_is_journal_appending(mock_journal, false);
493 expect_object_request_send(mock_image_ctx, 0);
494
495 C_SaferCond aio_comp_ctx;
496 AioCompletion *aio_comp = AioCompletion::create_and_start(
497 &aio_comp_ctx, ictx, AIO_TYPE_COMPARE_AND_WRITE);
498
499 bufferlist cmp_bl;
500 cmp_bl.append("1");
501 bufferlist write_bl;
502 write_bl.append("1");
503 uint64_t mismatch_offset;
504 MockImageCompareAndWriteRequest mock_aio_image_write(
505 mock_image_ctx, aio_comp, {{0, 1}}, std::move(cmp_bl), std::move(write_bl),
506 &mismatch_offset, mock_image_ctx.get_data_io_context(), 0, {});
507 {
508 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
509 mock_aio_image_write.send();
510 }
511 ASSERT_EQ(0, aio_comp_ctx.wait());
512 }
513
514 TEST_F(TestMockIoImageRequest, ListSnaps) {
515 librbd::ImageCtx *ictx;
516 ASSERT_EQ(0, open_image(m_image_name, &ictx));
517
518 MockTestImageCtx mock_image_ctx(*ictx);
519 mock_image_ctx.layout.object_size = 16384;
520 mock_image_ctx.layout.stripe_unit = 4096;
521 mock_image_ctx.layout.stripe_count = 2;
522
523 InSequence seq;
524
525 SnapshotDelta object_snapshot_delta;
526 object_snapshot_delta[{5,6}].insert(
527 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
528 object_snapshot_delta[{5,5}].insert(
529 4096, 4096, {SPARSE_EXTENT_STATE_ZEROED, 4096});
530 expect_object_list_snaps_request(mock_image_ctx, 0, object_snapshot_delta, 0);
531 object_snapshot_delta = {};
532 object_snapshot_delta[{5,6}].insert(
533 1024, 3072, {SPARSE_EXTENT_STATE_DATA, 3072});
534 object_snapshot_delta[{5,5}].insert(
535 2048, 2048, {SPARSE_EXTENT_STATE_ZEROED, 2048});
536 expect_object_list_snaps_request(mock_image_ctx, 1, object_snapshot_delta, 0);
537
538 SnapshotDelta snapshot_delta;
539 C_SaferCond aio_comp_ctx;
540 AioCompletion *aio_comp = AioCompletion::create_and_start(
541 &aio_comp_ctx, ictx, AIO_TYPE_GENERIC);
542 MockImageListSnapsRequest mock_image_list_snaps_request(
543 mock_image_ctx, aio_comp, {{0, 16384}, {16384, 16384}}, {0, CEPH_NOSNAP},
544 0, &snapshot_delta, {});
545 {
546 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
547 mock_image_list_snaps_request.send();
548 }
549 ASSERT_EQ(0, aio_comp_ctx.wait());
550
551 SnapshotDelta expected_snapshot_delta;
552 expected_snapshot_delta[{5,6}].insert(
553 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
554 expected_snapshot_delta[{5,6}].insert(
555 5120, 3072, {SPARSE_EXTENT_STATE_DATA, 3072});
556 expected_snapshot_delta[{5,5}].insert(
557 6144, 6144, {SPARSE_EXTENT_STATE_ZEROED, 6144});
558 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
559 }
560
561 } // namespace io
562 } // namespace librbd