]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
11fdf7f2 | 9 | #include "test/librbd/mock/io/MockObjectDispatch.h" |
7c673cae | 10 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" |
31f18b77 | 11 | #include "common/AsyncOpTracker.h" |
7c673cae FG |
12 | #include "librbd/exclusive_lock/PreReleaseRequest.h" |
13 | #include "gmock/gmock.h" | |
14 | #include "gtest/gtest.h" | |
15 | #include <list> | |
16 | ||
17 | // template definitions | |
18 | #include "librbd/exclusive_lock/PreReleaseRequest.cc" | |
19 | template class librbd::exclusive_lock::PreReleaseRequest<librbd::MockImageCtx>; | |
20 | ||
21 | namespace librbd { | |
22 | ||
23 | namespace exclusive_lock { | |
24 | ||
25 | namespace { | |
26 | ||
27 | struct MockContext : public Context { | |
28 | MOCK_METHOD1(complete, void(int)); | |
29 | MOCK_METHOD1(finish, void(int)); | |
30 | }; | |
31 | ||
32 | } // anonymous namespace | |
33 | ||
34 | using ::testing::_; | |
35 | using ::testing::InSequence; | |
36 | using ::testing::Invoke; | |
37 | using ::testing::Return; | |
38 | using ::testing::StrEq; | |
39 | using ::testing::WithArg; | |
40 | ||
41 | static const std::string TEST_COOKIE("auto 123"); | |
42 | ||
43 | class TestMockExclusiveLockPreReleaseRequest : public TestMockFixture { | |
44 | public: | |
45 | typedef PreReleaseRequest<MockImageCtx> MockPreReleaseRequest; | |
46 | ||
47 | void expect_complete_context(MockContext &mock_context, int r) { | |
48 | EXPECT_CALL(mock_context, complete(r)); | |
49 | } | |
50 | ||
51 | void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features, | |
52 | bool enabled) { | |
53 | EXPECT_CALL(mock_image_ctx, test_features(features)) | |
54 | .WillOnce(Return(enabled)); | |
55 | } | |
56 | ||
224ce89b WB |
57 | void expect_set_require_lock(MockImageCtx &mock_image_ctx, |
58 | librbd::io::Direction direction, bool enabled) { | |
59 | EXPECT_CALL(*mock_image_ctx.io_work_queue, set_require_lock(direction, | |
60 | enabled)); | |
7c673cae FG |
61 | } |
62 | ||
63 | void expect_block_writes(MockImageCtx &mock_image_ctx, int r) { | |
64 | expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, | |
65 | ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0)); | |
224ce89b WB |
66 | if (mock_image_ctx.clone_copy_on_read || |
67 | (mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) { | |
68 | expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_BOTH, true); | |
69 | } else { | |
70 | expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_WRITE, | |
71 | true); | |
7c673cae FG |
72 | } |
73 | EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_)) | |
74 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
75 | } | |
76 | ||
77 | void expect_unblock_writes(MockImageCtx &mock_image_ctx) { | |
78 | EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes()); | |
79 | } | |
80 | ||
81 | void expect_cancel_op_requests(MockImageCtx &mock_image_ctx, int r) { | |
82 | EXPECT_CALL(mock_image_ctx, cancel_async_requests(_)) | |
83 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
84 | } | |
85 | ||
86 | void expect_close_journal(MockImageCtx &mock_image_ctx, | |
87 | MockJournal &mock_journal, int r) { | |
88 | EXPECT_CALL(mock_journal, close(_)) | |
89 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
90 | } | |
91 | ||
92 | void expect_close_object_map(MockImageCtx &mock_image_ctx, | |
93 | MockObjectMap &mock_object_map) { | |
94 | EXPECT_CALL(mock_object_map, close(_)) | |
95 | .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)); | |
96 | } | |
97 | ||
11fdf7f2 | 98 | void expect_invalidate_cache(MockImageCtx &mock_image_ctx, |
7c673cae | 99 | int r) { |
11fdf7f2 TL |
100 | EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, invalidate_cache(_)) |
101 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
7c673cae FG |
102 | } |
103 | ||
104 | void expect_flush_notifies(MockImageCtx &mock_image_ctx) { | |
105 | EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_)) | |
106 | .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)); | |
107 | } | |
108 | ||
109 | void expect_prepare_lock(MockImageCtx &mock_image_ctx) { | |
110 | EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_)) | |
111 | .WillOnce(Invoke([](Context *on_ready) { | |
112 | on_ready->complete(0); | |
113 | })); | |
114 | } | |
115 | ||
116 | void expect_handle_prepare_lock_complete(MockImageCtx &mock_image_ctx) { | |
117 | EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete()); | |
118 | } | |
119 | ||
31f18b77 | 120 | AsyncOpTracker m_async_op_tracker; |
7c673cae FG |
121 | }; |
122 | ||
123 | TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) { | |
124 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
125 | ||
126 | librbd::ImageCtx *ictx; | |
127 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
128 | ||
129 | MockImageCtx mock_image_ctx(*ictx); | |
130 | expect_op_work_queue(mock_image_ctx); | |
131 | ||
132 | InSequence seq; | |
133 | ||
134 | expect_prepare_lock(mock_image_ctx); | |
135 | expect_cancel_op_requests(mock_image_ctx, 0); | |
136 | expect_block_writes(mock_image_ctx, 0); | |
11fdf7f2 TL |
137 | expect_invalidate_cache(mock_image_ctx, 0); |
138 | ||
7c673cae FG |
139 | expect_flush_notifies(mock_image_ctx); |
140 | ||
9f95a23c TL |
141 | MockJournal mock_journal; |
142 | mock_image_ctx.journal = &mock_journal; | |
143 | expect_close_journal(mock_image_ctx, mock_journal, -EINVAL); | |
7c673cae | 144 | |
9f95a23c TL |
145 | MockObjectMap mock_object_map; |
146 | mock_image_ctx.object_map = &mock_object_map; | |
147 | expect_close_object_map(mock_image_ctx, mock_object_map); | |
7c673cae FG |
148 | |
149 | expect_handle_prepare_lock_complete(mock_image_ctx); | |
150 | ||
151 | C_SaferCond ctx; | |
152 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 153 | mock_image_ctx, false, m_async_op_tracker, &ctx); |
7c673cae FG |
154 | req->send(); |
155 | ASSERT_EQ(0, ctx.wait()); | |
156 | } | |
157 | ||
158 | TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessJournalDisabled) { | |
159 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
160 | ||
161 | librbd::ImageCtx *ictx; | |
162 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
163 | ||
164 | MockImageCtx mock_image_ctx(*ictx); | |
165 | ||
166 | expect_block_writes(mock_image_ctx, 0); | |
167 | expect_op_work_queue(mock_image_ctx); | |
168 | ||
169 | InSequence seq; | |
170 | expect_prepare_lock(mock_image_ctx); | |
171 | expect_cancel_op_requests(mock_image_ctx, 0); | |
11fdf7f2 TL |
172 | expect_invalidate_cache(mock_image_ctx, 0); |
173 | ||
7c673cae FG |
174 | expect_flush_notifies(mock_image_ctx); |
175 | ||
9f95a23c TL |
176 | MockObjectMap mock_object_map; |
177 | mock_image_ctx.object_map = &mock_object_map; | |
178 | expect_close_object_map(mock_image_ctx, mock_object_map); | |
7c673cae FG |
179 | |
180 | expect_handle_prepare_lock_complete(mock_image_ctx); | |
181 | ||
182 | C_SaferCond ctx; | |
183 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 184 | mock_image_ctx, false, m_async_op_tracker, &ctx); |
7c673cae FG |
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); | |
11fdf7f2 TL |
202 | expect_invalidate_cache(mock_image_ctx, 0); |
203 | ||
7c673cae FG |
204 | expect_flush_notifies(mock_image_ctx); |
205 | ||
206 | C_SaferCond release_ctx; | |
207 | C_SaferCond ctx; | |
208 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 209 | mock_image_ctx, true, m_async_op_tracker, &ctx); |
7c673cae FG |
210 | req->send(); |
211 | ASSERT_EQ(0, ctx.wait()); | |
212 | } | |
213 | ||
214 | TEST_F(TestMockExclusiveLockPreReleaseRequest, Blacklisted) { | |
215 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
216 | ||
217 | librbd::ImageCtx *ictx; | |
218 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
219 | ||
220 | MockImageCtx mock_image_ctx(*ictx); | |
221 | expect_op_work_queue(mock_image_ctx); | |
222 | ||
223 | InSequence seq; | |
224 | expect_prepare_lock(mock_image_ctx); | |
225 | expect_cancel_op_requests(mock_image_ctx, 0); | |
226 | expect_block_writes(mock_image_ctx, -EBLACKLISTED); | |
11fdf7f2 TL |
227 | expect_invalidate_cache(mock_image_ctx, -EBLACKLISTED); |
228 | ||
7c673cae FG |
229 | expect_flush_notifies(mock_image_ctx); |
230 | ||
9f95a23c TL |
231 | MockJournal mock_journal; |
232 | mock_image_ctx.journal = &mock_journal; | |
233 | expect_close_journal(mock_image_ctx, mock_journal, -EBLACKLISTED); | |
7c673cae | 234 | |
9f95a23c TL |
235 | MockObjectMap mock_object_map; |
236 | mock_image_ctx.object_map = &mock_object_map; | |
237 | expect_close_object_map(mock_image_ctx, mock_object_map); | |
7c673cae FG |
238 | |
239 | expect_handle_prepare_lock_complete(mock_image_ctx); | |
240 | ||
241 | C_SaferCond ctx; | |
242 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 243 | mock_image_ctx, false, m_async_op_tracker, &ctx); |
7c673cae FG |
244 | req->send(); |
245 | ASSERT_EQ(0, ctx.wait()); | |
246 | } | |
247 | ||
248 | TEST_F(TestMockExclusiveLockPreReleaseRequest, BlockWritesError) { | |
249 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
250 | ||
251 | librbd::ImageCtx *ictx; | |
252 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
253 | ||
254 | MockImageCtx mock_image_ctx(*ictx); | |
255 | ||
256 | expect_op_work_queue(mock_image_ctx); | |
257 | ||
258 | InSequence seq; | |
259 | expect_cancel_op_requests(mock_image_ctx, 0); | |
260 | expect_block_writes(mock_image_ctx, -EINVAL); | |
261 | expect_unblock_writes(mock_image_ctx); | |
262 | ||
263 | C_SaferCond ctx; | |
264 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 265 | mock_image_ctx, true, m_async_op_tracker, &ctx); |
7c673cae FG |
266 | req->send(); |
267 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
268 | } | |
269 | ||
270 | TEST_F(TestMockExclusiveLockPreReleaseRequest, UnlockError) { | |
271 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
272 | ||
273 | librbd::ImageCtx *ictx; | |
274 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
275 | ||
276 | MockImageCtx mock_image_ctx(*ictx); | |
277 | ||
278 | expect_op_work_queue(mock_image_ctx); | |
279 | ||
280 | InSequence seq; | |
281 | expect_cancel_op_requests(mock_image_ctx, 0); | |
282 | expect_block_writes(mock_image_ctx, 0); | |
11fdf7f2 TL |
283 | expect_invalidate_cache(mock_image_ctx, 0); |
284 | ||
7c673cae FG |
285 | expect_flush_notifies(mock_image_ctx); |
286 | ||
287 | C_SaferCond ctx; | |
288 | MockPreReleaseRequest *req = MockPreReleaseRequest::create( | |
31f18b77 | 289 | mock_image_ctx, true, m_async_op_tracker, &ctx); |
7c673cae FG |
290 | req->send(); |
291 | ASSERT_EQ(0, ctx.wait()); | |
292 | } | |
293 | ||
294 | } // namespace exclusive_lock | |
295 | } // namespace librbd |