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/MockJournal.h"
8 #include "test/librbd/mock/cache/MockImageCache.h"
9 #include "librbd/io/ImageRequest.h"
10 #include "librbd/io/ObjectRequest.h"
15 struct MockTestImageCtx
: public MockImageCtx
{
16 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
20 } // anonymous namespace
24 inline ImageCtx
*get_image_ctx(MockTestImageCtx
*image_ctx
) {
25 return image_ctx
->image_ctx
;
33 struct ObjectRequest
<librbd::MockTestImageCtx
> : public ObjectRequestHandle
{
34 static ObjectRequest
* s_instance
;
35 Context
*on_finish
= nullptr;
37 static ObjectRequest
* create_remove(librbd::MockTestImageCtx
*ictx
,
38 const std::string
&oid
,
40 const ::SnapContext
&snapc
,
41 const ZTracer::Trace
&parent_trace
,
42 Context
*completion
) {
43 assert(s_instance
!= nullptr);
44 s_instance
->on_finish
= completion
;
48 static ObjectRequest
* create_truncate(librbd::MockTestImageCtx
*ictx
,
49 const std::string
&oid
,
52 const ::SnapContext
&snapc
,
53 const ZTracer::Trace
&parent_trace
,
54 Context
*completion
) {
55 assert(s_instance
!= nullptr);
56 s_instance
->on_finish
= completion
;
60 static ObjectRequest
* create_write(librbd::MockTestImageCtx
*ictx
,
61 const std::string
&oid
,
64 const ceph::bufferlist
&data
,
65 const ::SnapContext
&snapc
, int op_flags
,
66 const ZTracer::Trace
&parent_trace
,
67 Context
*completion
) {
68 assert(s_instance
!= nullptr);
69 s_instance
->on_finish
= completion
;
73 static ObjectRequest
* create_zero(librbd::MockTestImageCtx
*ictx
,
74 const std::string
&oid
,
75 uint64_t object_no
, uint64_t object_off
,
77 const ::SnapContext
&snapc
,
78 const ZTracer::Trace
&parent_trace
,
79 Context
*completion
) {
80 assert(s_instance
!= nullptr);
81 s_instance
->on_finish
= completion
;
85 static ObjectRequest
* create_writesame(librbd::MockTestImageCtx
*ictx
,
86 const std::string
&oid
,
90 const ceph::bufferlist
&data
,
91 const ::SnapContext
&snapc
,
93 const ZTracer::Trace
&parent_trace
,
94 Context
*completion
) {
95 assert(s_instance
!= nullptr);
96 s_instance
->on_finish
= completion
;
100 static ObjectRequest
* create_compare_and_write(librbd::MockTestImageCtx
*ictx
,
101 const std::string
&oid
,
104 const ceph::bufferlist
&cmp_data
,
105 const ceph::bufferlist
&write_data
,
106 const ::SnapContext
&snapc
,
107 uint64_t *mismatch_offset
,
109 const ZTracer::Trace
&parent_trace
,
110 Context
*completion
) {
111 assert(s_instance
!= nullptr);
112 s_instance
->on_finish
= completion
;
117 assert(s_instance
== nullptr);
120 ~ObjectRequest() override
{
121 s_instance
= nullptr;
124 MOCK_METHOD1(complete
, void(int));
125 MOCK_METHOD0(send
, void());
129 struct ObjectReadRequest
<librbd::MockTestImageCtx
> : public ObjectRequest
<librbd::MockTestImageCtx
> {
130 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
131 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
133 static ObjectReadRequest
* s_instance
;
135 static ObjectReadRequest
* create(librbd::MockTestImageCtx
*ictx
,
136 const std::string
&oid
,
137 uint64_t objectno
, uint64_t offset
,
138 uint64_t len
, Extents
&buffer_extents
,
139 librados::snap_t snap_id
, bool sparse
,
141 const ZTracer::Trace
&parent_trace
,
142 Context
*completion
) {
143 assert(s_instance
!= nullptr);
144 s_instance
->on_finish
= completion
;
148 ObjectReadRequest() {
149 assert(s_instance
== nullptr);
152 ~ObjectReadRequest() override
{
153 s_instance
= nullptr;
156 MOCK_CONST_METHOD0(get_offset
, uint64_t());
157 MOCK_CONST_METHOD0(get_length
, uint64_t());
158 MOCK_METHOD0(data
, ceph::bufferlist
&());
159 MOCK_CONST_METHOD0(get_buffer_extents
, const Extents
&());
160 MOCK_METHOD0(get_extent_map
, ExtentMap
&());
164 ObjectRequest
<librbd::MockTestImageCtx
>* ObjectRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
165 ObjectReadRequest
<librbd::MockTestImageCtx
>* ObjectReadRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
168 } // namespace librbd
170 #include "librbd/io/ImageRequest.cc"
176 using ::testing::InSequence
;
177 using ::testing::Invoke
;
178 using ::testing::Return
;
179 using ::testing::WithArg
;
181 struct TestMockIoImageRequest
: public TestMockFixture
{
182 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
183 typedef ImageWriteRequest
<librbd::MockTestImageCtx
> MockImageWriteRequest
;
184 typedef ImageDiscardRequest
<librbd::MockTestImageCtx
> MockImageDiscardRequest
;
185 typedef ImageFlushRequest
<librbd::MockTestImageCtx
> MockImageFlushRequest
;
186 typedef ImageWriteSameRequest
<librbd::MockTestImageCtx
> MockImageWriteSameRequest
;
187 typedef ImageCompareAndWriteRequest
<librbd::MockTestImageCtx
> MockImageCompareAndWriteRequest
;
188 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
189 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
191 void expect_is_journal_appending(MockJournal
&mock_journal
, bool appending
) {
192 EXPECT_CALL(mock_journal
, is_journal_appending())
193 .WillOnce(Return(appending
));
196 void expect_write_to_cache(MockImageCtx
&mock_image_ctx
,
197 const object_t
&object
,
198 uint64_t offset
, uint64_t length
,
199 uint64_t journal_tid
, int r
) {
200 EXPECT_CALL(mock_image_ctx
, write_to_cache(object
, _
, length
, offset
, _
, _
,
202 .WillOnce(WithArg
<4>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
205 void expect_object_request_send(MockImageCtx
&mock_image_ctx
,
206 MockObjectRequest
&mock_object_request
,
208 EXPECT_CALL(mock_object_request
, send())
209 .WillOnce(Invoke([&mock_image_ctx
, &mock_object_request
, r
]() {
210 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
211 mock_object_request
.on_finish
, r
);
215 void expect_user_flushed(MockImageCtx
&mock_image_ctx
) {
216 EXPECT_CALL(mock_image_ctx
, user_flushed());
219 void expect_flush(MockImageCtx
&mock_image_ctx
, int r
) {
220 EXPECT_CALL(mock_image_ctx
, flush(_
))
221 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
225 TEST_F(TestMockIoImageRequest
, AioWriteJournalAppendDisabled
) {
226 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
228 librbd::ImageCtx
*ictx
;
229 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
231 MockObjectRequest mock_aio_object_request
;
232 MockTestImageCtx
mock_image_ctx(*ictx
);
233 MockJournal mock_journal
;
234 mock_image_ctx
.journal
= &mock_journal
;
237 expect_is_journal_appending(mock_journal
, false);
238 if (mock_image_ctx
.image_ctx
->cache
) {
239 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
242 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
245 C_SaferCond aio_comp_ctx
;
246 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
247 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITE
);
251 MockImageWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
252 {{0, 1}}, std::move(bl
), 0, {});
254 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
255 mock_aio_image_write
.send();
257 ASSERT_EQ(0, aio_comp_ctx
.wait());
260 TEST_F(TestMockIoImageRequest
, AioDiscardJournalAppendDisabled
) {
261 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
263 librbd::ImageCtx
*ictx
;
264 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
266 MockObjectRequest mock_aio_object_request
;
267 MockTestImageCtx
mock_image_ctx(*ictx
);
268 MockJournal mock_journal
;
269 mock_image_ctx
.journal
= &mock_journal
;
272 expect_is_journal_appending(mock_journal
, false);
273 if (!ictx
->skip_partial_discard
) {
274 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
277 C_SaferCond aio_comp_ctx
;
278 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
279 &aio_comp_ctx
, ictx
, AIO_TYPE_DISCARD
);
280 MockImageDiscardRequest
mock_aio_image_discard(mock_image_ctx
, aio_comp
,
282 ictx
->skip_partial_discard
,
285 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
286 mock_aio_image_discard
.send();
288 ASSERT_EQ(0, aio_comp_ctx
.wait());
291 TEST_F(TestMockIoImageRequest
, AioFlushJournalAppendDisabled
) {
292 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
294 librbd::ImageCtx
*ictx
;
295 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
297 MockTestImageCtx
mock_image_ctx(*ictx
);
298 MockJournal mock_journal
;
299 mock_image_ctx
.journal
= &mock_journal
;
302 expect_user_flushed(mock_image_ctx
);
303 expect_is_journal_appending(mock_journal
, false);
304 expect_flush(mock_image_ctx
, 0);
306 C_SaferCond aio_comp_ctx
;
307 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
308 &aio_comp_ctx
, ictx
, AIO_TYPE_FLUSH
);
309 MockImageFlushRequest
mock_aio_image_flush(mock_image_ctx
, aio_comp
, {});
311 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
312 mock_aio_image_flush
.send();
314 ASSERT_EQ(0, aio_comp_ctx
.wait());
317 TEST_F(TestMockIoImageRequest
, AioWriteSameJournalAppendDisabled
) {
318 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
320 librbd::ImageCtx
*ictx
;
321 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
323 MockObjectRequest mock_aio_object_request
;
324 MockTestImageCtx
mock_image_ctx(*ictx
);
325 MockJournal mock_journal
;
326 mock_image_ctx
.journal
= &mock_journal
;
329 expect_is_journal_appending(mock_journal
, false);
330 if (mock_image_ctx
.image_ctx
->cache
) {
331 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
334 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
338 C_SaferCond aio_comp_ctx
;
339 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
340 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITESAME
);
344 MockImageWriteSameRequest
mock_aio_image_writesame(mock_image_ctx
, aio_comp
,
345 0, 1, std::move(bl
), 0,
348 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
349 mock_aio_image_writesame
.send();
351 ASSERT_EQ(0, aio_comp_ctx
.wait());
354 TEST_F(TestMockIoImageRequest
, AioCompareAndWriteJournalAppendDisabled
) {
355 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
357 librbd::ImageCtx
*ictx
;
358 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
360 MockObjectRequest mock_aio_object_request
;
361 MockTestImageCtx
mock_image_ctx(*ictx
);
362 MockJournal mock_journal
;
363 mock_image_ctx
.journal
= &mock_journal
;
366 expect_is_journal_appending(mock_journal
, false);
367 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
369 C_SaferCond aio_comp_ctx
;
370 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
371 &aio_comp_ctx
, ictx
, AIO_TYPE_COMPARE_AND_WRITE
);
376 write_bl
.append("1");
377 uint64_t mismatch_offset
;
378 MockImageCompareAndWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
379 {{0, 1}}, std::move(cmp_bl
),
384 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
385 mock_aio_image_write
.send();
387 ASSERT_EQ(0, aio_comp_ctx
.wait());
391 } // namespace librbd