]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / librbd / cache / test_mock_ParentCacheObjectDispatch.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 "gmock/gmock.h"
8 #include "gtest/gtest.h"
9 #include "include/Context.h"
10 #include "tools/immutable_object_cache/CacheClient.h"
11 #include "test/immutable_object_cache/MockCacheDaemon.h"
12 #include "librbd/cache/ParentCacheObjectDispatch.h"
13 #include "librbd/plugin/Api.h"
14 #include "test/librbd/test_mock_fixture.h"
15 #include "test/librbd/mock/MockImageCtx.h"
16
17 using namespace ceph::immutable_obj_cache;
18
19 namespace librbd {
20
21 namespace {
22
23 struct MockParentImageCacheImageCtx : public MockImageCtx {
24 MockParentImageCacheImageCtx(ImageCtx& image_ctx)
25 : MockImageCtx(image_ctx) {
26 }
27 ~MockParentImageCacheImageCtx() {}
28 };
29
30 } // anonymous namespace
31
32 namespace cache {
33
34 template<>
35 struct TypeTraits<MockParentImageCacheImageCtx> {
36 typedef ceph::immutable_obj_cache::MockCacheClient CacheClient;
37 };
38
39 } // namespace cache
40
41 namespace plugin {
42
43 template <>
44 struct Api<MockParentImageCacheImageCtx> {
45 MOCK_METHOD6(read_parent, void(MockParentImageCacheImageCtx*, uint64_t,
46 librbd::io::ReadExtents*, librados::snap_t,
47 const ZTracer::Trace &, Context*));
48 };
49
50 } // namespace plugin
51 } // namespace librbd
52
53 #include "librbd/cache/ParentCacheObjectDispatch.cc"
54 template class librbd::cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx>;
55
56 namespace librbd {
57
58 using ::testing::_;
59 using ::testing::DoAll;
60 using ::testing::Invoke;
61 using ::testing::InSequence;
62 using ::testing::Return;
63 using ::testing::WithArg;
64 using ::testing::WithArgs;
65
66 class TestMockParentCacheObjectDispatch : public TestMockFixture {
67 public :
68 typedef cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx> MockParentImageCache;
69 typedef plugin::Api<MockParentImageCacheImageCtx> MockPluginApi;
70
71 // ====== mock cache client ====
72 void expect_cache_run(MockParentImageCache& mparent_image_cache, bool ret_val) {
73 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), run());
74
75 expect.WillOnce((Invoke([]() {
76 })));
77 }
78
79 void expect_cache_session_state(MockParentImageCache& mparent_image_cache, bool ret_val) {
80 auto & expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), is_session_work());
81
82 expect.WillOnce((Invoke([ret_val]() {
83 return ret_val;
84 })));
85 }
86
87 void expect_cache_connect(MockParentImageCache& mparent_image_cache, int ret_val) {
88 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect());
89
90 expect.WillOnce((Invoke([ret_val]() {
91 return ret_val;
92 })));
93 }
94
95 void expect_cache_async_connect(MockParentImageCache& mparent_image_cache, int ret_val,
96 Context* on_finish) {
97 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect(_));
98
99 expect.WillOnce(WithArg<0>(Invoke([on_finish, ret_val](Context* ctx) {
100 ctx->complete(ret_val);
101 on_finish->complete(ret_val);
102 })));
103 }
104
105 void expect_cache_lookup_object(MockParentImageCache& mparent_image_cache,
106 const std::string &cache_path) {
107 EXPECT_CALL(*(mparent_image_cache.get_cache_client()),
108 lookup_object(_, _, _, _, _, _))
109 .WillOnce(WithArg<5>(Invoke([cache_path](CacheGenContextURef on_finish) {
110 ObjectCacheReadReplyData ack(RBDSC_READ_REPLY, 0, cache_path);
111 on_finish.release()->complete(&ack);
112 })));
113 }
114
115 void expect_read_parent(MockPluginApi &mock_plugin_api, uint64_t object_no,
116 io::ReadExtents* extents, librados::snap_t snap_id,
117 int r) {
118 EXPECT_CALL(mock_plugin_api,
119 read_parent(_, object_no, extents, snap_id, _, _))
120 .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
121 }
122
123 void expect_cache_close(MockParentImageCache& mparent_image_cache, int ret_val) {
124 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), close());
125
126 expect.WillOnce((Invoke([]() {
127 })));
128 }
129
130 void expect_cache_stop(MockParentImageCache& mparent_image_cache, int ret_val) {
131 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), stop());
132
133 expect.WillOnce((Invoke([]() {
134 })));
135 }
136
137 void expect_cache_register(MockParentImageCache& mparent_image_cache, Context* mock_handle_register, int ret_val) {
138 auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), register_client(_));
139
140 expect.WillOnce(WithArg<0>(Invoke([mock_handle_register, ret_val](Context* ctx) {
141 if(ret_val == 0) {
142 mock_handle_register->complete(true);
143 } else {
144 mock_handle_register->complete(false);
145 }
146 ctx->complete(true);
147 return ret_val;
148 })));
149 }
150
151 void expect_io_object_dispatcher_register_state(MockParentImageCache& mparent_image_cache,
152 int ret_val) {
153 auto& expect = EXPECT_CALL((*(mparent_image_cache.get_image_ctx()->io_object_dispatcher)),
154 register_dispatch(_));
155
156 expect.WillOnce(WithArg<0>(Invoke([&mparent_image_cache]
157 (io::ObjectDispatchInterface* object_dispatch) {
158 ASSERT_EQ(object_dispatch, &mparent_image_cache);
159 })));
160 }
161 };
162
163 TEST_F(TestMockParentCacheObjectDispatch, test_initialization_success) {
164 librbd::ImageCtx* ictx;
165 ASSERT_EQ(0, open_image(m_image_name, &ictx));
166 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
167 mock_image_ctx.child = &mock_image_ctx;
168
169 MockPluginApi mock_plugin_api;
170 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
171 mock_plugin_api);
172
173 expect_cache_run(*mock_parent_image_cache, 0);
174 C_SaferCond cond;
175 Context* handle_connect = new LambdaContext([&cond](int ret) {
176 ASSERT_EQ(ret, 0);
177 cond.complete(0);
178 });
179 expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
180 Context* ctx = new LambdaContext([](bool reg) {
181 ASSERT_EQ(reg, true);
182 });
183 expect_cache_register(*mock_parent_image_cache, ctx, 0);
184 expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
185 expect_cache_close(*mock_parent_image_cache, 0);
186 expect_cache_stop(*mock_parent_image_cache, 0);
187
188 mock_parent_image_cache->init();
189 cond.wait();
190
191 ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
192 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
193 expect_cache_session_state(*mock_parent_image_cache, true);
194 ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
195
196 mock_parent_image_cache->get_cache_client()->close();
197 mock_parent_image_cache->get_cache_client()->stop();
198
199 delete mock_parent_image_cache;
200 }
201
202 TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_connect) {
203 librbd::ImageCtx* ictx;
204 ASSERT_EQ(0, open_image(m_image_name, &ictx));
205 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
206 mock_image_ctx.child = &mock_image_ctx;
207
208 MockPluginApi mock_plugin_api;
209 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
210 mock_plugin_api);
211
212 expect_cache_run(*mock_parent_image_cache, 0);
213 C_SaferCond cond;
214 Context* handle_connect = new LambdaContext([&cond](int ret) {
215 ASSERT_EQ(ret, -1);
216 cond.complete(0);
217 });
218 expect_cache_async_connect(*mock_parent_image_cache, -1, handle_connect);
219 expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
220 expect_cache_session_state(*mock_parent_image_cache, false);
221 expect_cache_close(*mock_parent_image_cache, 0);
222 expect_cache_stop(*mock_parent_image_cache, 0);
223
224 mock_parent_image_cache->init();
225
226 // initialization fails.
227 ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
228 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
229 ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), false);
230
231 mock_parent_image_cache->get_cache_client()->close();
232 mock_parent_image_cache->get_cache_client()->stop();
233
234 delete mock_parent_image_cache;
235
236 }
237
238 TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_register) {
239 librbd::ImageCtx* ictx;
240 ASSERT_EQ(0, open_image(m_image_name, &ictx));
241 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
242 mock_image_ctx.child = &mock_image_ctx;
243
244 MockPluginApi mock_plugin_api;
245 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
246 mock_plugin_api);
247
248 expect_cache_run(*mock_parent_image_cache, 0);
249 C_SaferCond cond;
250 Context* handle_connect = new LambdaContext([&cond](int ret) {
251 ASSERT_EQ(ret, 0);
252 cond.complete(0);
253 });
254 expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
255 Context* ctx = new LambdaContext([](bool reg) {
256 ASSERT_EQ(reg, false);
257 });
258 expect_cache_register(*mock_parent_image_cache, ctx, -1);
259 expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
260 expect_cache_close(*mock_parent_image_cache, 0);
261 expect_cache_stop(*mock_parent_image_cache, 0);
262
263 mock_parent_image_cache->init();
264 cond.wait();
265
266 ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
267 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
268 expect_cache_session_state(*mock_parent_image_cache, true);
269 ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
270
271 mock_parent_image_cache->get_cache_client()->close();
272 mock_parent_image_cache->get_cache_client()->stop();
273
274 delete mock_parent_image_cache;
275 }
276
277 TEST_F(TestMockParentCacheObjectDispatch, test_disble_interface) {
278 librbd::ImageCtx* ictx;
279 ASSERT_EQ(0, open_image(m_image_name, &ictx));
280 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
281 mock_image_ctx.child = &mock_image_ctx;
282
283 MockPluginApi mock_plugin_api;
284 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
285 mock_plugin_api);
286
287 std::string temp_oid("12345");
288 ceph::bufferlist temp_bl;
289 IOContext io_context = mock_image_ctx.get_data_io_context();
290 io::DispatchResult* temp_dispatch_result = nullptr;
291 io::Extents temp_buffer_extents;
292 int* temp_op_flags = nullptr;
293 uint64_t* temp_journal_tid = nullptr;
294 Context** temp_on_finish = nullptr;
295 Context* temp_on_dispatched = nullptr;
296 ZTracer::Trace* temp_trace = nullptr;
297 io::LightweightBufferExtents buffer_extents;
298
299 ASSERT_EQ(mock_parent_image_cache->discard(0, 0, 0, io_context, 0,
300 *temp_trace, temp_op_flags, temp_journal_tid, temp_dispatch_result,
301 temp_on_finish, temp_on_dispatched), false);
302 ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl),
303 io_context, 0, 0, std::nullopt, *temp_trace, temp_op_flags,
304 temp_journal_tid, temp_dispatch_result, temp_on_finish,
305 temp_on_dispatched), false);
306 ASSERT_EQ(mock_parent_image_cache->write_same(0, 0, 0, std::move(buffer_extents),
307 std::move(temp_bl), io_context, 0, *temp_trace, temp_op_flags,
308 temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false );
309 ASSERT_EQ(mock_parent_image_cache->compare_and_write(0, 0, std::move(temp_bl), std::move(temp_bl),
310 io_context, 0, *temp_trace, temp_journal_tid, temp_op_flags,
311 temp_journal_tid, temp_dispatch_result, temp_on_finish,
312 temp_on_dispatched), false);
313 ASSERT_EQ(mock_parent_image_cache->flush(io::FLUSH_SOURCE_USER, *temp_trace, temp_journal_tid,
314 temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
315 ASSERT_EQ(mock_parent_image_cache->invalidate_cache(nullptr), false);
316 ASSERT_EQ(mock_parent_image_cache->reset_existence_cache(nullptr), false);
317
318 delete mock_parent_image_cache;
319
320 }
321
322 TEST_F(TestMockParentCacheObjectDispatch, test_read) {
323 librbd::ImageCtx* ictx;
324 ASSERT_EQ(0, open_image(m_image_name, &ictx));
325 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
326 mock_image_ctx.child = &mock_image_ctx;
327
328 MockPluginApi mock_plugin_api;
329 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
330 mock_plugin_api);
331
332 expect_cache_run(*mock_parent_image_cache, 0);
333 C_SaferCond conn_cond;
334 Context* handle_connect = new LambdaContext([&conn_cond](int ret) {
335 ASSERT_EQ(ret, 0);
336 conn_cond.complete(0);
337 });
338 expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
339 Context* ctx = new LambdaContext([](bool reg) {
340 ASSERT_EQ(reg, true);
341 });
342 expect_cache_register(*mock_parent_image_cache, ctx, 0);
343 expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
344 expect_cache_close(*mock_parent_image_cache, 0);
345 expect_cache_stop(*mock_parent_image_cache, 0);
346
347 mock_parent_image_cache->init();
348 conn_cond.wait();
349
350 ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
351 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
352 expect_cache_session_state(*mock_parent_image_cache, true);
353 ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true);
354
355 auto& expect = EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work());
356 expect.WillOnce(Return(true));
357
358 expect_cache_lookup_object(*mock_parent_image_cache, "/dev/null");
359
360 C_SaferCond on_dispatched;
361 io::DispatchResult dispatch_result;
362 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
363 mock_parent_image_cache->read(
364 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
365 nullptr, &dispatch_result, nullptr, &on_dispatched);
366 ASSERT_EQ(0, on_dispatched.wait());
367
368 mock_parent_image_cache->get_cache_client()->close();
369 mock_parent_image_cache->get_cache_client()->stop();
370 delete mock_parent_image_cache;
371 }
372
373 TEST_F(TestMockParentCacheObjectDispatch, test_read_dne) {
374 librbd::ImageCtx* ictx;
375 ASSERT_EQ(0, open_image(m_image_name, &ictx));
376 MockParentImageCacheImageCtx mock_image_ctx(*ictx);
377 mock_image_ctx.child = &mock_image_ctx;
378
379 MockPluginApi mock_plugin_api;
380 auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx,
381 mock_plugin_api);
382
383 expect_cache_run(*mock_parent_image_cache, 0);
384 C_SaferCond conn_cond;
385 Context* handle_connect = new LambdaContext([&conn_cond](int ret) {
386 ASSERT_EQ(ret, 0);
387 conn_cond.complete(0);
388 });
389 expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect);
390 Context* ctx = new LambdaContext([](bool reg) {
391 ASSERT_EQ(reg, true);
392 });
393 expect_cache_register(*mock_parent_image_cache, ctx, 0);
394 expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0);
395 expect_cache_close(*mock_parent_image_cache, 0);
396 expect_cache_stop(*mock_parent_image_cache, 0);
397
398 mock_parent_image_cache->init();
399 conn_cond.wait();
400
401 ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(),
402 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE);
403 expect_cache_session_state(*mock_parent_image_cache, true);
404 ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(),
405 true);
406
407 EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work())
408 .WillOnce(Return(true));
409
410 expect_cache_lookup_object(*mock_parent_image_cache, "");
411
412 io::ReadExtents extents = {{0, 4096}};
413 expect_read_parent(mock_plugin_api, 0, &extents, CEPH_NOSNAP, 0);
414
415 C_SaferCond on_dispatched;
416 io::DispatchResult dispatch_result;
417 mock_parent_image_cache->read(
418 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
419 nullptr, &dispatch_result, nullptr, &on_dispatched);
420 ASSERT_EQ(0, on_dispatched.wait());
421
422 mock_parent_image_cache->get_cache_client()->close();
423 mock_parent_image_cache->get_cache_client()->stop();
424 delete mock_parent_image_cache;
425 }
426
427 } // namespace librbd