]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ImageRequest.cc
8460926d19568ea59eb01209f3e7cee931ff7da5
[ceph.git] / ceph / src / test / librbd / io / test_mock_ImageRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
11
12 namespace librbd {
13 namespace {
14
15 struct MockTestImageCtx : public MockImageCtx {
16 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
17 }
18 };
19
20 } // anonymous namespace
21
22 namespace util {
23
24 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
25 return image_ctx->image_ctx;
26 }
27
28 } // namespace util
29
30 namespace io {
31
32 template <>
33 struct ObjectRequest<librbd::MockTestImageCtx> : public ObjectRequestHandle {
34 static ObjectRequest* s_instance;
35 Context *on_finish = nullptr;
36
37 static ObjectRequest* create_write(librbd::MockTestImageCtx *ictx,
38 const std::string &oid,
39 uint64_t object_no,
40 uint64_t object_off,
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;
47 return s_instance;
48 }
49
50 static ObjectRequest* create_discard(librbd::MockTestImageCtx *ictx,
51 const std::string &oid,
52 uint64_t object_no, uint64_t object_off,
53 uint64_t object_len,
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;
63 return s_instance;
64 }
65
66 static ObjectRequest* create_writesame(librbd::MockTestImageCtx *ictx,
67 const std::string &oid,
68 uint64_t object_no,
69 uint64_t object_off,
70 uint64_t object_len,
71 const ceph::bufferlist &data,
72 const ::SnapContext &snapc,
73 int op_flags,
74 const ZTracer::Trace &parent_trace,
75 Context *completion) {
76 assert(s_instance != nullptr);
77 s_instance->on_finish = completion;
78 return s_instance;
79 }
80
81 static ObjectRequest* create_compare_and_write(librbd::MockTestImageCtx *ictx,
82 const std::string &oid,
83 uint64_t object_no,
84 uint64_t object_off,
85 const ceph::bufferlist &cmp_data,
86 const ceph::bufferlist &write_data,
87 const ::SnapContext &snapc,
88 uint64_t *mismatch_offset,
89 int op_flags,
90 const ZTracer::Trace &parent_trace,
91 Context *completion) {
92 assert(s_instance != nullptr);
93 s_instance->on_finish = completion;
94 return s_instance;
95 }
96
97 ObjectRequest() {
98 assert(s_instance == nullptr);
99 s_instance = this;
100 }
101 ~ObjectRequest() override {
102 s_instance = nullptr;
103 }
104
105 MOCK_METHOD0(send, void());
106 MOCK_METHOD1(fail, void(int));
107 };
108
109 template <>
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;
113
114 static ObjectReadRequest* s_instance;
115
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;
125 return s_instance;
126 }
127
128 ObjectReadRequest() {
129 assert(s_instance == nullptr);
130 s_instance = this;
131 }
132 ~ObjectReadRequest() override {
133 s_instance = nullptr;
134 }
135
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 &());
141
142 };
143
144 ObjectRequest<librbd::MockTestImageCtx>* ObjectRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
145 ObjectReadRequest<librbd::MockTestImageCtx>* ObjectReadRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
146
147 } // namespace io
148 } // namespace librbd
149
150 #include "librbd/io/ImageRequest.cc"
151
152 namespace librbd {
153 namespace io {
154
155 using ::testing::_;
156 using ::testing::InSequence;
157 using ::testing::Invoke;
158 using ::testing::Return;
159 using ::testing::WithArg;
160
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;
170
171 void expect_is_journal_appending(MockJournal &mock_journal, bool appending) {
172 EXPECT_CALL(mock_journal, is_journal_appending())
173 .WillOnce(Return(appending));
174 }
175
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, _, _,
181 journal_tid, _))
182 .WillOnce(WithArg<4>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
183 }
184
185 void expect_object_request_send(MockImageCtx &mock_image_ctx,
186 MockObjectRequest &mock_object_request,
187 int r) {
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);
192 }));
193 }
194
195 void expect_user_flushed(MockImageCtx &mock_image_ctx) {
196 EXPECT_CALL(mock_image_ctx, user_flushed());
197 }
198
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));
202 }
203 };
204
205 TEST_F(TestMockIoImageRequest, AioWriteJournalAppendDisabled) {
206 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
207
208 librbd::ImageCtx *ictx;
209 ASSERT_EQ(0, open_image(m_image_name, &ictx));
210
211 MockObjectRequest mock_aio_object_request;
212 MockTestImageCtx mock_image_ctx(*ictx);
213 MockJournal mock_journal;
214 mock_image_ctx.journal = &mock_journal;
215
216 InSequence seq;
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),
220 0, 1, 0, 0);
221 } else {
222 expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
223 }
224
225 C_SaferCond aio_comp_ctx;
226 AioCompletion *aio_comp = AioCompletion::create_and_start(
227 &aio_comp_ctx, ictx, AIO_TYPE_WRITE);
228
229 bufferlist bl;
230 bl.append("1");
231 MockImageWriteRequest mock_aio_image_write(mock_image_ctx, aio_comp,
232 {{0, 1}}, std::move(bl), 0, {});
233 {
234 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
235 mock_aio_image_write.send();
236 }
237 ASSERT_EQ(0, aio_comp_ctx.wait());
238 }
239
240 TEST_F(TestMockIoImageRequest, AioDiscardJournalAppendDisabled) {
241 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
242
243 librbd::ImageCtx *ictx;
244 ASSERT_EQ(0, open_image(m_image_name, &ictx));
245
246 MockObjectRequest mock_aio_object_request;
247 MockTestImageCtx mock_image_ctx(*ictx);
248 MockJournal mock_journal;
249 mock_image_ctx.journal = &mock_journal;
250
251 expect_op_work_queue(mock_image_ctx);
252
253 InSequence seq;
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);
257 }
258
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,
263 0, 1,
264 ictx->skip_partial_discard,
265 {});
266 {
267 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
268 mock_aio_image_discard.send();
269 }
270 ASSERT_EQ(0, aio_comp_ctx.wait());
271 }
272
273 TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) {
274 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
275
276 librbd::ImageCtx *ictx;
277 ASSERT_EQ(0, open_image(m_image_name, &ictx));
278
279 MockTestImageCtx mock_image_ctx(*ictx);
280 MockJournal mock_journal;
281 mock_image_ctx.journal = &mock_journal;
282
283 InSequence seq;
284 expect_user_flushed(mock_image_ctx);
285 expect_is_journal_appending(mock_journal, false);
286 expect_flush(mock_image_ctx, 0);
287
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, {});
292 {
293 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
294 mock_aio_image_flush.send();
295 }
296 ASSERT_EQ(0, aio_comp_ctx.wait());
297 }
298
299 TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) {
300 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
301
302 librbd::ImageCtx *ictx;
303 ASSERT_EQ(0, open_image(m_image_name, &ictx));
304
305 MockObjectRequest mock_aio_object_request;
306 MockTestImageCtx mock_image_ctx(*ictx);
307 MockJournal mock_journal;
308 mock_image_ctx.journal = &mock_journal;
309
310 InSequence seq;
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),
314 0, 1, 0, 0);
315 } else {
316 expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
317 }
318
319
320 C_SaferCond aio_comp_ctx;
321 AioCompletion *aio_comp = AioCompletion::create_and_start(
322 &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME);
323
324 bufferlist bl;
325 bl.append("1");
326 MockImageWriteSameRequest mock_aio_image_writesame(mock_image_ctx, aio_comp,
327 0, 1, std::move(bl), 0,
328 {});
329 {
330 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
331 mock_aio_image_writesame.send();
332 }
333 ASSERT_EQ(0, aio_comp_ctx.wait());
334 }
335
336 TEST_F(TestMockIoImageRequest, AioCompareAndWriteJournalAppendDisabled) {
337 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
338
339 librbd::ImageCtx *ictx;
340 ASSERT_EQ(0, open_image(m_image_name, &ictx));
341
342 MockObjectRequest mock_aio_object_request;
343 MockTestImageCtx mock_image_ctx(*ictx);
344 MockJournal mock_journal;
345 mock_image_ctx.journal = &mock_journal;
346
347 expect_op_work_queue(mock_image_ctx);
348
349 InSequence seq;
350 expect_is_journal_appending(mock_journal, false);
351 expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
352
353 C_SaferCond aio_comp_ctx;
354 AioCompletion *aio_comp = AioCompletion::create_and_start(
355 &aio_comp_ctx, ictx, AIO_TYPE_COMPARE_AND_WRITE);
356
357 bufferlist cmp_bl;
358 cmp_bl.append("1");
359 bufferlist write_bl;
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),
364 std::move(write_bl),
365 &mismatch_offset,
366 0, {});
367 {
368 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
369 mock_aio_image_write.send();
370 }
371 ASSERT_EQ(0, aio_comp_ctx.wait());
372 }
373
374 } // namespace io
375 } // namespace librbd