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 "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"
17 using namespace ceph::immutable_obj_cache
;
23 struct MockParentImageCacheImageCtx
: public MockImageCtx
{
24 MockParentImageCacheImageCtx(ImageCtx
& image_ctx
)
25 : MockImageCtx(image_ctx
) {
27 ~MockParentImageCacheImageCtx() {}
30 } // anonymous namespace
35 struct TypeTraits
<MockParentImageCacheImageCtx
> {
36 typedef ceph::immutable_obj_cache::MockCacheClient CacheClient
;
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
*));
53 #include "librbd/cache/ParentCacheObjectDispatch.cc"
54 template class librbd::cache::ParentCacheObjectDispatch
<librbd::MockParentImageCacheImageCtx
>;
59 using ::testing::DoAll
;
60 using ::testing::Invoke
;
61 using ::testing::InSequence
;
62 using ::testing::Return
;
63 using ::testing::WithArg
;
64 using ::testing::WithArgs
;
66 class TestMockParentCacheObjectDispatch
: public TestMockFixture
{
68 typedef cache::ParentCacheObjectDispatch
<librbd::MockParentImageCacheImageCtx
> MockParentImageCache
;
69 typedef plugin::Api
<MockParentImageCacheImageCtx
> MockPluginApi
;
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());
75 expect
.WillOnce((Invoke([]() {
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());
82 expect
.WillOnce((Invoke([ret_val
]() {
87 void expect_cache_connect(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
88 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), connect());
90 expect
.WillOnce((Invoke([ret_val
]() {
95 void expect_cache_async_connect(MockParentImageCache
& mparent_image_cache
, int ret_val
,
97 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), connect(_
));
99 expect
.WillOnce(WithArg
<0>(Invoke([on_finish
, ret_val
](Context
* ctx
) {
100 ctx
->complete(ret_val
);
101 on_finish
->complete(ret_val
);
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
);
115 void expect_read_parent(MockPluginApi
&mock_plugin_api
, uint64_t object_no
,
116 io::ReadExtents
* extents
, librados::snap_t snap_id
,
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))));
123 void expect_cache_close(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
124 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), close());
126 expect
.WillOnce((Invoke([]() {
130 void expect_cache_stop(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
131 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), stop());
133 expect
.WillOnce((Invoke([]() {
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(_
));
140 expect
.WillOnce(WithArg
<0>(Invoke([mock_handle_register
, ret_val
](Context
* ctx
) {
142 mock_handle_register
->complete(true);
144 mock_handle_register
->complete(false);
151 void expect_io_object_dispatcher_register_state(MockParentImageCache
& mparent_image_cache
,
153 auto& expect
= EXPECT_CALL((*(mparent_image_cache
.get_image_ctx()->io_object_dispatcher
)),
154 register_dispatch(_
));
156 expect
.WillOnce(WithArg
<0>(Invoke([&mparent_image_cache
]
157 (io::ObjectDispatchInterface
* object_dispatch
) {
158 ASSERT_EQ(object_dispatch
, &mparent_image_cache
);
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
;
169 MockPluginApi mock_plugin_api
;
170 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
173 expect_cache_run(*mock_parent_image_cache
, 0);
175 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
179 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
180 Context
* ctx
= new LambdaContext([](bool reg
) {
181 ASSERT_EQ(reg
, true);
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);
188 mock_parent_image_cache
->init();
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);
196 mock_parent_image_cache
->get_cache_client()->close();
197 mock_parent_image_cache
->get_cache_client()->stop();
199 delete mock_parent_image_cache
;
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
;
208 MockPluginApi mock_plugin_api
;
209 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
212 expect_cache_run(*mock_parent_image_cache
, 0);
214 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
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);
224 mock_parent_image_cache
->init();
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);
231 mock_parent_image_cache
->get_cache_client()->close();
232 mock_parent_image_cache
->get_cache_client()->stop();
234 delete mock_parent_image_cache
;
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
;
244 MockPluginApi mock_plugin_api
;
245 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
248 expect_cache_run(*mock_parent_image_cache
, 0);
250 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
254 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
255 Context
* ctx
= new LambdaContext([](bool reg
) {
256 ASSERT_EQ(reg
, false);
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);
263 mock_parent_image_cache
->init();
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);
271 mock_parent_image_cache
->get_cache_client()->close();
272 mock_parent_image_cache
->get_cache_client()->stop();
274 delete mock_parent_image_cache
;
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
;
283 MockPluginApi mock_plugin_api
;
284 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
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
;
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);
318 delete mock_parent_image_cache
;
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
;
328 MockPluginApi mock_plugin_api
;
329 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
332 expect_cache_run(*mock_parent_image_cache
, 0);
333 C_SaferCond conn_cond
;
334 Context
* handle_connect
= new LambdaContext([&conn_cond
](int ret
) {
336 conn_cond
.complete(0);
338 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
339 Context
* ctx
= new LambdaContext([](bool reg
) {
340 ASSERT_EQ(reg
, true);
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);
347 mock_parent_image_cache
->init();
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);
355 auto& expect
= EXPECT_CALL(*(mock_parent_image_cache
->get_cache_client()), is_session_work());
356 expect
.WillOnce(Return(true));
358 expect_cache_lookup_object(*mock_parent_image_cache
, "/dev/null");
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());
368 mock_parent_image_cache
->get_cache_client()->close();
369 mock_parent_image_cache
->get_cache_client()->stop();
370 delete mock_parent_image_cache
;
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
;
379 MockPluginApi mock_plugin_api
;
380 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
,
383 expect_cache_run(*mock_parent_image_cache
, 0);
384 C_SaferCond conn_cond
;
385 Context
* handle_connect
= new LambdaContext([&conn_cond
](int ret
) {
387 conn_cond
.complete(0);
389 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
390 Context
* ctx
= new LambdaContext([](bool reg
) {
391 ASSERT_EQ(reg
, true);
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);
398 mock_parent_image_cache
->init();
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(),
407 EXPECT_CALL(*(mock_parent_image_cache
->get_cache_client()), is_session_work())
408 .WillOnce(Return(true));
410 expect_cache_lookup_object(*mock_parent_image_cache
, "");
412 io::ReadExtents extents
= {{0, 4096}};
413 expect_read_parent(mock_plugin_api
, 0, &extents
, CEPH_NOSNAP
, 0);
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());
422 mock_parent_image_cache
->get_cache_client()->close();
423 mock_parent_image_cache
->get_cache_client()->stop();
424 delete mock_parent_image_cache
;
427 } // namespace librbd