]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_mock_ManagedLock.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / librbd / test_mock_ManagedLock.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 "librbd/ManagedLock.h"
7 #include "librbd/managed_lock/AcquireRequest.h"
8 #include "librbd/managed_lock/BreakRequest.h"
9 #include "librbd/managed_lock/GetLockerRequest.h"
10 #include "librbd/managed_lock/ReacquireRequest.h"
11 #include "librbd/managed_lock/ReleaseRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 #include <list>
15
16 namespace librbd {
17
18 struct MockManagedLockImageCtx : public MockImageCtx {
19 MockManagedLockImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {}
20 };
21
22 namespace watcher {
23 template <>
24 struct Traits<MockManagedLockImageCtx> {
25 typedef librbd::MockImageWatcher Watcher;
26 };
27 }
28
29 namespace managed_lock {
30
31 template<typename T>
32 struct BaseRequest {
33 static std::list<T *> s_requests;
34 Context *on_finish = nullptr;
35
36 static T* create(librados::IoCtx& ioctx, MockImageWatcher *watcher,
37 ContextWQ *work_queue, const std::string& oid,
38 const std::string& cookie, Context *on_finish) {
39 assert(!s_requests.empty());
40 T* req = s_requests.front();
41 req->on_finish = on_finish;
42 s_requests.pop_front();
43 return req;
44 }
45
46 BaseRequest() {
47 s_requests.push_back(reinterpret_cast<T*>(this));
48 }
49 };
50
51 template<typename T>
52 std::list<T *> BaseRequest<T>::s_requests;
53
54 template <>
55 struct AcquireRequest<MockManagedLockImageCtx> : public BaseRequest<AcquireRequest<MockManagedLockImageCtx> > {
56 static AcquireRequest* create(librados::IoCtx& ioctx,
57 MockImageWatcher *watcher,
58 ContextWQ *work_queue, const std::string& oid,
59 const std::string& cookie,
60 bool exclusive, bool blacklist_on_break_lock,
61 uint32_t blacklist_expire_seconds,
62 Context *on_finish) {
63 return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie, on_finish);
64 }
65
66 MOCK_METHOD0(send, void());
67 };
68
69 template <>
70 struct ReacquireRequest<MockManagedLockImageCtx> : public BaseRequest<ReacquireRequest<MockManagedLockImageCtx> > {
71 static ReacquireRequest* create(librados::IoCtx &ioctx, const std::string& oid,
72 const string& old_cookie, const std::string& new_cookie,
73 bool exclusive, Context *on_finish) {
74 return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie,
75 on_finish);
76 }
77
78 MOCK_METHOD0(send, void());
79 };
80
81 template <>
82 struct ReleaseRequest<MockManagedLockImageCtx> : public BaseRequest<ReleaseRequest<MockManagedLockImageCtx> > {
83 static ReleaseRequest* create(librados::IoCtx& ioctx, MockImageWatcher *watcher,
84 ContextWQ *work_queue, const std::string& oid,
85 const std::string& cookie, Context *on_finish) {
86 return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie,
87 on_finish);
88 }
89 MOCK_METHOD0(send, void());
90 };
91
92 template <>
93 struct GetLockerRequest<MockManagedLockImageCtx> {
94 static GetLockerRequest* create(librados::IoCtx& ioctx,
95 const std::string& oid, bool exclusive,
96 Locker *locker, Context *on_finish) {
97 assert(0 == "unexpected call");
98 }
99
100 void send() {
101 assert(0 == "unexpected call");
102 }
103 };
104
105 template <>
106 struct BreakRequest<MockManagedLockImageCtx> {
107 static BreakRequest* create(librados::IoCtx& ioctx, ContextWQ *work_queue,
108 const std::string& oid, const Locker &locker,
109 bool exclusive, bool blacklist_locker,
110 uint32_t blacklist_expire_seconds,
111 bool force_break_lock, Context *on_finish) {
112 assert(0 == "unexpected call");
113 }
114
115 void send() {
116 assert(0 == "unexpected call");
117 }
118 };
119
120 } // namespace managed_lock
121 } // namespace librbd
122
123 // template definitions
124 #include "librbd/ManagedLock.cc"
125 template class librbd::ManagedLock<librbd::MockManagedLockImageCtx>;
126
127
128 ACTION_P3(QueueRequest, request, r, wq) {
129 if (request->on_finish != nullptr) {
130 if (wq != nullptr) {
131 wq->queue(request->on_finish, r);
132 } else {
133 request->on_finish->complete(r);
134 }
135 }
136 }
137
138 ACTION_P2(QueueContext, r, wq) {
139 wq->queue(arg0, r);
140 }
141
142 namespace librbd {
143
144 using ::testing::_;
145 using ::testing::DoAll;
146 using ::testing::Invoke;
147 using ::testing::InSequence;
148 using ::testing::Return;
149
150 class TestMockManagedLock : public TestMockFixture {
151 public:
152 typedef ManagedLock<MockManagedLockImageCtx> MockManagedLock;
153 typedef managed_lock::AcquireRequest<MockManagedLockImageCtx> MockAcquireRequest;
154 typedef managed_lock::ReacquireRequest<MockManagedLockImageCtx> MockReacquireRequest;
155 typedef managed_lock::ReleaseRequest<MockManagedLockImageCtx> MockReleaseRequest;
156
157 void expect_get_watch_handle(MockImageWatcher &mock_watcher,
158 uint64_t watch_handle = 1234567890) {
159 EXPECT_CALL(mock_watcher, get_watch_handle())
160 .WillOnce(Return(watch_handle));
161 }
162
163 void expect_acquire_lock(MockImageWatcher &watcher,
164 ContextWQ *work_queue,
165 MockAcquireRequest &acquire_request, int r) {
166 expect_get_watch_handle(watcher);
167 EXPECT_CALL(acquire_request, send())
168 .WillOnce(QueueRequest(&acquire_request, r, work_queue));
169 }
170
171 void expect_release_lock(ContextWQ *work_queue,
172 MockReleaseRequest &release_request, int r) {
173 EXPECT_CALL(release_request, send())
174 .WillOnce(QueueRequest(&release_request, r, work_queue));
175 }
176
177 void expect_reacquire_lock(MockImageWatcher& watcher,
178 ContextWQ *work_queue,
179 MockReacquireRequest &mock_reacquire_request,
180 int r) {
181 expect_get_watch_handle(watcher, 98765);
182 EXPECT_CALL(mock_reacquire_request, send())
183 .WillOnce(QueueRequest(&mock_reacquire_request, r, work_queue));
184 }
185
186 void expect_flush_notifies(MockImageWatcher *mock_watcher) {
187 EXPECT_CALL(*mock_watcher, flush(_))
188 .WillOnce(CompleteContext(0, (ContextWQ *)nullptr));
189 }
190
191 int when_acquire_lock(MockManagedLock &managed_lock) {
192 C_SaferCond ctx;
193 {
194 managed_lock.acquire_lock(&ctx);
195 }
196 return ctx.wait();
197 }
198 int when_release_lock(MockManagedLock &managed_lock) {
199 C_SaferCond ctx;
200 {
201 managed_lock.release_lock(&ctx);
202 }
203 return ctx.wait();
204 }
205 int when_shut_down(MockManagedLock &managed_lock) {
206 C_SaferCond ctx;
207 {
208 managed_lock.shut_down(&ctx);
209 }
210 return ctx.wait();
211 }
212
213 bool is_lock_owner(MockManagedLock &managed_lock) {
214 return managed_lock.is_lock_owner();
215 }
216 };
217
218 TEST_F(TestMockManagedLock, StateTransitions) {
219 librbd::ImageCtx *ictx;
220 ASSERT_EQ(0, open_image(m_image_name, &ictx));
221
222 MockManagedLockImageCtx mock_image_ctx(*ictx);
223 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
224 ictx->header_oid, mock_image_ctx.image_watcher,
225 librbd::managed_lock::EXCLUSIVE, true, 0);
226 InSequence seq;
227
228 MockAcquireRequest request_lock_acquire1;
229 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_lock_acquire1, 0);
230 ASSERT_EQ(0, when_acquire_lock(managed_lock));
231 ASSERT_TRUE(is_lock_owner(managed_lock));
232
233 MockReleaseRequest request_release;
234 expect_release_lock(ictx->op_work_queue, request_release, 0);
235 ASSERT_EQ(0, when_release_lock(managed_lock));
236 ASSERT_FALSE(is_lock_owner(managed_lock));
237
238 MockAcquireRequest request_lock_acquire2;
239 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_lock_acquire2, 0);
240 ASSERT_EQ(0, when_acquire_lock(managed_lock));
241 ASSERT_TRUE(is_lock_owner(managed_lock));
242
243 MockReleaseRequest shutdown_release;
244 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
245 ASSERT_EQ(0, when_shut_down(managed_lock));
246 ASSERT_FALSE(is_lock_owner(managed_lock));
247 }
248
249 TEST_F(TestMockManagedLock, AcquireLockLockedState) {
250 librbd::ImageCtx *ictx;
251 ASSERT_EQ(0, open_image(m_image_name, &ictx));
252
253 MockManagedLockImageCtx mock_image_ctx(*ictx);
254 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
255 ictx->header_oid, mock_image_ctx.image_watcher,
256 librbd::managed_lock::EXCLUSIVE, true, 0);
257 InSequence seq;
258
259 MockAcquireRequest try_lock_acquire;
260 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, 0);
261 ASSERT_EQ(0, when_acquire_lock(managed_lock));
262 ASSERT_EQ(0, when_acquire_lock(managed_lock));
263
264 MockReleaseRequest shutdown_release;
265 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
266 ASSERT_EQ(0, when_shut_down(managed_lock));
267 }
268
269 TEST_F(TestMockManagedLock, AcquireLockAlreadyLocked) {
270 librbd::ImageCtx *ictx;
271 ASSERT_EQ(0, open_image(m_image_name, &ictx));
272
273 MockManagedLockImageCtx mock_image_ctx(*ictx);
274 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
275 ictx->header_oid, mock_image_ctx.image_watcher,
276 librbd::managed_lock::EXCLUSIVE, true, 0);
277 InSequence seq;
278
279 MockAcquireRequest try_lock_acquire;
280 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, -EAGAIN);
281 ASSERT_EQ(-EAGAIN, when_acquire_lock(managed_lock));
282 ASSERT_FALSE(is_lock_owner(managed_lock));
283
284 ASSERT_EQ(0, when_shut_down(managed_lock));
285 }
286
287 TEST_F(TestMockManagedLock, AcquireLockBusy) {
288 librbd::ImageCtx *ictx;
289 ASSERT_EQ(0, open_image(m_image_name, &ictx));
290
291 MockManagedLockImageCtx mock_image_ctx(*ictx);
292 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
293 ictx->header_oid, mock_image_ctx.image_watcher,
294 librbd::managed_lock::EXCLUSIVE, true, 0);
295 InSequence seq;
296
297 MockAcquireRequest try_lock_acquire;
298 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, -EBUSY);
299 ASSERT_EQ(-EBUSY, when_acquire_lock(managed_lock));
300 ASSERT_FALSE(is_lock_owner(managed_lock));
301
302 ASSERT_EQ(0, when_shut_down(managed_lock));
303 }
304
305 TEST_F(TestMockManagedLock, AcquireLockError) {
306 librbd::ImageCtx *ictx;
307 ASSERT_EQ(0, open_image(m_image_name, &ictx));
308
309 MockManagedLockImageCtx mock_image_ctx(*ictx);
310 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
311 ictx->header_oid, mock_image_ctx.image_watcher,
312 librbd::managed_lock::EXCLUSIVE, true, 0);
313 InSequence seq;
314
315 MockAcquireRequest try_lock_acquire;
316 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, -EINVAL);
317
318 ASSERT_EQ(-EINVAL, when_acquire_lock(managed_lock));
319 ASSERT_FALSE(is_lock_owner(managed_lock));
320
321 ASSERT_EQ(0, when_shut_down(managed_lock));
322 }
323
324 TEST_F(TestMockManagedLock, AcquireLockBlacklist) {
325 librbd::ImageCtx *ictx;
326 ASSERT_EQ(0, open_image(m_image_name, &ictx));
327
328 MockManagedLockImageCtx mock_image_ctx(*ictx);
329 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
330 ictx->header_oid, mock_image_ctx.image_watcher,
331 librbd::managed_lock::EXCLUSIVE, true, 0);
332 InSequence seq;
333
334 // will abort after seeing blacklist error (avoid infinite request loop)
335 MockAcquireRequest request_lock_acquire;
336 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_lock_acquire, -EBLACKLISTED);
337 ASSERT_EQ(-EBLACKLISTED, when_acquire_lock(managed_lock));
338 ASSERT_FALSE(is_lock_owner(managed_lock));
339
340 ASSERT_EQ(0, when_shut_down(managed_lock));
341 }
342
343 TEST_F(TestMockManagedLock, ReleaseLockUnlockedState) {
344 librbd::ImageCtx *ictx;
345 ASSERT_EQ(0, open_image(m_image_name, &ictx));
346
347 MockManagedLockImageCtx mock_image_ctx(*ictx);
348 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
349 ictx->header_oid, mock_image_ctx.image_watcher,
350 librbd::managed_lock::EXCLUSIVE, true, 0);
351 InSequence seq;
352
353 ASSERT_EQ(0, when_release_lock(managed_lock));
354
355 ASSERT_EQ(0, when_shut_down(managed_lock));
356 }
357
358 TEST_F(TestMockManagedLock, ReleaseLockError) {
359 librbd::ImageCtx *ictx;
360 ASSERT_EQ(0, open_image(m_image_name, &ictx));
361
362 MockManagedLockImageCtx mock_image_ctx(*ictx);
363 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
364 ictx->header_oid, mock_image_ctx.image_watcher,
365 librbd::managed_lock::EXCLUSIVE, true, 0);
366 InSequence seq;
367
368 MockAcquireRequest try_lock_acquire;
369 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, 0);
370 ASSERT_EQ(0, when_acquire_lock(managed_lock));
371
372 MockReleaseRequest release;
373 expect_release_lock(ictx->op_work_queue, release, -EINVAL);
374
375 ASSERT_EQ(-EINVAL, when_release_lock(managed_lock));
376 ASSERT_TRUE(is_lock_owner(managed_lock));
377
378 MockReleaseRequest shutdown_release;
379 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
380 ASSERT_EQ(0, when_shut_down(managed_lock));
381 ASSERT_FALSE(is_lock_owner(managed_lock));
382 }
383
384 TEST_F(TestMockManagedLock, ConcurrentRequests) {
385 librbd::ImageCtx *ictx;
386 ASSERT_EQ(0, open_image(m_image_name, &ictx));
387
388 MockManagedLockImageCtx mock_image_ctx(*ictx);
389 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
390 ictx->header_oid, mock_image_ctx.image_watcher,
391 librbd::managed_lock::EXCLUSIVE, true, 0);
392 InSequence seq;
393
394 expect_get_watch_handle(*mock_image_ctx.image_watcher);
395
396 C_SaferCond wait_for_send_ctx1;
397 MockAcquireRequest acquire_error;
398 EXPECT_CALL(acquire_error, send())
399 .WillOnce(Notify(&wait_for_send_ctx1));
400
401 MockAcquireRequest request_acquire;
402 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_acquire, 0);
403
404 MockReleaseRequest release;
405 C_SaferCond wait_for_send_ctx2;
406 EXPECT_CALL(release, send())
407 .WillOnce(Notify(&wait_for_send_ctx2));
408
409 C_SaferCond acquire_request_ctx1;
410 managed_lock.acquire_lock(&acquire_request_ctx1);
411
412 C_SaferCond acquire_lock_ctx1;
413 C_SaferCond acquire_lock_ctx2;
414 managed_lock.acquire_lock(&acquire_lock_ctx1);
415 managed_lock.acquire_lock(&acquire_lock_ctx2);
416
417 // fail the try_lock
418 ASSERT_EQ(0, wait_for_send_ctx1.wait());
419 acquire_error.on_finish->complete(-EINVAL);
420 ASSERT_EQ(-EINVAL, acquire_request_ctx1.wait());
421
422 C_SaferCond acquire_lock_ctx3;
423 managed_lock.acquire_lock(&acquire_lock_ctx3);
424
425 C_SaferCond release_lock_ctx1;
426 managed_lock.release_lock(&release_lock_ctx1);
427
428 // all three pending request locks should complete
429 ASSERT_EQ(-EINVAL, acquire_lock_ctx1.wait());
430 ASSERT_EQ(-EINVAL, acquire_lock_ctx2.wait());
431 ASSERT_EQ(0, acquire_lock_ctx3.wait());
432
433 // proceed with the release
434 ASSERT_EQ(0, wait_for_send_ctx2.wait());
435 release.on_finish->complete(0);
436 ASSERT_EQ(0, release_lock_ctx1.wait());
437
438 ASSERT_EQ(0, when_shut_down(managed_lock));
439 }
440
441 TEST_F(TestMockManagedLock, ReacquireLock) {
442 librbd::ImageCtx *ictx;
443 ASSERT_EQ(0, open_image(m_image_name, &ictx));
444
445 MockManagedLockImageCtx mock_image_ctx(*ictx);
446 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
447 ictx->header_oid, mock_image_ctx.image_watcher,
448 librbd::managed_lock::EXCLUSIVE, true, 0);
449 InSequence seq;
450
451 MockAcquireRequest request_lock_acquire;
452 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_lock_acquire, 0);
453 ASSERT_EQ(0, when_acquire_lock(managed_lock));
454 ASSERT_TRUE(is_lock_owner(managed_lock));
455
456 MockReacquireRequest mock_reacquire_request;
457 C_SaferCond reacquire_ctx;
458 expect_reacquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, mock_reacquire_request, 0);
459 managed_lock.reacquire_lock(&reacquire_ctx);
460 ASSERT_EQ(0, reacquire_ctx.wait());
461
462 MockReleaseRequest shutdown_release;
463 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
464 ASSERT_EQ(0, when_shut_down(managed_lock));
465 ASSERT_FALSE(is_lock_owner(managed_lock));
466 }
467
468 TEST_F(TestMockManagedLock, ReacquireLockError) {
469 librbd::ImageCtx *ictx;
470 ASSERT_EQ(0, open_image(m_image_name, &ictx));
471
472 MockManagedLockImageCtx mock_image_ctx(*ictx);
473 MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue,
474 ictx->header_oid, mock_image_ctx.image_watcher,
475 librbd::managed_lock::EXCLUSIVE, true, 0);
476 InSequence seq;
477
478 MockAcquireRequest request_lock_acquire;
479 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_lock_acquire, 0);
480 ASSERT_EQ(0, when_acquire_lock(managed_lock));
481 ASSERT_TRUE(is_lock_owner(managed_lock));
482
483 MockReacquireRequest mock_reacquire_request;
484 C_SaferCond reacquire_ctx;
485 expect_reacquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, mock_reacquire_request, -EOPNOTSUPP);
486
487 MockReleaseRequest reacquire_lock_release;
488 expect_release_lock(ictx->op_work_queue, reacquire_lock_release, 0);
489
490 MockAcquireRequest reacquire_lock_acquire;
491 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, reacquire_lock_acquire, 0);
492
493 managed_lock.reacquire_lock(&reacquire_ctx);
494 ASSERT_EQ(-EOPNOTSUPP, reacquire_ctx.wait());
495
496 MockReleaseRequest shutdown_release;
497 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
498 ASSERT_EQ(0, when_shut_down(managed_lock));
499 ASSERT_FALSE(is_lock_owner(managed_lock));
500 }
501
502 } // namespace librbd