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_write(librbd::MockTestImageCtx
*ictx
,
38 const std::string
&oid
,
41 const ceph::bufferlist
&data
,
42 const ::SnapContext
&snapc
, int op_flags
,
43 const ZTracer::Trace
&parent_trace
,
44 Context
*completion
) {
45 assert(s_instance
!= nullptr);
46 s_instance
->on_finish
= completion
;
50 static ObjectRequest
* create_discard(librbd::MockTestImageCtx
*ictx
,
51 const std::string
&oid
,
52 uint64_t object_no
, uint64_t object_off
,
54 const ::SnapContext
&snapc
,
55 bool disable_remove_on_clone
,
56 bool update_object_map
,
57 const ZTracer::Trace
&parent_trace
,
58 Context
*completion
) {
59 assert(s_instance
!= nullptr);
60 EXPECT_TRUE(disable_remove_on_clone
);
61 EXPECT_TRUE(update_object_map
);
62 s_instance
->on_finish
= completion
;
66 static ObjectRequest
* create_writesame(librbd::MockTestImageCtx
*ictx
,
67 const std::string
&oid
,
71 const ceph::bufferlist
&data
,
72 const ::SnapContext
&snapc
,
74 const ZTracer::Trace
&parent_trace
,
75 Context
*completion
) {
76 assert(s_instance
!= nullptr);
77 s_instance
->on_finish
= completion
;
81 static ObjectRequest
* create_compare_and_write(librbd::MockTestImageCtx
*ictx
,
82 const std::string
&oid
,
85 const ceph::bufferlist
&cmp_data
,
86 const ceph::bufferlist
&write_data
,
87 const ::SnapContext
&snapc
,
88 uint64_t *mismatch_offset
,
90 const ZTracer::Trace
&parent_trace
,
91 Context
*completion
) {
92 assert(s_instance
!= nullptr);
93 s_instance
->on_finish
= completion
;
98 assert(s_instance
== nullptr);
101 ~ObjectRequest() override
{
102 s_instance
= nullptr;
105 MOCK_METHOD0(send
, void());
106 MOCK_METHOD1(fail
, void(int));
110 struct ObjectReadRequest
<librbd::MockTestImageCtx
> : public ObjectRequest
<librbd::MockTestImageCtx
> {
111 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
112 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
114 static ObjectReadRequest
* s_instance
;
116 static ObjectReadRequest
* create(librbd::MockTestImageCtx
*ictx
,
117 const std::string
&oid
,
118 uint64_t objectno
, uint64_t offset
,
119 uint64_t len
, Extents
&buffer_extents
,
120 librados::snap_t snap_id
, int op_flags
,
121 const ZTracer::Trace
&parent_trace
,
122 Context
*completion
) {
123 assert(s_instance
!= nullptr);
124 s_instance
->on_finish
= completion
;
128 ObjectReadRequest() {
129 assert(s_instance
== nullptr);
132 ~ObjectReadRequest() override
{
133 s_instance
= nullptr;
136 MOCK_CONST_METHOD0(get_offset
, uint64_t());
137 MOCK_CONST_METHOD0(get_length
, uint64_t());
138 MOCK_METHOD0(data
, ceph::bufferlist
&());
139 MOCK_CONST_METHOD0(get_buffer_extents
, const Extents
&());
140 MOCK_METHOD0(get_extent_map
, ExtentMap
&());
144 ObjectRequest
<librbd::MockTestImageCtx
>* ObjectRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
145 ObjectReadRequest
<librbd::MockTestImageCtx
>* ObjectReadRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
148 } // namespace librbd
150 #include "librbd/io/ImageRequest.cc"
156 using ::testing::InSequence
;
157 using ::testing::Invoke
;
158 using ::testing::Return
;
159 using ::testing::WithArg
;
161 struct TestMockIoImageRequest
: public TestMockFixture
{
162 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
163 typedef ImageWriteRequest
<librbd::MockTestImageCtx
> MockImageWriteRequest
;
164 typedef ImageDiscardRequest
<librbd::MockTestImageCtx
> MockImageDiscardRequest
;
165 typedef ImageFlushRequest
<librbd::MockTestImageCtx
> MockImageFlushRequest
;
166 typedef ImageWriteSameRequest
<librbd::MockTestImageCtx
> MockImageWriteSameRequest
;
167 typedef ImageCompareAndWriteRequest
<librbd::MockTestImageCtx
> MockImageCompareAndWriteRequest
;
168 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
169 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
171 void expect_is_journal_appending(MockJournal
&mock_journal
, bool appending
) {
172 EXPECT_CALL(mock_journal
, is_journal_appending())
173 .WillOnce(Return(appending
));
176 void expect_write_to_cache(MockImageCtx
&mock_image_ctx
,
177 const object_t
&object
,
178 uint64_t offset
, uint64_t length
,
179 uint64_t journal_tid
, int r
) {
180 EXPECT_CALL(mock_image_ctx
, write_to_cache(object
, _
, length
, offset
, _
, _
,
182 .WillOnce(WithArg
<4>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
185 void expect_object_request_send(MockImageCtx
&mock_image_ctx
,
186 MockObjectRequest
&mock_object_request
,
188 EXPECT_CALL(mock_object_request
, send())
189 .WillOnce(Invoke([&mock_image_ctx
, &mock_object_request
, r
]() {
190 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
191 mock_object_request
.on_finish
, r
);
195 void expect_user_flushed(MockImageCtx
&mock_image_ctx
) {
196 EXPECT_CALL(mock_image_ctx
, user_flushed());
199 void expect_flush(MockImageCtx
&mock_image_ctx
, int r
) {
200 EXPECT_CALL(mock_image_ctx
, flush(_
))
201 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
205 TEST_F(TestMockIoImageRequest
, AioWriteJournalAppendDisabled
) {
206 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
208 librbd::ImageCtx
*ictx
;
209 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
211 MockObjectRequest mock_aio_object_request
;
212 MockTestImageCtx
mock_image_ctx(*ictx
);
213 MockJournal mock_journal
;
214 mock_image_ctx
.journal
= &mock_journal
;
217 expect_is_journal_appending(mock_journal
, false);
218 if (mock_image_ctx
.image_ctx
->cache
) {
219 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
222 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
225 C_SaferCond aio_comp_ctx
;
226 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
227 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITE
);
231 MockImageWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
232 {{0, 1}}, std::move(bl
), 0, {});
234 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
235 mock_aio_image_write
.send();
237 ASSERT_EQ(0, aio_comp_ctx
.wait());
240 TEST_F(TestMockIoImageRequest
, AioDiscardJournalAppendDisabled
) {
241 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
243 librbd::ImageCtx
*ictx
;
244 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
246 MockObjectRequest mock_aio_object_request
;
247 MockTestImageCtx
mock_image_ctx(*ictx
);
248 MockJournal mock_journal
;
249 mock_image_ctx
.journal
= &mock_journal
;
251 expect_op_work_queue(mock_image_ctx
);
254 expect_is_journal_appending(mock_journal
, false);
255 if (!ictx
->skip_partial_discard
) {
256 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
259 C_SaferCond aio_comp_ctx
;
260 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
261 &aio_comp_ctx
, ictx
, AIO_TYPE_DISCARD
);
262 MockImageDiscardRequest
mock_aio_image_discard(mock_image_ctx
, aio_comp
,
264 ictx
->skip_partial_discard
,
267 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
268 mock_aio_image_discard
.send();
270 ASSERT_EQ(0, aio_comp_ctx
.wait());
273 TEST_F(TestMockIoImageRequest
, AioFlushJournalAppendDisabled
) {
274 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
276 librbd::ImageCtx
*ictx
;
277 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
279 MockTestImageCtx
mock_image_ctx(*ictx
);
280 MockJournal mock_journal
;
281 mock_image_ctx
.journal
= &mock_journal
;
284 expect_user_flushed(mock_image_ctx
);
285 expect_is_journal_appending(mock_journal
, false);
286 expect_flush(mock_image_ctx
, 0);
288 C_SaferCond aio_comp_ctx
;
289 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
290 &aio_comp_ctx
, ictx
, AIO_TYPE_FLUSH
);
291 MockImageFlushRequest
mock_aio_image_flush(mock_image_ctx
, aio_comp
, {});
293 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
294 mock_aio_image_flush
.send();
296 ASSERT_EQ(0, aio_comp_ctx
.wait());
299 TEST_F(TestMockIoImageRequest
, AioWriteSameJournalAppendDisabled
) {
300 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
302 librbd::ImageCtx
*ictx
;
303 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
305 MockObjectRequest mock_aio_object_request
;
306 MockTestImageCtx
mock_image_ctx(*ictx
);
307 MockJournal mock_journal
;
308 mock_image_ctx
.journal
= &mock_journal
;
311 expect_is_journal_appending(mock_journal
, false);
312 if (mock_image_ctx
.image_ctx
->cache
) {
313 expect_write_to_cache(mock_image_ctx
, ictx
->get_object_name(0),
316 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
320 C_SaferCond aio_comp_ctx
;
321 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
322 &aio_comp_ctx
, ictx
, AIO_TYPE_WRITESAME
);
326 MockImageWriteSameRequest
mock_aio_image_writesame(mock_image_ctx
, aio_comp
,
327 0, 1, std::move(bl
), 0,
330 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
331 mock_aio_image_writesame
.send();
333 ASSERT_EQ(0, aio_comp_ctx
.wait());
336 TEST_F(TestMockIoImageRequest
, AioCompareAndWriteJournalAppendDisabled
) {
337 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
339 librbd::ImageCtx
*ictx
;
340 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
342 MockObjectRequest mock_aio_object_request
;
343 MockTestImageCtx
mock_image_ctx(*ictx
);
344 MockJournal mock_journal
;
345 mock_image_ctx
.journal
= &mock_journal
;
347 expect_op_work_queue(mock_image_ctx
);
350 expect_is_journal_appending(mock_journal
, false);
351 expect_object_request_send(mock_image_ctx
, mock_aio_object_request
, 0);
353 C_SaferCond aio_comp_ctx
;
354 AioCompletion
*aio_comp
= AioCompletion::create_and_start(
355 &aio_comp_ctx
, ictx
, AIO_TYPE_COMPARE_AND_WRITE
);
360 write_bl
.append("1");
361 uint64_t mismatch_offset
;
362 MockImageCompareAndWriteRequest
mock_aio_image_write(mock_image_ctx
, aio_comp
,
363 {{0, 1}}, std::move(cmp_bl
),
368 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
369 mock_aio_image_write
.send();
371 ASSERT_EQ(0, aio_comp_ctx
.wait());
375 } // namespace librbd