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
;
101 assert(s_instance
== nullptr);
104 ~ObjectRequest() override
{
105 s_instance
= nullptr;
108 MOCK_METHOD1(complete
, void(int));
109 MOCK_METHOD0(send
, void());
113 struct ObjectReadRequest
<librbd::MockTestImageCtx
> : public ObjectRequest
<librbd::MockTestImageCtx
> {
114 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
115 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
117 static ObjectReadRequest
* s_instance
;
119 static ObjectReadRequest
* create(librbd::MockTestImageCtx
*ictx
,
120 const std::string
&oid
,
121 uint64_t objectno
, uint64_t offset
,
122 uint64_t len
, Extents
&buffer_extents
,
123 librados::snap_t snap_id
, bool sparse
,
125 const ZTracer::Trace
&parent_trace
,
126 Context
*completion
) {
127 assert(s_instance
!= nullptr);
128 s_instance
->on_finish
= completion
;
132 ObjectReadRequest() {
133 assert(s_instance
== nullptr);
136 ~ObjectReadRequest() override
{
137 s_instance
= nullptr;
140 MOCK_CONST_METHOD0(get_offset
, uint64_t());
141 MOCK_CONST_METHOD0(get_length
, uint64_t());
142 MOCK_METHOD0(data
, ceph::bufferlist
&());
143 MOCK_CONST_METHOD0(get_buffer_extents
, const Extents
&());
144 MOCK_METHOD0(get_extent_map
, ExtentMap
&());
148 ObjectRequest
<librbd::MockTestImageCtx
>* ObjectRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
149 ObjectReadRequest
<librbd::MockTestImageCtx
>* ObjectReadRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
152 } // namespace librbd
154 #include "librbd/io/ImageRequest.cc"
160 using ::testing::InSequence
;
161 using ::testing::Invoke
;
162 using ::testing::Return
;
163 using ::testing::WithArg
;
165 struct TestMockIoImageRequest
: public TestMockFixture
{
166 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
167 typedef ImageWriteRequest
<librbd::MockTestImageCtx
> MockImageWriteRequest
;
168 typedef ImageDiscardRequest
<librbd::MockTestImageCtx
> MockImageDiscardRequest
;
169 typedef ImageFlushRequest
<librbd::MockTestImageCtx
> MockImageFlushRequest
;
170 typedef ImageWriteSameRequest
<librbd::MockTestImageCtx
> MockImageWriteSameRequest
;
171 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
172 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
174 void expect_is_journal_appending(MockJournal
&mock_journal
, bool appending
) {
175 EXPECT_CALL(mock_journal
, is_journal_appending())
176 .WillOnce(Return(appending
));
179 void expect_write_to_cache(MockImageCtx
&mock_image_ctx
,
180 const object_t
&object
,
181 uint64_t offset
, uint64_t length
,
182 uint64_t journal_tid
, int r
) {
183 EXPECT_CALL(mock_image_ctx
, write_to_cache(object
, _
, length
, offset
, _
, _
,
185 .WillOnce(WithArg
<4>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
188 void expect_object_request_send(MockImageCtx
&mock_image_ctx
,
189 MockObjectRequest
&mock_object_request
,
191 EXPECT_CALL(mock_object_request
, send())
192 .WillOnce(Invoke([&mock_image_ctx
, &mock_object_request
, r
]() {
193 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
194 mock_object_request
.on_finish
, r
);
198 void expect_user_flushed(MockImageCtx
&mock_image_ctx
) {
199 EXPECT_CALL(mock_image_ctx
, user_flushed());
202 void expect_flush(MockImageCtx
&mock_image_ctx
, int r
) {
203 EXPECT_CALL(mock_image_ctx
, flush(_
))
204 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
208 TEST_F(TestMockIoImageRequest
, AioWriteJournalAppendDisabled
) {
209 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
211 librbd::ImageCtx
*ictx
;
212 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
214 MockObjectRequest mock_aio_object_request
;
215 MockTestImageCtx
mock_image_ctx(*ictx
);
216 MockJournal mock_journal
;
217 mock_image_ctx
.journal
= &mock_journal
;
220 expect_is_journal_appending(mock_journal
, false);
221 if (mock_image_ctx
.image_ctx
->cache
) {
222 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
225 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
228 C_SaferCond aio_comp_ctx
;
229 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
230 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITE
);
234 MockImageWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
235 {{0, 1}}, std::move(bl
), 0, {});
237 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
238 mock_aio_image_write
.send();
240 ASSERT_EQ(0, aio_comp_ctx
.wait());
243 TEST_F(TestMockIoImageRequest
, AioDiscardJournalAppendDisabled
) {
244 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
246 librbd::ImageCtx
*ictx
;
247 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
249 MockObjectRequest mock_aio_object_request
;
250 MockTestImageCtx
mock_image_ctx(*ictx
);
251 MockJournal mock_journal
;
252 mock_image_ctx
.journal
= &mock_journal
;
255 expect_is_journal_appending(mock_journal
, false);
256 if (!ictx
->skip_partial_discard
) {
257 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
260 C_SaferCond aio_comp_ctx
;
261 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
262 &aio_comp_ctx
, ictx
, AIO_TYPE_DISCARD
);
263 MockImageDiscardRequest
mock_aio_image_discard(mock_image_ctx
, aio_comp
,
265 ictx
->skip_partial_discard
,
268 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
269 mock_aio_image_discard
.send();
271 ASSERT_EQ(0, aio_comp_ctx
.wait());
274 TEST_F(TestMockIoImageRequest
, AioFlushJournalAppendDisabled
) {
275 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
277 librbd::ImageCtx
*ictx
;
278 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
280 MockTestImageCtx
mock_image_ctx(*ictx
);
281 MockJournal mock_journal
;
282 mock_image_ctx
.journal
= &mock_journal
;
285 expect_user_flushed(mock_image_ctx
);
286 expect_is_journal_appending(mock_journal
, false);
287 expect_flush(mock_image_ctx
, 0);
289 C_SaferCond aio_comp_ctx
;
290 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
291 &aio_comp_ctx
, ictx
, AIO_TYPE_FLUSH
);
292 MockImageFlushRequest
mock_aio_image_flush(mock_image_ctx
, aio_comp
, {});
294 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
295 mock_aio_image_flush
.send();
297 ASSERT_EQ(0, aio_comp_ctx
.wait());
300 TEST_F(TestMockIoImageRequest
, AioWriteSameJournalAppendDisabled
) {
301 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
303 librbd::ImageCtx
*ictx
;
304 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
306 MockObjectRequest mock_aio_object_request
;
307 MockTestImageCtx
mock_image_ctx(*ictx
);
308 MockJournal mock_journal
;
309 mock_image_ctx
.journal
= &mock_journal
;
312 expect_is_journal_appending(mock_journal
, false);
313 if (mock_image_ctx
.image_ctx
->cache
) {
314 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
317 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
321 C_SaferCond aio_comp_ctx
;
322 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
323 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITESAME
);
327 MockImageWriteSameRequest
mock_aio_image_writesame(mock_image_ctx
, aio_comp
,
328 0, 1, std::move(bl
), 0,
331 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
332 mock_aio_image_writesame
.send();
334 ASSERT_EQ(0, aio_comp_ctx
.wait());
338 } // namespace librbd