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/mock/MockObjectMap.h"
8 #include "test/librbd/mock/cache/MockImageCache.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "include/rbd/librbd.hpp"
12 #include "librbd/io/CopyupRequest.h"
13 #include "librbd/io/ImageRequest.h"
14 #include "librbd/io/ObjectRequest.h"
19 struct MockTestImageCtx
: public MockImageCtx
{
20 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
24 } // anonymous namespace
28 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
29 return image_ctx
->image_ctx
;
37 struct CopyupRequest
<librbd::MockImageCtx
> {
38 MOCK_METHOD0(send
, void());
39 MOCK_METHOD1(append_request
, void(AbstractObjectWriteRequest
<librbd::MockTestImageCtx
>*));
43 struct CopyupRequest
<librbd::MockTestImageCtx
> : public CopyupRequest
<librbd::MockImageCtx
> {
44 static CopyupRequest
* s_instance
;
45 static CopyupRequest
* create(librbd::MockTestImageCtx
*ictx
,
46 const std::string
&oid
, uint64_t objectno
,
47 Extents
&&image_extents
,
48 const ZTracer::Trace
&parent_trace
) {
58 struct ImageRequest
<librbd::MockTestImageCtx
> {
59 static ImageRequest
*s_instance
;
60 static void aio_read(librbd::MockImageCtx
*ictx
, AioCompletion
*c
,
61 Extents
&&image_extents
, ReadResult
&&read_result
,
62 int op_flags
, const ZTracer::Trace
&parent_trace
) {
63 s_instance
->aio_read(c
, image_extents
);
66 MOCK_METHOD2(aio_read
, void(AioCompletion
*, const Extents
&));
73 CopyupRequest
<librbd::MockTestImageCtx
>* CopyupRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
74 ImageRequest
<librbd::MockTestImageCtx
>* ImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
79 #include "librbd/io/ObjectRequest.cc"
85 using ::testing::DoDefault
;
86 using ::testing::InSequence
;
87 using ::testing::Invoke
;
88 using ::testing::Return
;
89 using ::testing::WithArg
;
90 using ::testing::WithArgs
;
92 struct TestMockIoObjectRequest
: public TestMockFixture
{
93 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
94 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
95 typedef ObjectWriteRequest
<librbd::MockTestImageCtx
> MockObjectWriteRequest
;
96 typedef ObjectDiscardRequest
<librbd::MockTestImageCtx
> MockObjectDiscardRequest
;
97 typedef ObjectWriteSameRequest
<librbd::MockTestImageCtx
> MockObjectWriteSameRequest
;
98 typedef ObjectCompareAndWriteRequest
<librbd::MockTestImageCtx
> MockObjectCompareAndWriteRequest
;
99 typedef AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> MockAbstractObjectWriteRequest
;
100 typedef CopyupRequest
<librbd::MockTestImageCtx
> MockCopyupRequest
;
101 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
103 void expect_object_may_exist(MockTestImageCtx
&mock_image_ctx
,
104 uint64_t object_no
, bool exists
) {
105 if (mock_image_ctx
.object_map
!= nullptr) {
106 EXPECT_CALL(*mock_image_ctx
.object_map
, object_may_exist(object_no
))
107 .WillOnce(Return(exists
));
111 void expect_get_object_size(MockTestImageCtx
&mock_image_ctx
) {
112 EXPECT_CALL(mock_image_ctx
, get_object_size()).WillRepeatedly(Return(
113 mock_image_ctx
.layout
.object_size
));
116 void expect_get_parent_overlap(MockTestImageCtx
&mock_image_ctx
,
117 librados::snap_t snap_id
, uint64_t overlap
,
119 EXPECT_CALL(mock_image_ctx
, get_parent_overlap(snap_id
, _
))
120 .WillOnce(WithArg
<1>(Invoke([overlap
, r
](uint64_t *o
) {
126 void expect_prune_parent_extents(MockTestImageCtx
&mock_image_ctx
,
127 const Extents
& extents
,
128 uint64_t overlap
, uint64_t object_overlap
) {
129 EXPECT_CALL(mock_image_ctx
, prune_parent_extents(_
, overlap
))
130 .WillOnce(WithArg
<0>(Invoke([extents
, object_overlap
](Extents
& e
) {
132 return object_overlap
;
136 void expect_get_read_flags(MockTestImageCtx
&mock_image_ctx
,
137 librados::snap_t snap_id
, int flags
) {
138 EXPECT_CALL(mock_image_ctx
, get_read_flags(snap_id
))
139 .WillOnce(Return(flags
));
142 void expect_is_lock_owner(MockExclusiveLock
& mock_exclusive_lock
) {
143 EXPECT_CALL(mock_exclusive_lock
, is_lock_owner()).WillRepeatedly(
147 void expect_read(MockTestImageCtx
&mock_image_ctx
,
148 const std::string
& oid
, uint64_t off
, uint64_t len
,
149 const std::string
& data
, int r
) {
153 auto& expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
154 read(oid
, len
, off
, _
));
156 expect
.WillOnce(Return(r
));
158 expect
.WillOnce(WithArg
<3>(Invoke([bl
](bufferlist
*out_bl
) {
165 void expect_sparse_read(MockTestImageCtx
&mock_image_ctx
,
166 const std::string
& oid
, uint64_t off
, uint64_t len
,
167 const std::string
& data
, int r
) {
171 auto& expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
172 sparse_read(oid
, off
, len
, _
, _
));
174 expect
.WillOnce(Return(r
));
176 expect
.WillOnce(WithArg
<4>(Invoke([bl
](bufferlist
*out_bl
) {
183 void expect_cache_read(MockTestImageCtx
&mock_image_ctx
,
184 const std::string
& oid
, uint64_t object_no
,
185 uint64_t off
, uint64_t len
, const std::string
& data
,
190 EXPECT_CALL(mock_image_ctx
, aio_read_from_cache({oid
}, object_no
, _
, len
,
192 .WillOnce(WithArgs
<2, 5>(Invoke([bl
, r
](bufferlist
*out_bl
,
193 Context
*on_finish
) {
195 on_finish
->complete(r
);
199 void expect_aio_read(MockImageRequest
& mock_image_request
,
200 Extents
&& extents
, int r
) {
201 EXPECT_CALL(mock_image_request
, aio_read(_
, extents
))
202 .WillOnce(WithArg
<0>(Invoke([r
](AioCompletion
* aio_comp
) {
203 aio_comp
->set_request_count(1);
204 aio_comp
->add_request();
205 aio_comp
->complete_request(r
);
209 void expect_copyup(MockCopyupRequest
& mock_copyup_request
, int r
) {
210 EXPECT_CALL(mock_copyup_request
, send())
211 .WillOnce(Invoke([&mock_copyup_request
, r
]() {
215 void expect_copyup(MockCopyupRequest
& mock_copyup_request
,
216 MockAbstractObjectWriteRequest
** write_request
, int r
) {
217 EXPECT_CALL(mock_copyup_request
, append_request(_
))
218 .WillOnce(Invoke([write_request
](MockAbstractObjectWriteRequest
*req
) {
219 *write_request
= req
;
221 EXPECT_CALL(mock_copyup_request
, send())
222 .WillOnce(Invoke([write_request
, r
]() {
223 (*write_request
)->handle_copyup(r
);
227 void expect_object_map_update(MockTestImageCtx
&mock_image_ctx
,
228 uint64_t start_object
, uint64_t end_object
,
230 const boost::optional
<uint8_t> ¤t_state
,
231 bool updated
, int ret_val
) {
232 if (mock_image_ctx
.object_map
!= nullptr) {
233 EXPECT_CALL(*mock_image_ctx
.object_map
,
234 aio_update(CEPH_NOSNAP
, start_object
, end_object
, state
,
235 current_state
, _
, _
))
236 .WillOnce(WithArg
<6>(Invoke([&mock_image_ctx
, updated
, ret_val
](Context
*ctx
) {
238 mock_image_ctx
.op_work_queue
->queue(ctx
, ret_val
);
245 void expect_assert_exists(MockTestImageCtx
&mock_image_ctx
, int r
) {
246 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
), assert_exists(_
))
247 .WillOnce(Return(r
));
250 void expect_write(MockTestImageCtx
&mock_image_ctx
,
251 uint64_t offset
, uint64_t length
, int r
) {
252 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
253 write(_
, _
, length
, offset
, _
));
255 expect
.WillOnce(Return(r
));
257 expect
.WillOnce(DoDefault());
261 void expect_write_full(MockTestImageCtx
&mock_image_ctx
, int r
) {
262 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
263 write_full(_
, _
, _
));
265 expect
.WillOnce(Return(r
));
267 expect
.WillOnce(DoDefault());
271 void expect_writesame(MockTestImageCtx
&mock_image_ctx
,
272 uint64_t offset
, uint64_t length
, int r
) {
273 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
274 writesame(_
, _
, length
, offset
, _
));
276 expect
.WillOnce(Return(r
));
278 expect
.WillOnce(DoDefault());
282 void expect_remove(MockTestImageCtx
&mock_image_ctx
, int r
) {
283 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
286 expect
.WillOnce(Return(r
));
288 expect
.WillOnce(DoDefault());
292 void expect_truncate(MockTestImageCtx
&mock_image_ctx
, int offset
, int r
) {
293 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
294 truncate(_
, offset
, _
));
296 expect
.WillOnce(Return(r
));
298 expect
.WillOnce(DoDefault());
302 void expect_zero(MockTestImageCtx
&mock_image_ctx
, int offset
, int length
,
304 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
305 zero(_
, offset
, length
, _
));
307 expect
.WillOnce(Return(r
));
309 expect
.WillOnce(DoDefault());
313 void expect_cmpext(MockTestImageCtx
&mock_image_ctx
, int offset
, int r
) {
314 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
315 cmpext(_
, offset
, _
));
317 expect
.WillOnce(Return(r
));
319 expect
.WillOnce(DoDefault());
324 TEST_F(TestMockIoObjectRequest
, Read
) {
325 librbd::ImageCtx
*ictx
;
326 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
327 ictx
->sparse_read_threshold_bytes
= 8096;
329 MockTestImageCtx
mock_image_ctx(*ictx
);
330 mock_image_ctx
.object_cacher
= nullptr;
332 MockObjectMap mock_object_map
;
333 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
334 mock_image_ctx
.object_map
= &mock_object_map
;
338 expect_object_may_exist(mock_image_ctx
, 0, true);
339 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
340 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096,
341 std::string(4096, '1'), 0);
344 auto req
= MockObjectReadRequest::create(
345 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
348 ASSERT_EQ(0, ctx
.wait());
351 TEST_F(TestMockIoObjectRequest
, SparseReadThreshold
) {
352 librbd::ImageCtx
*ictx
;
353 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
354 ictx
->sparse_read_threshold_bytes
= ictx
->get_object_size();
356 MockTestImageCtx
mock_image_ctx(*ictx
);
357 mock_image_ctx
.object_cacher
= nullptr;
359 MockObjectMap mock_object_map
;
360 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
361 mock_image_ctx
.object_map
= &mock_object_map
;
365 expect_object_may_exist(mock_image_ctx
, 0, true);
366 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
367 expect_sparse_read(mock_image_ctx
, ictx
->get_object_name(0), 0,
368 ictx
->sparse_read_threshold_bytes
,
369 std::string(ictx
->sparse_read_threshold_bytes
, '1'), 0);
372 auto req
= MockObjectReadRequest::create(
373 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0,
374 ictx
->sparse_read_threshold_bytes
, CEPH_NOSNAP
, 0, false, {}, &ctx
);
376 ASSERT_EQ(0, ctx
.wait());
379 TEST_F(TestMockIoObjectRequest
, ReadError
) {
380 librbd::ImageCtx
*ictx
;
381 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
382 ictx
->sparse_read_threshold_bytes
= 8096;
384 MockTestImageCtx
mock_image_ctx(*ictx
);
385 mock_image_ctx
.object_cacher
= nullptr;
387 MockObjectMap mock_object_map
;
388 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
389 mock_image_ctx
.object_map
= &mock_object_map
;
393 expect_object_may_exist(mock_image_ctx
, 0, true);
394 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
395 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -EPERM
);
398 auto req
= MockObjectReadRequest::create(
399 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
402 ASSERT_EQ(-EPERM
, ctx
.wait());
405 TEST_F(TestMockIoObjectRequest
, CacheRead
) {
406 librbd::ImageCtx
*ictx
;
407 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
408 ictx
->sparse_read_threshold_bytes
= 8096;
410 MockTestImageCtx
mock_image_ctx(*ictx
);
411 MockObjectMap mock_object_map
;
412 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
413 mock_image_ctx
.object_map
= &mock_object_map
;
416 expect_op_work_queue(mock_image_ctx
);
419 expect_cache_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096,
420 std::string(4096, '1'), 0);
423 auto req
= MockObjectReadRequest::create(
424 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
427 ASSERT_EQ(0, ctx
.wait());
430 TEST_F(TestMockIoObjectRequest
, CacheReadError
) {
431 librbd::ImageCtx
*ictx
;
432 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
433 ictx
->sparse_read_threshold_bytes
= 8096;
435 MockTestImageCtx
mock_image_ctx(*ictx
);
436 MockObjectMap mock_object_map
;
437 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
438 mock_image_ctx
.object_map
= &mock_object_map
;
441 expect_op_work_queue(mock_image_ctx
);
444 expect_cache_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096,
448 auto req
= MockObjectReadRequest::create(
449 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
452 ASSERT_EQ(-EPERM
, ctx
.wait());
455 TEST_F(TestMockIoObjectRequest
, ParentRead
) {
456 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
460 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
461 ASSERT_EQ(0, image
.snap_create("one"));
462 ASSERT_EQ(0, image
.snap_protect("one"));
465 std::string clone_name
= get_temp_image_name();
467 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
468 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
470 librbd::ImageCtx
*ictx
;
471 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
472 ictx
->sparse_read_threshold_bytes
= 8096;
473 ictx
->clone_copy_on_read
= false;
475 MockTestImageCtx
mock_image_ctx(*ictx
);
476 mock_image_ctx
.parent
= &mock_image_ctx
;
477 mock_image_ctx
.object_cacher
= nullptr;
479 MockObjectMap mock_object_map
;
480 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
481 mock_image_ctx
.object_map
= &mock_object_map
;
485 expect_object_may_exist(mock_image_ctx
, 0, true);
486 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
487 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
489 MockImageRequest mock_image_request
;
490 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
491 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
492 expect_aio_read(mock_image_request
, {{0, 4096}}, 0);
495 auto req
= MockObjectReadRequest::create(
496 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
499 ASSERT_EQ(0, ctx
.wait());
502 TEST_F(TestMockIoObjectRequest
, ParentReadError
) {
503 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
507 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
508 ASSERT_EQ(0, image
.snap_create("one"));
509 ASSERT_EQ(0, image
.snap_protect("one"));
512 std::string clone_name
= get_temp_image_name();
514 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
515 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
517 librbd::ImageCtx
*ictx
;
518 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
519 ictx
->sparse_read_threshold_bytes
= 8096;
520 ictx
->clone_copy_on_read
= false;
522 MockTestImageCtx
mock_image_ctx(*ictx
);
523 mock_image_ctx
.parent
= &mock_image_ctx
;
524 mock_image_ctx
.object_cacher
= nullptr;
526 MockObjectMap mock_object_map
;
527 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
528 mock_image_ctx
.object_map
= &mock_object_map
;
532 expect_object_may_exist(mock_image_ctx
, 0, true);
533 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
534 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
536 MockImageRequest mock_image_request
;
537 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
538 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
539 expect_aio_read(mock_image_request
, {{0, 4096}}, -EPERM
);
542 auto req
= MockObjectReadRequest::create(
543 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
546 ASSERT_EQ(-EPERM
, ctx
.wait());
549 TEST_F(TestMockIoObjectRequest
, CacheInitiated
) {
550 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
554 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
555 ASSERT_EQ(0, image
.snap_create("one"));
556 ASSERT_EQ(0, image
.snap_protect("one"));
559 std::string clone_name
= get_temp_image_name();
561 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
562 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
564 librbd::ImageCtx
*ictx
;
565 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
566 ictx
->sparse_read_threshold_bytes
= 8096;
567 ictx
->clone_copy_on_read
= false;
569 MockTestImageCtx
mock_image_ctx(*ictx
);
570 mock_image_ctx
.parent
= &mock_image_ctx
;
572 MockObjectMap mock_object_map
;
573 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
574 mock_image_ctx
.object_map
= &mock_object_map
;
578 expect_object_may_exist(mock_image_ctx
, 0, true);
579 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
580 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
583 auto req
= MockObjectReadRequest::create(
584 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0, true,
587 ASSERT_EQ(-ENOENT
, ctx
.wait());
590 TEST_F(TestMockIoObjectRequest
, CopyOnRead
) {
591 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
595 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
596 ASSERT_EQ(0, image
.snap_create("one"));
597 ASSERT_EQ(0, image
.snap_protect("one"));
600 std::string clone_name
= get_temp_image_name();
602 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
603 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
605 librbd::ImageCtx
*ictx
;
606 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
607 ictx
->sparse_read_threshold_bytes
= 8096;
608 ictx
->clone_copy_on_read
= true;
610 MockTestImageCtx
mock_image_ctx(*ictx
);
611 mock_image_ctx
.parent
= &mock_image_ctx
;
612 mock_image_ctx
.object_cacher
= nullptr;
614 MockObjectMap mock_object_map
;
615 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
616 mock_image_ctx
.object_map
= &mock_object_map
;
620 expect_object_may_exist(mock_image_ctx
, 0, true);
621 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
622 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
624 MockImageRequest mock_image_request
;
625 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
626 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
627 expect_aio_read(mock_image_request
, {{0, 4096}}, 0);
629 MockCopyupRequest mock_copyup_request
;
630 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
631 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
632 expect_copyup(mock_copyup_request
, 0);
635 auto req
= MockObjectReadRequest::create(
636 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP
, 0,
639 ASSERT_EQ(0, ctx
.wait());
642 TEST_F(TestMockIoObjectRequest
, Write
) {
643 librbd::ImageCtx
*ictx
;
644 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
646 MockTestImageCtx
mock_image_ctx(*ictx
);
647 expect_get_object_size(mock_image_ctx
);
649 MockExclusiveLock mock_exclusive_lock
;
650 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
651 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
652 expect_is_lock_owner(mock_exclusive_lock
);
655 MockObjectMap mock_object_map
;
656 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
657 mock_image_ctx
.object_map
= &mock_object_map
;
661 bl
.append(std::string(4096, '1'));
664 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
665 expect_object_may_exist(mock_image_ctx
, 0, true);
666 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
667 expect_write(mock_image_ctx
, 0, 4096, 0);
670 auto req
= MockObjectWriteRequest::create_write(
671 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
674 ASSERT_EQ(0, ctx
.wait());
677 TEST_F(TestMockIoObjectRequest
, WriteFull
) {
678 librbd::ImageCtx
*ictx
;
679 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
681 MockTestImageCtx
mock_image_ctx(*ictx
);
682 expect_get_object_size(mock_image_ctx
);
684 MockExclusiveLock mock_exclusive_lock
;
685 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
686 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
687 expect_is_lock_owner(mock_exclusive_lock
);
690 MockObjectMap mock_object_map
;
691 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
692 mock_image_ctx
.object_map
= &mock_object_map
;
696 bl
.append(std::string(ictx
->get_object_size(), '1'));
699 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
700 expect_object_may_exist(mock_image_ctx
, 0, true);
701 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
702 expect_write_full(mock_image_ctx
, 0);
705 auto req
= MockObjectWriteRequest::create_write(
706 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
709 ASSERT_EQ(0, ctx
.wait());
712 TEST_F(TestMockIoObjectRequest
, WriteObjectMap
) {
713 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
715 librbd::ImageCtx
*ictx
;
716 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
718 MockTestImageCtx
mock_image_ctx(*ictx
);
719 expect_op_work_queue(mock_image_ctx
);
720 expect_get_object_size(mock_image_ctx
);
722 MockExclusiveLock mock_exclusive_lock
;
723 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
724 expect_is_lock_owner(mock_exclusive_lock
);
726 MockObjectMap mock_object_map
;
727 mock_image_ctx
.object_map
= &mock_object_map
;
730 bl
.append(std::string(4096, '1'));
733 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
734 expect_object_may_exist(mock_image_ctx
, 0, true);
735 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, true, 0);
736 expect_write(mock_image_ctx
, 0, 4096, 0);
739 auto req
= MockObjectWriteRequest::create_write(
740 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
743 ASSERT_EQ(0, ctx
.wait());
746 TEST_F(TestMockIoObjectRequest
, WriteError
) {
747 librbd::ImageCtx
*ictx
;
748 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
750 MockTestImageCtx
mock_image_ctx(*ictx
);
751 expect_get_object_size(mock_image_ctx
);
754 bl
.append(std::string(4096, '1'));
757 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
758 expect_write(mock_image_ctx
, 0, 4096, -EPERM
);
761 auto req
= MockObjectWriteRequest::create_write(
762 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
765 ASSERT_EQ(-EPERM
, ctx
.wait());
768 TEST_F(TestMockIoObjectRequest
, Copyup
) {
769 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
773 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
774 ASSERT_EQ(0, image
.snap_create("one"));
775 ASSERT_EQ(0, image
.snap_protect("one"));
778 std::string clone_name
= get_temp_image_name();
780 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
781 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
783 librbd::ImageCtx
*ictx
;
784 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
786 MockTestImageCtx
mock_image_ctx(*ictx
);
787 expect_get_object_size(mock_image_ctx
);
789 MockExclusiveLock mock_exclusive_lock
;
790 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
791 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
792 expect_is_lock_owner(mock_exclusive_lock
);
795 MockObjectMap mock_object_map
;
796 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
797 mock_image_ctx
.object_map
= &mock_object_map
;
801 bl
.append(std::string(4096, '1'));
804 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
805 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
806 expect_object_may_exist(mock_image_ctx
, 0, true);
807 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
808 expect_assert_exists(mock_image_ctx
, -ENOENT
);
810 MockAbstractObjectWriteRequest
*write_request
= nullptr;
811 MockCopyupRequest mock_copyup_request
;
812 expect_copyup(mock_copyup_request
, &write_request
, 0);
815 auto req
= MockObjectWriteRequest::create_write(
816 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
819 ASSERT_EQ(0, ctx
.wait());
822 TEST_F(TestMockIoObjectRequest
, CopyupOptimization
) {
823 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_OBJECT_MAP
);
827 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
828 ASSERT_EQ(0, image
.snap_create("one"));
829 ASSERT_EQ(0, image
.snap_protect("one"));
832 std::string clone_name
= get_temp_image_name();
834 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
835 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
837 librbd::ImageCtx
*ictx
;
838 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
840 MockTestImageCtx
mock_image_ctx(*ictx
);
841 expect_get_object_size(mock_image_ctx
);
843 MockExclusiveLock mock_exclusive_lock
;
844 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
845 expect_is_lock_owner(mock_exclusive_lock
);
847 MockObjectMap mock_object_map
;
848 mock_image_ctx
.object_map
= &mock_object_map
;
851 bl
.append(std::string(4096, '1'));
854 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
855 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
856 expect_object_may_exist(mock_image_ctx
, 0, false);
858 MockAbstractObjectWriteRequest
*write_request
= nullptr;
859 MockCopyupRequest mock_copyup_request
;
860 expect_copyup(mock_copyup_request
, &write_request
, 0);
863 auto req
= MockObjectWriteRequest::create_write(
864 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
867 ASSERT_EQ(0, ctx
.wait());
870 TEST_F(TestMockIoObjectRequest
, CopyupError
) {
871 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
875 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
876 ASSERT_EQ(0, image
.snap_create("one"));
877 ASSERT_EQ(0, image
.snap_protect("one"));
880 std::string clone_name
= get_temp_image_name();
882 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
883 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
885 librbd::ImageCtx
*ictx
;
886 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
888 MockTestImageCtx
mock_image_ctx(*ictx
);
889 expect_get_object_size(mock_image_ctx
);
892 bl
.append(std::string(4096, '1'));
895 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
896 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
897 expect_assert_exists(mock_image_ctx
, -ENOENT
);
899 MockAbstractObjectWriteRequest
*write_request
= nullptr;
900 MockCopyupRequest mock_copyup_request
;
901 expect_copyup(mock_copyup_request
, &write_request
, -EPERM
);
904 auto req
= MockObjectWriteRequest::create_write(
905 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, bl
, mock_image_ctx
.snapc
,
908 ASSERT_EQ(-EPERM
, ctx
.wait());
911 TEST_F(TestMockIoObjectRequest
, DiscardRemove
) {
912 librbd::ImageCtx
*ictx
;
913 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
915 MockTestImageCtx
mock_image_ctx(*ictx
);
916 expect_get_object_size(mock_image_ctx
);
918 MockExclusiveLock mock_exclusive_lock
;
919 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
920 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
921 expect_is_lock_owner(mock_exclusive_lock
);
924 MockObjectMap mock_object_map
;
925 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
926 mock_image_ctx
.object_map
= &mock_object_map
;
930 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
931 expect_object_may_exist(mock_image_ctx
, 0, true);
932 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_PENDING
, {}, false, 0);
933 expect_remove(mock_image_ctx
, 0);
934 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_NONEXISTENT
,
935 OBJECT_PENDING
, false, 0);
938 auto req
= MockObjectDiscardRequest::create_discard(
939 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0,
940 mock_image_ctx
.get_object_size(), mock_image_ctx
.snapc
, false, true, {},
943 ASSERT_EQ(0, ctx
.wait());
946 TEST_F(TestMockIoObjectRequest
, DiscardRemoveTruncate
) {
947 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
951 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
952 ASSERT_EQ(0, image
.snap_create("one"));
953 ASSERT_EQ(0, image
.snap_protect("one"));
956 std::string clone_name
= get_temp_image_name();
958 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
959 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
961 librbd::ImageCtx
*ictx
;
962 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
964 MockTestImageCtx
mock_image_ctx(*ictx
);
965 expect_get_object_size(mock_image_ctx
);
967 MockExclusiveLock mock_exclusive_lock
;
968 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
969 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
970 expect_is_lock_owner(mock_exclusive_lock
);
973 MockObjectMap mock_object_map
;
974 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
975 mock_image_ctx
.object_map
= &mock_object_map
;
979 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
980 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
981 expect_object_may_exist(mock_image_ctx
, 0, true);
982 expect_truncate(mock_image_ctx
, 0, 0);
985 auto req
= MockObjectDiscardRequest::create_discard(
986 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0,
987 mock_image_ctx
.get_object_size(), mock_image_ctx
.snapc
, true, true, {},
990 ASSERT_EQ(0, ctx
.wait());
993 TEST_F(TestMockIoObjectRequest
, DiscardTruncate
) {
994 librbd::ImageCtx
*ictx
;
995 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
997 MockTestImageCtx
mock_image_ctx(*ictx
);
998 expect_get_object_size(mock_image_ctx
);
1000 MockExclusiveLock mock_exclusive_lock
;
1001 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1002 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1003 expect_is_lock_owner(mock_exclusive_lock
);
1006 MockObjectMap mock_object_map
;
1007 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1008 mock_image_ctx
.object_map
= &mock_object_map
;
1012 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1013 expect_object_may_exist(mock_image_ctx
, 0, true);
1014 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1015 expect_truncate(mock_image_ctx
, 1, 0);
1018 auto req
= MockObjectDiscardRequest::create_discard(
1019 &mock_image_ctx
, ictx
->get_object_name(0), 0, 1,
1020 mock_image_ctx
.get_object_size() - 1, mock_image_ctx
.snapc
, false, true, {},
1023 ASSERT_EQ(0, ctx
.wait());
1026 TEST_F(TestMockIoObjectRequest
, DiscardZero
) {
1027 librbd::ImageCtx
*ictx
;
1028 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1030 MockTestImageCtx
mock_image_ctx(*ictx
);
1031 expect_get_object_size(mock_image_ctx
);
1033 MockExclusiveLock mock_exclusive_lock
;
1034 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1035 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1036 expect_is_lock_owner(mock_exclusive_lock
);
1039 MockObjectMap mock_object_map
;
1040 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1041 mock_image_ctx
.object_map
= &mock_object_map
;
1045 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1046 expect_object_may_exist(mock_image_ctx
, 0, true);
1047 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1048 expect_zero(mock_image_ctx
, 1, 1, 0);
1051 auto req
= MockObjectDiscardRequest::create_discard(
1052 &mock_image_ctx
, ictx
->get_object_name(0), 0, 1, 1, mock_image_ctx
.snapc
,
1053 false, true, {}, &ctx
);
1055 ASSERT_EQ(0, ctx
.wait());
1058 TEST_F(TestMockIoObjectRequest
, DiscardDisableObjectMapUpdate
) {
1059 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
1061 librbd::ImageCtx
*ictx
;
1062 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1064 MockTestImageCtx
mock_image_ctx(*ictx
);
1065 expect_get_object_size(mock_image_ctx
);
1067 MockExclusiveLock mock_exclusive_lock
;
1068 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1069 expect_is_lock_owner(mock_exclusive_lock
);
1071 MockObjectMap mock_object_map
;
1072 mock_image_ctx
.object_map
= &mock_object_map
;
1075 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1076 expect_object_may_exist(mock_image_ctx
, 0, true);
1077 expect_remove(mock_image_ctx
, 0);
1080 auto req
= MockObjectDiscardRequest::create_discard(
1081 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0,
1082 mock_image_ctx
.get_object_size(), mock_image_ctx
.snapc
, true, false, {},
1085 ASSERT_EQ(0, ctx
.wait());
1088 TEST_F(TestMockIoObjectRequest
, DiscardNoOp
) {
1089 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
1091 librbd::ImageCtx
*ictx
;
1092 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1094 MockTestImageCtx
mock_image_ctx(*ictx
);
1095 expect_op_work_queue(mock_image_ctx
);
1096 expect_get_object_size(mock_image_ctx
);
1098 MockExclusiveLock mock_exclusive_lock
;
1099 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1100 expect_is_lock_owner(mock_exclusive_lock
);
1102 MockObjectMap mock_object_map
;
1103 mock_image_ctx
.object_map
= &mock_object_map
;
1106 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1107 expect_object_may_exist(mock_image_ctx
, 0, false);
1110 auto req
= MockObjectDiscardRequest::create_discard(
1111 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0,
1112 mock_image_ctx
.get_object_size(), mock_image_ctx
.snapc
, true, false, {},
1115 ASSERT_EQ(0, ctx
.wait());
1118 TEST_F(TestMockIoObjectRequest
, WriteSame
) {
1119 librbd::ImageCtx
*ictx
;
1120 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1122 MockTestImageCtx
mock_image_ctx(*ictx
);
1123 expect_get_object_size(mock_image_ctx
);
1125 MockExclusiveLock mock_exclusive_lock
;
1126 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1127 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1128 expect_is_lock_owner(mock_exclusive_lock
);
1131 MockObjectMap mock_object_map
;
1132 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1133 mock_image_ctx
.object_map
= &mock_object_map
;
1137 bl
.append(std::string(4096, '1'));
1140 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1141 expect_object_may_exist(mock_image_ctx
, 0, true);
1142 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1143 expect_writesame(mock_image_ctx
, 0, 4096, 0);
1146 auto req
= MockObjectWriteSameRequest::create_writesame(
1147 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, 4096, bl
,
1148 mock_image_ctx
.snapc
, 0, {}, &ctx
);
1150 ASSERT_EQ(0, ctx
.wait());
1153 TEST_F(TestMockIoObjectRequest
, CompareAndWrite
) {
1154 librbd::ImageCtx
*ictx
;
1155 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1157 MockTestImageCtx
mock_image_ctx(*ictx
);
1158 expect_get_object_size(mock_image_ctx
);
1160 MockExclusiveLock mock_exclusive_lock
;
1161 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1162 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1163 expect_is_lock_owner(mock_exclusive_lock
);
1166 MockObjectMap mock_object_map
;
1167 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1168 mock_image_ctx
.object_map
= &mock_object_map
;
1172 cmp_bl
.append_zero(4096);
1175 bl
.append(std::string(4096, '1'));
1178 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1179 expect_object_may_exist(mock_image_ctx
, 0, true);
1180 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1181 expect_cmpext(mock_image_ctx
, 0, 0);
1182 expect_write(mock_image_ctx
, 0, 4096, 0);
1185 uint64_t mismatch_offset
;
1186 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1187 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, cmp_bl
, bl
,
1188 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1190 ASSERT_EQ(0, ctx
.wait());
1193 TEST_F(TestMockIoObjectRequest
, CompareAndWriteFull
) {
1194 librbd::ImageCtx
*ictx
;
1195 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1197 MockTestImageCtx
mock_image_ctx(*ictx
);
1198 expect_get_object_size(mock_image_ctx
);
1200 MockExclusiveLock mock_exclusive_lock
;
1201 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1202 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1203 expect_is_lock_owner(mock_exclusive_lock
);
1206 MockObjectMap mock_object_map
;
1207 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1208 mock_image_ctx
.object_map
= &mock_object_map
;
1212 cmp_bl
.append_zero(ictx
->get_object_size());
1215 bl
.append(std::string(ictx
->get_object_size(), '1'));
1218 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1219 expect_object_may_exist(mock_image_ctx
, 0, true);
1220 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1221 expect_cmpext(mock_image_ctx
, 0, 0);
1222 expect_write_full(mock_image_ctx
, 0);
1225 uint64_t mismatch_offset
;
1226 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1227 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, cmp_bl
, bl
,
1228 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1230 ASSERT_EQ(0, ctx
.wait());
1233 TEST_F(TestMockIoObjectRequest
, CompareAndWriteCopyup
) {
1234 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1236 librbd::Image image
;
1238 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
1239 ASSERT_EQ(0, image
.snap_create("one"));
1240 ASSERT_EQ(0, image
.snap_protect("one"));
1243 std::string clone_name
= get_temp_image_name();
1245 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
1246 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
1248 librbd::ImageCtx
*ictx
;
1249 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
1251 MockTestImageCtx
mock_image_ctx(*ictx
);
1252 expect_get_object_size(mock_image_ctx
);
1254 MockExclusiveLock mock_exclusive_lock
;
1255 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1256 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1257 expect_is_lock_owner(mock_exclusive_lock
);
1260 MockObjectMap mock_object_map
;
1261 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1262 mock_image_ctx
.object_map
= &mock_object_map
;
1266 cmp_bl
.append_zero(4096);
1269 bl
.append(std::string(4096, '1'));
1272 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
1273 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
1274 expect_object_may_exist(mock_image_ctx
, 0, true);
1275 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1276 expect_assert_exists(mock_image_ctx
, -ENOENT
);
1278 MockAbstractObjectWriteRequest
*write_request
= nullptr;
1279 MockCopyupRequest mock_copyup_request
;
1280 expect_copyup(mock_copyup_request
, &write_request
, 0);
1282 expect_assert_exists(mock_image_ctx
, 0);
1283 expect_cmpext(mock_image_ctx
, 0, 0);
1284 expect_write(mock_image_ctx
, 0, 4096, 0);
1287 uint64_t mismatch_offset
;
1288 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1289 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, cmp_bl
, bl
,
1290 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1292 ASSERT_EQ(0, ctx
.wait());
1295 TEST_F(TestMockIoObjectRequest
, CompareAndWriteMismatch
) {
1296 librbd::ImageCtx
*ictx
;
1297 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1299 MockTestImageCtx
mock_image_ctx(*ictx
);
1300 expect_get_object_size(mock_image_ctx
);
1302 MockExclusiveLock mock_exclusive_lock
;
1303 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1304 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1305 expect_is_lock_owner(mock_exclusive_lock
);
1308 MockObjectMap mock_object_map
;
1309 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1310 mock_image_ctx
.object_map
= &mock_object_map
;
1314 cmp_bl
.append_zero(4096);
1317 bl
.append(std::string(4096, '1'));
1320 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1321 expect_object_may_exist(mock_image_ctx
, 0, true);
1322 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1323 expect_cmpext(mock_image_ctx
, 0, -MAX_ERRNO
- 1);
1326 uint64_t mismatch_offset
;
1327 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1328 &mock_image_ctx
, ictx
->get_object_name(0), 0, 0, cmp_bl
, bl
,
1329 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1331 ASSERT_EQ(-EILSEQ
, ctx
.wait());
1332 ASSERT_EQ(1ULL, mismatch_offset
);
1336 } // namespace librbd