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 "test/librbd/mock/MockJournal.h"
8 #include "test/librbd/mock/MockObjectMap.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "common/AsyncOpTracker.h"
11 #include "librbd/exclusive_lock/PreReleaseRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
16 // template definitions
17 #include "librbd/exclusive_lock/PreReleaseRequest.cc"
18 template class librbd::exclusive_lock::PreReleaseRequest
<librbd::MockImageCtx
>;
22 namespace exclusive_lock
{
26 struct MockContext
: public Context
{
27 MOCK_METHOD1(complete
, void(int));
28 MOCK_METHOD1(finish
, void(int));
31 } // anonymous namespace
34 using ::testing::InSequence
;
35 using ::testing::Invoke
;
36 using ::testing::Return
;
37 using ::testing::StrEq
;
38 using ::testing::WithArg
;
40 static const std::string
TEST_COOKIE("auto 123");
42 class TestMockExclusiveLockPreReleaseRequest
: public TestMockFixture
{
44 typedef PreReleaseRequest
<MockImageCtx
> MockPreReleaseRequest
;
46 void expect_complete_context(MockContext
&mock_context
, int r
) {
47 EXPECT_CALL(mock_context
, complete(r
));
50 void expect_test_features(MockImageCtx
&mock_image_ctx
, uint64_t features
,
52 EXPECT_CALL(mock_image_ctx
, test_features(features
))
53 .WillOnce(Return(enabled
));
56 void expect_set_require_lock_on_read(MockImageCtx
&mock_image_ctx
) {
57 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, set_require_lock_on_read());
60 void expect_block_writes(MockImageCtx
&mock_image_ctx
, int r
) {
61 expect_test_features(mock_image_ctx
, RBD_FEATURE_JOURNALING
,
62 ((mock_image_ctx
.features
& RBD_FEATURE_JOURNALING
) != 0));
63 if ((mock_image_ctx
.features
& RBD_FEATURE_JOURNALING
) != 0) {
64 expect_set_require_lock_on_read(mock_image_ctx
);
66 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, block_writes(_
))
67 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
70 void expect_unblock_writes(MockImageCtx
&mock_image_ctx
) {
71 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, unblock_writes());
74 void expect_cancel_op_requests(MockImageCtx
&mock_image_ctx
, int r
) {
75 EXPECT_CALL(mock_image_ctx
, cancel_async_requests(_
))
76 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
79 void expect_close_journal(MockImageCtx
&mock_image_ctx
,
80 MockJournal
&mock_journal
, int r
) {
81 EXPECT_CALL(mock_journal
, close(_
))
82 .WillOnce(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
));
85 void expect_close_object_map(MockImageCtx
&mock_image_ctx
,
86 MockObjectMap
&mock_object_map
) {
87 EXPECT_CALL(mock_object_map
, close(_
))
88 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
91 void expect_invalidate_cache(MockImageCtx
&mock_image_ctx
, bool purge
,
93 if (mock_image_ctx
.object_cacher
!= nullptr) {
94 EXPECT_CALL(mock_image_ctx
, invalidate_cache(purge
, _
))
95 .WillOnce(WithArg
<1>(CompleteContext(r
, static_cast<ContextWQ
*>(NULL
))));
99 void expect_is_cache_empty(MockImageCtx
&mock_image_ctx
, bool empty
) {
100 if (mock_image_ctx
.object_cacher
!= nullptr) {
101 EXPECT_CALL(mock_image_ctx
, is_cache_empty())
102 .WillOnce(Return(empty
));
106 void expect_flush_notifies(MockImageCtx
&mock_image_ctx
) {
107 EXPECT_CALL(*mock_image_ctx
.image_watcher
, flush(_
))
108 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
111 void expect_prepare_lock(MockImageCtx
&mock_image_ctx
) {
112 EXPECT_CALL(*mock_image_ctx
.state
, prepare_lock(_
))
113 .WillOnce(Invoke([](Context
*on_ready
) {
114 on_ready
->complete(0);
118 void expect_handle_prepare_lock_complete(MockImageCtx
&mock_image_ctx
) {
119 EXPECT_CALL(*mock_image_ctx
.state
, handle_prepare_lock_complete());
122 AsyncOpTracker m_async_op_tracker
;
125 TEST_F(TestMockExclusiveLockPreReleaseRequest
, Success
) {
126 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
128 librbd::ImageCtx
*ictx
;
129 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
131 MockImageCtx
mock_image_ctx(*ictx
);
132 expect_op_work_queue(mock_image_ctx
);
136 expect_prepare_lock(mock_image_ctx
);
137 expect_cancel_op_requests(mock_image_ctx
, 0);
138 expect_block_writes(mock_image_ctx
, 0);
139 expect_invalidate_cache(mock_image_ctx
, false, 0);
140 expect_flush_notifies(mock_image_ctx
);
142 MockJournal
*mock_journal
= new MockJournal();
143 mock_image_ctx
.journal
= mock_journal
;
144 expect_close_journal(mock_image_ctx
, *mock_journal
, -EINVAL
);
146 MockObjectMap
*mock_object_map
= new MockObjectMap();
147 mock_image_ctx
.object_map
= mock_object_map
;
148 expect_close_object_map(mock_image_ctx
, *mock_object_map
);
150 expect_handle_prepare_lock_complete(mock_image_ctx
);
153 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
154 mock_image_ctx
, false, m_async_op_tracker
, &ctx
);
156 ASSERT_EQ(0, ctx
.wait());
159 TEST_F(TestMockExclusiveLockPreReleaseRequest
, SuccessJournalDisabled
) {
160 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
162 librbd::ImageCtx
*ictx
;
163 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
165 MockImageCtx
mock_image_ctx(*ictx
);
167 expect_block_writes(mock_image_ctx
, 0);
168 expect_op_work_queue(mock_image_ctx
);
171 expect_prepare_lock(mock_image_ctx
);
172 expect_cancel_op_requests(mock_image_ctx
, 0);
173 expect_invalidate_cache(mock_image_ctx
, false, 0);
174 expect_flush_notifies(mock_image_ctx
);
176 MockObjectMap
*mock_object_map
= new MockObjectMap();
177 mock_image_ctx
.object_map
= mock_object_map
;
178 expect_close_object_map(mock_image_ctx
, *mock_object_map
);
180 expect_handle_prepare_lock_complete(mock_image_ctx
);
183 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
184 mock_image_ctx
, false, m_async_op_tracker
, &ctx
);
186 ASSERT_EQ(0, ctx
.wait());
189 TEST_F(TestMockExclusiveLockPreReleaseRequest
, SuccessObjectMapDisabled
) {
190 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
192 librbd::ImageCtx
*ictx
;
193 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
195 MockImageCtx
mock_image_ctx(*ictx
);
197 expect_block_writes(mock_image_ctx
, 0);
198 expect_op_work_queue(mock_image_ctx
);
201 expect_cancel_op_requests(mock_image_ctx
, 0);
202 expect_invalidate_cache(mock_image_ctx
, false, 0);
203 expect_flush_notifies(mock_image_ctx
);
205 C_SaferCond release_ctx
;
207 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
208 mock_image_ctx
, true, m_async_op_tracker
, &ctx
);
210 ASSERT_EQ(0, ctx
.wait());
213 TEST_F(TestMockExclusiveLockPreReleaseRequest
, Blacklisted
) {
214 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
216 librbd::ImageCtx
*ictx
;
217 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
219 MockImageCtx
mock_image_ctx(*ictx
);
220 expect_op_work_queue(mock_image_ctx
);
223 expect_prepare_lock(mock_image_ctx
);
224 expect_cancel_op_requests(mock_image_ctx
, 0);
225 expect_block_writes(mock_image_ctx
, -EBLACKLISTED
);
226 expect_invalidate_cache(mock_image_ctx
, false, -EBLACKLISTED
);
227 expect_is_cache_empty(mock_image_ctx
, false);
228 expect_invalidate_cache(mock_image_ctx
, true, -EBLACKLISTED
);
229 expect_is_cache_empty(mock_image_ctx
, true);
230 expect_flush_notifies(mock_image_ctx
);
232 MockJournal
*mock_journal
= new MockJournal();
233 mock_image_ctx
.journal
= mock_journal
;
234 expect_close_journal(mock_image_ctx
, *mock_journal
, -EBLACKLISTED
);
236 MockObjectMap
*mock_object_map
= new MockObjectMap();
237 mock_image_ctx
.object_map
= mock_object_map
;
238 expect_close_object_map(mock_image_ctx
, *mock_object_map
);
240 expect_handle_prepare_lock_complete(mock_image_ctx
);
243 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
244 mock_image_ctx
, false, m_async_op_tracker
, &ctx
);
246 ASSERT_EQ(0, ctx
.wait());
249 TEST_F(TestMockExclusiveLockPreReleaseRequest
, BlockWritesError
) {
250 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
252 librbd::ImageCtx
*ictx
;
253 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
255 MockImageCtx
mock_image_ctx(*ictx
);
257 expect_op_work_queue(mock_image_ctx
);
260 expect_cancel_op_requests(mock_image_ctx
, 0);
261 expect_block_writes(mock_image_ctx
, -EINVAL
);
262 expect_unblock_writes(mock_image_ctx
);
265 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
266 mock_image_ctx
, true, m_async_op_tracker
, &ctx
);
268 ASSERT_EQ(-EINVAL
, ctx
.wait());
271 TEST_F(TestMockExclusiveLockPreReleaseRequest
, UnlockError
) {
272 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
274 librbd::ImageCtx
*ictx
;
275 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
277 MockImageCtx
mock_image_ctx(*ictx
);
279 expect_op_work_queue(mock_image_ctx
);
282 expect_cancel_op_requests(mock_image_ctx
, 0);
283 expect_block_writes(mock_image_ctx
, 0);
284 expect_invalidate_cache(mock_image_ctx
, false, 0);
285 expect_flush_notifies(mock_image_ctx
);
288 MockPreReleaseRequest
*req
= MockPreReleaseRequest::create(
289 mock_image_ctx
, true, m_async_op_tracker
, &ctx
);
291 ASSERT_EQ(0, ctx
.wait());
294 } // namespace exclusive_lock
295 } // namespace librbd