]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc
99de2551212a501990a6ecc8a3943bcd3cea5fac
[ceph.git] / ceph / src / test / librbd / exclusive_lock / test_mock_PreReleaseRequest.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/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"
14 #include <list>
15
16 // template definitions
17 #include "librbd/exclusive_lock/PreReleaseRequest.cc"
18 template class librbd::exclusive_lock::PreReleaseRequest<librbd::MockImageCtx>;
19
20 namespace librbd {
21
22 namespace exclusive_lock {
23
24 namespace {
25
26 struct MockContext : public Context {
27 MOCK_METHOD1(complete, void(int));
28 MOCK_METHOD1(finish, void(int));
29 };
30
31 } // anonymous namespace
32
33 using ::testing::_;
34 using ::testing::InSequence;
35 using ::testing::Invoke;
36 using ::testing::Return;
37 using ::testing::StrEq;
38 using ::testing::WithArg;
39
40 static const std::string TEST_COOKIE("auto 123");
41
42 class TestMockExclusiveLockPreReleaseRequest : public TestMockFixture {
43 public:
44 typedef PreReleaseRequest<MockImageCtx> MockPreReleaseRequest;
45
46 void expect_complete_context(MockContext &mock_context, int r) {
47 EXPECT_CALL(mock_context, complete(r));
48 }
49
50 void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features,
51 bool enabled) {
52 EXPECT_CALL(mock_image_ctx, test_features(features))
53 .WillOnce(Return(enabled));
54 }
55
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());
58 }
59
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);
65 }
66 EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_))
67 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
68 }
69
70 void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
71 EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes());
72 }
73
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));
77 }
78
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));
83 }
84
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));
89 }
90
91 void expect_invalidate_cache(MockImageCtx &mock_image_ctx, bool purge,
92 int r) {
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))));
96 }
97 }
98
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));
103 }
104 }
105
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));
109 }
110
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);
115 }));
116 }
117
118 void expect_handle_prepare_lock_complete(MockImageCtx &mock_image_ctx) {
119 EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
120 }
121
122 AsyncOpTracker m_async_op_tracker;
123 };
124
125 TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) {
126 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
127
128 librbd::ImageCtx *ictx;
129 ASSERT_EQ(0, open_image(m_image_name, &ictx));
130
131 MockImageCtx mock_image_ctx(*ictx);
132 expect_op_work_queue(mock_image_ctx);
133
134 InSequence seq;
135
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);
141
142 MockJournal *mock_journal = new MockJournal();
143 mock_image_ctx.journal = mock_journal;
144 expect_close_journal(mock_image_ctx, *mock_journal, -EINVAL);
145
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);
149
150 expect_handle_prepare_lock_complete(mock_image_ctx);
151
152 C_SaferCond ctx;
153 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
154 mock_image_ctx, false, m_async_op_tracker, &ctx);
155 req->send();
156 ASSERT_EQ(0, ctx.wait());
157 }
158
159 TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessJournalDisabled) {
160 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
161
162 librbd::ImageCtx *ictx;
163 ASSERT_EQ(0, open_image(m_image_name, &ictx));
164
165 MockImageCtx mock_image_ctx(*ictx);
166
167 expect_block_writes(mock_image_ctx, 0);
168 expect_op_work_queue(mock_image_ctx);
169
170 InSequence seq;
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);
175
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);
179
180 expect_handle_prepare_lock_complete(mock_image_ctx);
181
182 C_SaferCond ctx;
183 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
184 mock_image_ctx, false, m_async_op_tracker, &ctx);
185 req->send();
186 ASSERT_EQ(0, ctx.wait());
187 }
188
189 TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessObjectMapDisabled) {
190 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
191
192 librbd::ImageCtx *ictx;
193 ASSERT_EQ(0, open_image(m_image_name, &ictx));
194
195 MockImageCtx mock_image_ctx(*ictx);
196
197 expect_block_writes(mock_image_ctx, 0);
198 expect_op_work_queue(mock_image_ctx);
199
200 InSequence seq;
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);
204
205 C_SaferCond release_ctx;
206 C_SaferCond ctx;
207 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
208 mock_image_ctx, true, m_async_op_tracker, &ctx);
209 req->send();
210 ASSERT_EQ(0, ctx.wait());
211 }
212
213 TEST_F(TestMockExclusiveLockPreReleaseRequest, Blacklisted) {
214 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
215
216 librbd::ImageCtx *ictx;
217 ASSERT_EQ(0, open_image(m_image_name, &ictx));
218
219 MockImageCtx mock_image_ctx(*ictx);
220 expect_op_work_queue(mock_image_ctx);
221
222 InSequence seq;
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);
231
232 MockJournal *mock_journal = new MockJournal();
233 mock_image_ctx.journal = mock_journal;
234 expect_close_journal(mock_image_ctx, *mock_journal, -EBLACKLISTED);
235
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);
239
240 expect_handle_prepare_lock_complete(mock_image_ctx);
241
242 C_SaferCond ctx;
243 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
244 mock_image_ctx, false, m_async_op_tracker, &ctx);
245 req->send();
246 ASSERT_EQ(0, ctx.wait());
247 }
248
249 TEST_F(TestMockExclusiveLockPreReleaseRequest, BlockWritesError) {
250 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
251
252 librbd::ImageCtx *ictx;
253 ASSERT_EQ(0, open_image(m_image_name, &ictx));
254
255 MockImageCtx mock_image_ctx(*ictx);
256
257 expect_op_work_queue(mock_image_ctx);
258
259 InSequence seq;
260 expect_cancel_op_requests(mock_image_ctx, 0);
261 expect_block_writes(mock_image_ctx, -EINVAL);
262 expect_unblock_writes(mock_image_ctx);
263
264 C_SaferCond ctx;
265 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
266 mock_image_ctx, true, m_async_op_tracker, &ctx);
267 req->send();
268 ASSERT_EQ(-EINVAL, ctx.wait());
269 }
270
271 TEST_F(TestMockExclusiveLockPreReleaseRequest, UnlockError) {
272 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
273
274 librbd::ImageCtx *ictx;
275 ASSERT_EQ(0, open_image(m_image_name, &ictx));
276
277 MockImageCtx mock_image_ctx(*ictx);
278
279 expect_op_work_queue(mock_image_ctx);
280
281 InSequence seq;
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);
286
287 C_SaferCond ctx;
288 MockPreReleaseRequest *req = MockPreReleaseRequest::create(
289 mock_image_ctx, true, m_async_op_tracker, &ctx);
290 req->send();
291 ASSERT_EQ(0, ctx.wait());
292 }
293
294 } // namespace exclusive_lock
295 } // namespace librbd