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 Context
*completion
) {
42 assert(s_instance
!= nullptr);
43 s_instance
->on_finish
= completion
;
47 static ObjectRequest
* create_truncate(librbd::MockTestImageCtx
*ictx
,
48 const std::string
&oid
,
51 const ::SnapContext
&snapc
,
52 Context
*completion
) {
53 assert(s_instance
!= nullptr);
54 s_instance
->on_finish
= completion
;
58 static ObjectRequest
* create_write(librbd::MockTestImageCtx
*ictx
,
59 const std::string
&oid
,
62 const ceph::bufferlist
&data
,
63 const ::SnapContext
&snapc
,
64 Context
*completion
, int op_flags
) {
65 assert(s_instance
!= nullptr);
66 s_instance
->on_finish
= completion
;
70 static ObjectRequest
* create_zero(librbd::MockTestImageCtx
*ictx
,
71 const std::string
&oid
,
72 uint64_t object_no
, uint64_t object_off
,
74 const ::SnapContext
&snapc
,
75 Context
*completion
) {
76 assert(s_instance
!= nullptr);
77 s_instance
->on_finish
= completion
;
81 static ObjectRequest
* create_writesame(librbd::MockTestImageCtx
*ictx
,
82 const std::string
&oid
,
86 const ceph::bufferlist
&data
,
87 const ::SnapContext
&snapc
,
88 Context
*completion
, int op_flags
) {
89 assert(s_instance
!= nullptr);
90 s_instance
->on_finish
= completion
;
95 assert(s_instance
== nullptr);
98 ~ObjectRequest() override
{
102 MOCK_METHOD1(complete
, void(int));
103 MOCK_METHOD0(send
, void());
107 struct ObjectReadRequest
<librbd::MockTestImageCtx
> : public ObjectRequest
<librbd::MockTestImageCtx
> {
108 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
109 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
111 static ObjectReadRequest
* s_instance
;
113 static ObjectReadRequest
* create(librbd::MockTestImageCtx
*ictx
,
114 const std::string
&oid
,
115 uint64_t objectno
, uint64_t offset
,
116 uint64_t len
, Extents
&buffer_extents
,
117 librados::snap_t snap_id
, bool sparse
,
118 Context
*completion
, int op_flags
) {
119 assert(s_instance
!= nullptr);
120 s_instance
->on_finish
= completion
;
124 ObjectReadRequest() {
125 assert(s_instance
== nullptr);
128 ~ObjectReadRequest() override
{
129 s_instance
= nullptr;
132 MOCK_CONST_METHOD0(get_offset
, uint64_t());
133 MOCK_CONST_METHOD0(get_length
, uint64_t());
134 MOCK_METHOD0(data
, ceph::bufferlist
&());
135 MOCK_CONST_METHOD0(get_buffer_extents
, const Extents
&());
136 MOCK_METHOD0(get_extent_map
, ExtentMap
&());
140 ObjectRequest
<librbd::MockTestImageCtx
>* ObjectRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
141 ObjectReadRequest
<librbd::MockTestImageCtx
>* ObjectReadRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
144 } // namespace librbd
146 #include "librbd/io/ImageRequest.cc"
152 using ::testing::InSequence
;
153 using ::testing::Invoke
;
154 using ::testing::Return
;
155 using ::testing::WithArg
;
157 struct TestMockIoImageRequest
: public TestMockFixture
{
158 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
159 typedef ImageWriteRequest
<librbd::MockTestImageCtx
> MockImageWriteRequest
;
160 typedef ImageDiscardRequest
<librbd::MockTestImageCtx
> MockImageDiscardRequest
;
161 typedef ImageFlushRequest
<librbd::MockTestImageCtx
> MockImageFlushRequest
;
162 typedef ImageWriteSameRequest
<librbd::MockTestImageCtx
> MockImageWriteSameRequest
;
163 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
164 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
166 void expect_is_journal_appending(MockJournal
&mock_journal
, bool appending
) {
167 EXPECT_CALL(mock_journal
, is_journal_appending())
168 .WillOnce(Return(appending
));
171 void expect_write_to_cache(MockImageCtx
&mock_image_ctx
,
172 const object_t
&object
,
173 uint64_t offset
, uint64_t length
,
174 uint64_t journal_tid
, int r
) {
175 EXPECT_CALL(mock_image_ctx
, write_to_cache(object
, _
, length
, offset
, _
, _
,
177 .WillOnce(WithArg
<4>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
180 void expect_object_request_send(MockImageCtx
&mock_image_ctx
,
181 MockObjectRequest
&mock_object_request
,
183 EXPECT_CALL(mock_object_request
, send())
184 .WillOnce(Invoke([&mock_image_ctx
, &mock_object_request
, r
]() {
185 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
186 mock_object_request
.on_finish
, r
);
190 void expect_user_flushed(MockImageCtx
&mock_image_ctx
) {
191 EXPECT_CALL(mock_image_ctx
, user_flushed());
194 void expect_flush(MockImageCtx
&mock_image_ctx
, int r
) {
195 EXPECT_CALL(mock_image_ctx
, flush(_
))
196 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
200 TEST_F(TestMockIoImageRequest
, AioWriteJournalAppendDisabled
) {
201 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
203 librbd::ImageCtx
*ictx
;
204 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
206 MockObjectRequest mock_aio_object_request
;
207 MockTestImageCtx
mock_image_ctx(*ictx
);
208 MockJournal mock_journal
;
209 mock_image_ctx
.journal
= &mock_journal
;
212 expect_is_journal_appending(mock_journal
, false);
213 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
216 C_SaferCond aio_comp_ctx
;
217 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
218 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITE
);
222 MockImageWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
223 {{0, 1}}, std::move(bl
), 0);
225 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
226 mock_aio_image_write
.send();
228 ASSERT_EQ(0, aio_comp_ctx
.wait());
231 TEST_F(TestMockIoImageRequest
, AioDiscardJournalAppendDisabled
) {
232 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
234 librbd::ImageCtx
*ictx
;
235 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
237 MockObjectRequest mock_aio_object_request
;
238 MockTestImageCtx
mock_image_ctx(*ictx
);
239 MockJournal mock_journal
;
240 mock_image_ctx
.journal
= &mock_journal
;
243 expect_is_journal_appending(mock_journal
, false);
244 if (!ictx
->skip_partial_discard
) {
245 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
248 C_SaferCond aio_comp_ctx
;
249 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
250 &aio_comp_ctx
, ictx
, AIO_TYPE_DISCARD
);
251 MockImageDiscardRequest
mock_aio_image_discard(mock_image_ctx
, aio_comp
,
252 0, 1, ictx
->skip_partial_discard
);
254 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
255 mock_aio_image_discard
.send();
257 ASSERT_EQ(0, aio_comp_ctx
.wait());
260 TEST_F(TestMockIoImageRequest
, AioFlushJournalAppendDisabled
) {
261 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
263 librbd::ImageCtx
*ictx
;
264 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
266 MockTestImageCtx
mock_image_ctx(*ictx
);
267 MockJournal mock_journal
;
268 mock_image_ctx
.journal
= &mock_journal
;
271 expect_user_flushed(mock_image_ctx
);
272 expect_is_journal_appending(mock_journal
, false);
273 expect_flush(mock_image_ctx
, 0);
275 C_SaferCond aio_comp_ctx
;
276 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
277 &aio_comp_ctx
, ictx
, AIO_TYPE_FLUSH
);
278 MockImageFlushRequest
mock_aio_image_flush(mock_image_ctx
, aio_comp
);
280 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
281 mock_aio_image_flush
.send();
283 ASSERT_EQ(0, aio_comp_ctx
.wait());
286 TEST_F(TestMockIoImageRequest
, AioWriteSameJournalAppendDisabled
) {
287 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
289 librbd::ImageCtx
*ictx
;
290 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
292 MockObjectRequest mock_aio_object_request
;
293 MockTestImageCtx
mock_image_ctx(*ictx
);
294 MockJournal mock_journal
;
295 mock_image_ctx
.journal
= &mock_journal
;
298 expect_is_journal_appending(mock_journal
, false);
299 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
302 C_SaferCond aio_comp_ctx
;
303 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
304 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITESAME
);
308 MockImageWriteSameRequest
mock_aio_image_writesame(mock_image_ctx
, aio_comp
,
309 0, 1, std::move(bl
), 0);
311 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
312 mock_aio_image_writesame
.send();
314 ASSERT_EQ(0, aio_comp_ctx
.wait());
318 } // namespace librbd