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/io/Utils.h"
13 #include "librbd/cache/ParentCacheObjectDispatch.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
;
47 static Mock
* s_instance
;
53 MOCK_METHOD8(read_parent
,
54 void(librbd::MockParentImageCacheImageCtx
*, uint64_t, uint64_t,
55 uint64_t, librados::snap_t
, const ZTracer::Trace
&,
56 ceph::bufferlist
*, Context
*));
59 Mock
*Mock::s_instance
= nullptr;
61 } // anonymous namespace
63 template<> void read_parent(
64 librbd::MockParentImageCacheImageCtx
*image_ctx
, uint64_t object_no
,
65 uint64_t off
, uint64_t len
, librados::snap_t snap_id
,
66 const ZTracer::Trace
&trace
, ceph::bufferlist
* data
, Context
* on_finish
) {
67 Mock::s_instance
->read_parent(image_ctx
, object_no
, off
, len
, snap_id
, trace
,
74 }; // namespace librbd
76 #include "librbd/cache/ParentCacheObjectDispatch.cc"
77 template class librbd::cache::ParentCacheObjectDispatch
<librbd::MockParentImageCacheImageCtx
>;
82 using ::testing::DoAll
;
83 using ::testing::Invoke
;
84 using ::testing::InSequence
;
85 using ::testing::Return
;
86 using ::testing::WithArg
;
87 using ::testing::WithArgs
;
89 class TestMockParentCacheObjectDispatch
: public TestMockFixture
{
91 typedef cache::ParentCacheObjectDispatch
<librbd::MockParentImageCacheImageCtx
> MockParentImageCache
;
92 typedef io::util::Mock MockUtils
;
94 // ====== mock cache client ====
95 void expect_cache_run(MockParentImageCache
& mparent_image_cache
, bool ret_val
) {
96 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), run());
98 expect
.WillOnce((Invoke([ret_val
]() {
102 void expect_cache_session_state(MockParentImageCache
& mparent_image_cache
, bool ret_val
) {
103 auto & expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), is_session_work());
105 expect
.WillOnce((Invoke([ret_val
]() {
110 void expect_cache_connect(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
111 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), connect());
113 expect
.WillOnce((Invoke([ret_val
]() {
118 void expect_cache_async_connect(MockParentImageCache
& mparent_image_cache
, int ret_val
,
119 Context
* on_finish
) {
120 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), connect(_
));
122 expect
.WillOnce(WithArg
<0>(Invoke([on_finish
, ret_val
](Context
* ctx
) {
123 ctx
->complete(ret_val
);
124 on_finish
->complete(ret_val
);
128 void expect_cache_lookup_object(MockParentImageCache
& mparent_image_cache
,
129 const std::string
&cache_path
) {
130 EXPECT_CALL(*(mparent_image_cache
.get_cache_client()),
131 lookup_object(_
, _
, _
, _
, _
))
132 .WillOnce(WithArg
<4>(Invoke([cache_path
](CacheGenContextURef on_finish
) {
133 auto ack
= new ObjectCacheReadReplyData(RBDSC_READ_REPLY
, 0, cache_path
);
134 on_finish
.release()->complete(ack
);
138 void expect_read_parent(MockUtils
&mock_utils
, uint64_t object_no
,
139 uint64_t off
, uint64_t len
, librados::snap_t snap_id
,
141 EXPECT_CALL(mock_utils
,
142 read_parent(_
, object_no
, off
, len
, snap_id
, _
, _
, _
))
143 .WillOnce(WithArg
<7>(CompleteContext(r
, static_cast<ContextWQ
*>(nullptr))));
146 void expect_cache_close(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
147 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), close());
149 expect
.WillOnce((Invoke([ret_val
]() {
153 void expect_cache_stop(MockParentImageCache
& mparent_image_cache
, int ret_val
) {
154 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), stop());
156 expect
.WillOnce((Invoke([ret_val
]() {
160 void expect_cache_register(MockParentImageCache
& mparent_image_cache
, Context
* mock_handle_register
, int ret_val
) {
161 auto& expect
= EXPECT_CALL(*(mparent_image_cache
.get_cache_client()), register_client(_
));
163 expect
.WillOnce(WithArg
<0>(Invoke([mock_handle_register
, ret_val
](Context
* ctx
) {
165 mock_handle_register
->complete(true);
167 mock_handle_register
->complete(false);
174 void expect_io_object_dispatcher_register_state(MockParentImageCache
& mparent_image_cache
,
176 auto& expect
= EXPECT_CALL((*(mparent_image_cache
.get_image_ctx()->io_object_dispatcher
)),
177 register_object_dispatch(_
));
179 expect
.WillOnce(WithArg
<0>(Invoke([ret_val
, &mparent_image_cache
]
180 (io::ObjectDispatchInterface
* object_dispatch
) {
181 ASSERT_EQ(object_dispatch
, &mparent_image_cache
);
186 TEST_F(TestMockParentCacheObjectDispatch
, test_initialization_success
) {
187 librbd::ImageCtx
* ictx
;
188 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
189 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
190 mock_image_ctx
.child
= &mock_image_ctx
;
192 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
194 expect_cache_run(*mock_parent_image_cache
, 0);
196 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
200 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
201 Context
* ctx
= new LambdaContext([](bool reg
) {
202 ASSERT_EQ(reg
, true);
204 expect_cache_register(*mock_parent_image_cache
, ctx
, 0);
205 expect_io_object_dispatcher_register_state(*mock_parent_image_cache
, 0);
206 expect_cache_close(*mock_parent_image_cache
, 0);
207 expect_cache_stop(*mock_parent_image_cache
, 0);
209 mock_parent_image_cache
->init();
212 ASSERT_EQ(mock_parent_image_cache
->get_object_dispatch_layer(),
213 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE
);
214 expect_cache_session_state(*mock_parent_image_cache
, true);
215 ASSERT_EQ(mock_parent_image_cache
->get_cache_client()->is_session_work(), true);
217 mock_parent_image_cache
->get_cache_client()->close();
218 mock_parent_image_cache
->get_cache_client()->stop();
220 delete mock_parent_image_cache
;
223 TEST_F(TestMockParentCacheObjectDispatch
, test_initialization_fail_at_connect
) {
224 librbd::ImageCtx
* ictx
;
225 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
226 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
227 mock_image_ctx
.child
= &mock_image_ctx
;
229 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
231 expect_cache_run(*mock_parent_image_cache
, 0);
233 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
237 expect_cache_async_connect(*mock_parent_image_cache
, -1, handle_connect
);
238 expect_io_object_dispatcher_register_state(*mock_parent_image_cache
, 0);
239 expect_cache_session_state(*mock_parent_image_cache
, false);
240 expect_cache_close(*mock_parent_image_cache
, 0);
241 expect_cache_stop(*mock_parent_image_cache
, 0);
243 mock_parent_image_cache
->init();
245 // initialization fails.
246 ASSERT_EQ(mock_parent_image_cache
->get_object_dispatch_layer(),
247 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE
);
248 ASSERT_EQ(mock_parent_image_cache
->get_cache_client()->is_session_work(), false);
250 mock_parent_image_cache
->get_cache_client()->close();
251 mock_parent_image_cache
->get_cache_client()->stop();
253 delete mock_parent_image_cache
;
257 TEST_F(TestMockParentCacheObjectDispatch
, test_initialization_fail_at_register
) {
258 librbd::ImageCtx
* ictx
;
259 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
260 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
261 mock_image_ctx
.child
= &mock_image_ctx
;
263 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
265 expect_cache_run(*mock_parent_image_cache
, 0);
267 Context
* handle_connect
= new LambdaContext([&cond
](int ret
) {
271 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
272 Context
* ctx
= new LambdaContext([](bool reg
) {
273 ASSERT_EQ(reg
, false);
275 expect_cache_register(*mock_parent_image_cache
, ctx
, -1);
276 expect_io_object_dispatcher_register_state(*mock_parent_image_cache
, 0);
277 expect_cache_close(*mock_parent_image_cache
, 0);
278 expect_cache_stop(*mock_parent_image_cache
, 0);
280 mock_parent_image_cache
->init();
283 ASSERT_EQ(mock_parent_image_cache
->get_object_dispatch_layer(),
284 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE
);
285 expect_cache_session_state(*mock_parent_image_cache
, true);
286 ASSERT_EQ(mock_parent_image_cache
->get_cache_client()->is_session_work(), true);
288 mock_parent_image_cache
->get_cache_client()->close();
289 mock_parent_image_cache
->get_cache_client()->stop();
291 delete mock_parent_image_cache
;
294 TEST_F(TestMockParentCacheObjectDispatch
, test_disble_interface
) {
295 librbd::ImageCtx
* ictx
;
296 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
297 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
298 mock_image_ctx
.child
= &mock_image_ctx
;
300 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
302 std::string
temp_oid("12345");
303 ceph::bufferlist temp_bl
;
304 ::SnapContext
*temp_snapc
= nullptr;
305 io::DispatchResult
* temp_dispatch_result
= nullptr;
306 io::Extents temp_buffer_extents
;
307 int* temp_op_flags
= nullptr;
308 uint64_t* temp_journal_tid
= nullptr;
309 Context
** temp_on_finish
= nullptr;
310 Context
* temp_on_dispatched
= nullptr;
311 ZTracer::Trace
* temp_trace
= nullptr;
312 io::LightweightBufferExtents buffer_extents
;
314 ASSERT_EQ(mock_parent_image_cache
->discard(0, 0, 0, *temp_snapc
, 0, *temp_trace
, temp_op_flags
,
315 temp_journal_tid
, temp_dispatch_result
, temp_on_finish
, temp_on_dispatched
), false);
316 ASSERT_EQ(mock_parent_image_cache
->write(0, 0, std::move(temp_bl
), *temp_snapc
, 0,
317 *temp_trace
, temp_op_flags
, temp_journal_tid
, temp_dispatch_result
,
318 temp_on_finish
, temp_on_dispatched
), false);
319 ASSERT_EQ(mock_parent_image_cache
->write_same(0, 0, 0, std::move(buffer_extents
),
320 std::move(temp_bl
), *temp_snapc
, 0, *temp_trace
, temp_op_flags
,
321 temp_journal_tid
, temp_dispatch_result
, temp_on_finish
, temp_on_dispatched
), false );
322 ASSERT_EQ(mock_parent_image_cache
->compare_and_write(0, 0, std::move(temp_bl
), std::move(temp_bl
),
323 *temp_snapc
, 0, *temp_trace
, temp_journal_tid
, temp_op_flags
, temp_journal_tid
,
324 temp_dispatch_result
, temp_on_finish
, temp_on_dispatched
), false);
325 ASSERT_EQ(mock_parent_image_cache
->flush(io::FLUSH_SOURCE_USER
, *temp_trace
, temp_journal_tid
,
326 temp_dispatch_result
, temp_on_finish
, temp_on_dispatched
), false);
327 ASSERT_EQ(mock_parent_image_cache
->invalidate_cache(nullptr), false);
328 ASSERT_EQ(mock_parent_image_cache
->reset_existence_cache(nullptr), false);
330 delete mock_parent_image_cache
;
334 TEST_F(TestMockParentCacheObjectDispatch
, test_read
) {
335 librbd::ImageCtx
* ictx
;
336 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
337 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
338 mock_image_ctx
.child
= &mock_image_ctx
;
340 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
342 expect_cache_run(*mock_parent_image_cache
, 0);
343 C_SaferCond conn_cond
;
344 Context
* handle_connect
= new LambdaContext([&conn_cond
](int ret
) {
346 conn_cond
.complete(0);
348 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
349 Context
* ctx
= new LambdaContext([](bool reg
) {
350 ASSERT_EQ(reg
, true);
352 expect_cache_register(*mock_parent_image_cache
, ctx
, 0);
353 expect_io_object_dispatcher_register_state(*mock_parent_image_cache
, 0);
354 expect_cache_close(*mock_parent_image_cache
, 0);
355 expect_cache_stop(*mock_parent_image_cache
, 0);
357 mock_parent_image_cache
->init();
360 ASSERT_EQ(mock_parent_image_cache
->get_object_dispatch_layer(),
361 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE
);
362 expect_cache_session_state(*mock_parent_image_cache
, true);
363 ASSERT_EQ(mock_parent_image_cache
->get_cache_client()->is_session_work(), true);
365 auto& expect
= EXPECT_CALL(*(mock_parent_image_cache
->get_cache_client()), is_session_work());
366 expect
.WillOnce(Return(true));
368 expect_cache_lookup_object(*mock_parent_image_cache
, "/dev/null");
370 C_SaferCond on_dispatched
;
371 io::DispatchResult dispatch_result
;
372 ceph::bufferlist read_data
;
373 mock_parent_image_cache
->read(0, 0, 4096, CEPH_NOSNAP
, 0, {}, &read_data
,
374 nullptr, nullptr, &dispatch_result
, nullptr,
376 ASSERT_EQ(0, on_dispatched
.wait());
378 mock_parent_image_cache
->get_cache_client()->close();
379 mock_parent_image_cache
->get_cache_client()->stop();
380 delete mock_parent_image_cache
;
383 TEST_F(TestMockParentCacheObjectDispatch
, test_read_dne
) {
384 librbd::ImageCtx
* ictx
;
385 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
386 MockParentImageCacheImageCtx
mock_image_ctx(*ictx
);
387 mock_image_ctx
.child
= &mock_image_ctx
;
389 auto mock_parent_image_cache
= MockParentImageCache::create(&mock_image_ctx
);
391 expect_cache_run(*mock_parent_image_cache
, 0);
392 C_SaferCond conn_cond
;
393 Context
* handle_connect
= new LambdaContext([&conn_cond
](int ret
) {
395 conn_cond
.complete(0);
397 expect_cache_async_connect(*mock_parent_image_cache
, 0, handle_connect
);
398 Context
* ctx
= new LambdaContext([](bool reg
) {
399 ASSERT_EQ(reg
, true);
401 expect_cache_register(*mock_parent_image_cache
, ctx
, 0);
402 expect_io_object_dispatcher_register_state(*mock_parent_image_cache
, 0);
403 expect_cache_close(*mock_parent_image_cache
, 0);
404 expect_cache_stop(*mock_parent_image_cache
, 0);
406 mock_parent_image_cache
->init();
409 ASSERT_EQ(mock_parent_image_cache
->get_object_dispatch_layer(),
410 io::OBJECT_DISPATCH_LAYER_PARENT_CACHE
);
411 expect_cache_session_state(*mock_parent_image_cache
, true);
412 ASSERT_EQ(mock_parent_image_cache
->get_cache_client()->is_session_work(),
415 EXPECT_CALL(*(mock_parent_image_cache
->get_cache_client()), is_session_work())
416 .WillOnce(Return(true));
418 expect_cache_lookup_object(*mock_parent_image_cache
, "");
420 MockUtils mock_utils
;
421 expect_read_parent(mock_utils
, 0, 0, 4096, CEPH_NOSNAP
, 0);
423 C_SaferCond on_dispatched
;
424 io::DispatchResult dispatch_result
;
425 mock_parent_image_cache
->read(0, 0, 4096, CEPH_NOSNAP
, 0, {}, nullptr,
426 nullptr, nullptr, &dispatch_result
, nullptr,
428 ASSERT_EQ(0, on_dispatched
.wait());
430 mock_parent_image_cache
->get_cache_client()->close();
431 mock_parent_image_cache
->get_cache_client()->stop();
432 delete mock_parent_image_cache
;
435 } // namespace librbd