]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ImageRequest.cc
update sources to v12.1.0
[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_remove(librbd::MockTestImageCtx *ictx,
38 const std::string &oid,
39 uint64_t object_no,
40 const ::SnapContext &snapc,
41 const ZTracer::Trace &parent_trace,
42 Context *completion) {
43 assert(s_instance != nullptr);
44 s_instance->on_finish = completion;
45 return s_instance;
46 }
47
48 static ObjectRequest* create_truncate(librbd::MockTestImageCtx *ictx,
49 const std::string &oid,
50 uint64_t object_no,
51 uint64_t object_off,
52 const ::SnapContext &snapc,
53 const ZTracer::Trace &parent_trace,
54 Context *completion) {
55 assert(s_instance != nullptr);
56 s_instance->on_finish = completion;
57 return s_instance;
58 }
59
60 static ObjectRequest* create_write(librbd::MockTestImageCtx *ictx,
61 const std::string &oid,
62 uint64_t object_no,
63 uint64_t object_off,
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;
70 return s_instance;
71 }
72
73 static ObjectRequest* create_zero(librbd::MockTestImageCtx *ictx,
74 const std::string &oid,
75 uint64_t object_no, uint64_t object_off,
76 uint64_t object_len,
77 const ::SnapContext &snapc,
78 const ZTracer::Trace &parent_trace,
79 Context *completion) {
80 assert(s_instance != nullptr);
81 s_instance->on_finish = completion;
82 return s_instance;
83 }
84
85 static ObjectRequest* create_writesame(librbd::MockTestImageCtx *ictx,
86 const std::string &oid,
87 uint64_t object_no,
88 uint64_t object_off,
89 uint64_t object_len,
90 const ceph::bufferlist &data,
91 const ::SnapContext &snapc,
92 int op_flags,
93 const ZTracer::Trace &parent_trace,
94 Context *completion) {
95 assert(s_instance != nullptr);
96 s_instance->on_finish = completion;
97 return s_instance;
98 }
99
100 ObjectRequest() {
101 assert(s_instance == nullptr);
102 s_instance = this;
103 }
104 ~ObjectRequest() override {
105 s_instance = nullptr;
106 }
107
108 MOCK_METHOD1(complete, void(int));
109 MOCK_METHOD0(send, void());
110 };
111
112 template <>
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;
116
117 static ObjectReadRequest* s_instance;
118
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,
124 int op_flags,
125 const ZTracer::Trace &parent_trace,
126 Context *completion) {
127 assert(s_instance != nullptr);
128 s_instance->on_finish = completion;
129 return s_instance;
130 }
131
132 ObjectReadRequest() {
133 assert(s_instance == nullptr);
134 s_instance = this;
135 }
136 ~ObjectReadRequest() override {
137 s_instance = nullptr;
138 }
139
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 &());
145
146 };
147
148 ObjectRequest<librbd::MockTestImageCtx>* ObjectRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
149 ObjectReadRequest<librbd::MockTestImageCtx>* ObjectReadRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
150
151 } // namespace io
152 } // namespace librbd
153
154 #include "librbd/io/ImageRequest.cc"
155
156 namespace librbd {
157 namespace io {
158
159 using ::testing::_;
160 using ::testing::InSequence;
161 using ::testing::Invoke;
162 using ::testing::Return;
163 using ::testing::WithArg;
164
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;
173
174 void expect_is_journal_appending(MockJournal &mock_journal, bool appending) {
175 EXPECT_CALL(mock_journal, is_journal_appending())
176 .WillOnce(Return(appending));
177 }
178
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, _, _,
184 journal_tid, _))
185 .WillOnce(WithArg<4>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
186 }
187
188 void expect_object_request_send(MockImageCtx &mock_image_ctx,
189 MockObjectRequest &mock_object_request,
190 int r) {
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);
195 }));
196 }
197
198 void expect_user_flushed(MockImageCtx &mock_image_ctx) {
199 EXPECT_CALL(mock_image_ctx, user_flushed());
200 }
201
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));
205 }
206 };
207
208 TEST_F(TestMockIoImageRequest, AioWriteJournalAppendDisabled) {
209 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
210
211 librbd::ImageCtx *ictx;
212 ASSERT_EQ(0, open_image(m_image_name, &ictx));
213
214 MockObjectRequest mock_aio_object_request;
215 MockTestImageCtx mock_image_ctx(*ictx);
216 MockJournal mock_journal;
217 mock_image_ctx.journal = &mock_journal;
218
219 InSequence seq;
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),
223 0, 1, 0, 0);
224 } else {
225 expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
226 }
227
228 C_SaferCond aio_comp_ctx;
229 AioCompletion *aio_comp = AioCompletion::create_and_start(
230 &aio_comp_ctx, ictx, AIO_TYPE_WRITE);
231
232 bufferlist bl;
233 bl.append("1");
234 MockImageWriteRequest mock_aio_image_write(mock_image_ctx, aio_comp,
235 {{0, 1}}, std::move(bl), 0, {});
236 {
237 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
238 mock_aio_image_write.send();
239 }
240 ASSERT_EQ(0, aio_comp_ctx.wait());
241 }
242
243 TEST_F(TestMockIoImageRequest, AioDiscardJournalAppendDisabled) {
244 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
245
246 librbd::ImageCtx *ictx;
247 ASSERT_EQ(0, open_image(m_image_name, &ictx));
248
249 MockObjectRequest mock_aio_object_request;
250 MockTestImageCtx mock_image_ctx(*ictx);
251 MockJournal mock_journal;
252 mock_image_ctx.journal = &mock_journal;
253
254 InSequence seq;
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);
258 }
259
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,
264 0, 1,
265 ictx->skip_partial_discard,
266 {});
267 {
268 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
269 mock_aio_image_discard.send();
270 }
271 ASSERT_EQ(0, aio_comp_ctx.wait());
272 }
273
274 TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) {
275 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
276
277 librbd::ImageCtx *ictx;
278 ASSERT_EQ(0, open_image(m_image_name, &ictx));
279
280 MockTestImageCtx mock_image_ctx(*ictx);
281 MockJournal mock_journal;
282 mock_image_ctx.journal = &mock_journal;
283
284 InSequence seq;
285 expect_user_flushed(mock_image_ctx);
286 expect_is_journal_appending(mock_journal, false);
287 expect_flush(mock_image_ctx, 0);
288
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, {});
293 {
294 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
295 mock_aio_image_flush.send();
296 }
297 ASSERT_EQ(0, aio_comp_ctx.wait());
298 }
299
300 TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) {
301 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
302
303 librbd::ImageCtx *ictx;
304 ASSERT_EQ(0, open_image(m_image_name, &ictx));
305
306 MockObjectRequest mock_aio_object_request;
307 MockTestImageCtx mock_image_ctx(*ictx);
308 MockJournal mock_journal;
309 mock_image_ctx.journal = &mock_journal;
310
311 InSequence seq;
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),
315 0, 1, 0, 0);
316 } else {
317 expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
318 }
319
320
321 C_SaferCond aio_comp_ctx;
322 AioCompletion *aio_comp = AioCompletion::create_and_start(
323 &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME);
324
325 bufferlist bl;
326 bl.append("1");
327 MockImageWriteSameRequest mock_aio_image_writesame(mock_image_ctx, aio_comp,
328 0, 1, std::move(bl), 0,
329 {});
330 {
331 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
332 mock_aio_image_writesame.send();
333 }
334 ASSERT_EQ(0, aio_comp_ctx.wait());
335 }
336
337 } // namespace io
338 } // namespace librbd