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 "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"
18 struct MockManagedLockImageCtx : public MockImageCtx {
19 MockManagedLockImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {}
24 struct Traits<MockManagedLockImageCtx> {
25 typedef librbd::MockImageWatcher Watcher;
29 namespace managed_lock {
33 static std::list<T *> s_requests;
34 Context *on_finish = nullptr;
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();
47 s_requests.push_back(reinterpret_cast<T*>(this));
52 std::list<T *> BaseRequest<T>::s_requests;
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,
63 return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie, on_finish);
66 MOCK_METHOD0(send, void());
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,
78 MOCK_METHOD0(send, void());
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,
89 MOCK_METHOD0(send, void());
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");
101 assert(0 == "unexpected call");
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");
116 assert(0 == "unexpected call");
120 } // namespace managed_lock
121 } // namespace librbd
123 // template definitions
124 #include "librbd/ManagedLock.cc"
125 template class librbd::ManagedLock<librbd::MockManagedLockImageCtx>;
128 ACTION_P3(QueueRequest, request, r, wq) {
129 if (request->on_finish != nullptr) {
131 wq->queue(request->on_finish, r);
133 request->on_finish->complete(r);
138 ACTION_P2(QueueContext, r, wq) {
145 using ::testing::DoAll;
146 using ::testing::Invoke;
147 using ::testing::InSequence;
148 using ::testing::Return;
150 class TestMockManagedLock : public TestMockFixture {
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;
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));
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));
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));
177 void expect_reacquire_lock(MockImageWatcher& watcher,
178 ContextWQ *work_queue,
179 MockReacquireRequest &mock_reacquire_request,
181 expect_get_watch_handle(watcher, 98765);
182 EXPECT_CALL(mock_reacquire_request, send())
183 .WillOnce(QueueRequest(&mock_reacquire_request, r, work_queue));
186 void expect_flush_notifies(MockImageWatcher *mock_watcher) {
187 EXPECT_CALL(*mock_watcher, flush(_))
188 .WillOnce(CompleteContext(0, (ContextWQ *)nullptr));
191 int when_acquire_lock(MockManagedLock &managed_lock) {
194 managed_lock.acquire_lock(&ctx);
198 int when_release_lock(MockManagedLock &managed_lock) {
201 managed_lock.release_lock(&ctx);
205 int when_shut_down(MockManagedLock &managed_lock) {
208 managed_lock.shut_down(&ctx);
213 bool is_lock_owner(MockManagedLock &managed_lock) {
214 return managed_lock.is_lock_owner();
218 TEST_F(TestMockManagedLock, StateTransitions) {
219 librbd::ImageCtx *ictx;
220 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
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));
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));
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));
249 TEST_F(TestMockManagedLock, AcquireLockLockedState) {
250 librbd::ImageCtx *ictx;
251 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
264 MockReleaseRequest shutdown_release;
265 expect_release_lock(ictx->op_work_queue, shutdown_release, 0);
266 ASSERT_EQ(0, when_shut_down(managed_lock));
269 TEST_F(TestMockManagedLock, AcquireLockAlreadyLocked) {
270 librbd::ImageCtx *ictx;
271 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
284 ASSERT_EQ(0, when_shut_down(managed_lock));
287 TEST_F(TestMockManagedLock, AcquireLockBusy) {
288 librbd::ImageCtx *ictx;
289 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
302 ASSERT_EQ(0, when_shut_down(managed_lock));
305 TEST_F(TestMockManagedLock, AcquireLockError) {
306 librbd::ImageCtx *ictx;
307 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
315 MockAcquireRequest try_lock_acquire;
316 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, try_lock_acquire, -EINVAL);
318 ASSERT_EQ(-EINVAL, when_acquire_lock(managed_lock));
319 ASSERT_FALSE(is_lock_owner(managed_lock));
321 ASSERT_EQ(0, when_shut_down(managed_lock));
324 TEST_F(TestMockManagedLock, AcquireLockBlacklist) {
325 librbd::ImageCtx *ictx;
326 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
340 ASSERT_EQ(0, when_shut_down(managed_lock));
343 TEST_F(TestMockManagedLock, ReleaseLockUnlockedState) {
344 librbd::ImageCtx *ictx;
345 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
353 ASSERT_EQ(0, when_release_lock(managed_lock));
355 ASSERT_EQ(0, when_shut_down(managed_lock));
358 TEST_F(TestMockManagedLock, ReleaseLockError) {
359 librbd::ImageCtx *ictx;
360 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
372 MockReleaseRequest release;
373 expect_release_lock(ictx->op_work_queue, release, -EINVAL);
375 ASSERT_EQ(-EINVAL, when_release_lock(managed_lock));
376 ASSERT_TRUE(is_lock_owner(managed_lock));
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));
384 TEST_F(TestMockManagedLock, ConcurrentRequests) {
385 librbd::ImageCtx *ictx;
386 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
394 expect_get_watch_handle(*mock_image_ctx.image_watcher);
396 C_SaferCond wait_for_send_ctx1;
397 MockAcquireRequest acquire_error;
398 EXPECT_CALL(acquire_error, send())
399 .WillOnce(Notify(&wait_for_send_ctx1));
401 MockAcquireRequest request_acquire;
402 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, request_acquire, 0);
404 MockReleaseRequest release;
405 C_SaferCond wait_for_send_ctx2;
406 EXPECT_CALL(release, send())
407 .WillOnce(Notify(&wait_for_send_ctx2));
409 C_SaferCond acquire_request_ctx1;
410 managed_lock.acquire_lock(&acquire_request_ctx1);
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);
418 ASSERT_EQ(0, wait_for_send_ctx1.wait());
419 acquire_error.on_finish->complete(-EINVAL);
420 ASSERT_EQ(-EINVAL, acquire_request_ctx1.wait());
422 C_SaferCond acquire_lock_ctx3;
423 managed_lock.acquire_lock(&acquire_lock_ctx3);
425 C_SaferCond release_lock_ctx1;
426 managed_lock.release_lock(&release_lock_ctx1);
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());
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());
438 ASSERT_EQ(0, when_shut_down(managed_lock));
441 TEST_F(TestMockManagedLock, ReacquireLock) {
442 librbd::ImageCtx *ictx;
443 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
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());
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));
468 TEST_F(TestMockManagedLock, ReacquireLockError) {
469 librbd::ImageCtx *ictx;
470 ASSERT_EQ(0, open_image(m_image_name, &ictx));
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);
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));
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);
487 MockReleaseRequest reacquire_lock_release;
488 expect_release_lock(ictx->op_work_queue, reacquire_lock_release, 0);
490 MockAcquireRequest reacquire_lock_acquire;
491 expect_acquire_lock(*mock_image_ctx.image_watcher, ictx->op_work_queue, reacquire_lock_acquire, 0);
493 managed_lock.reacquire_lock(&reacquire_ctx);
494 ASSERT_EQ(-EOPNOTSUPP, reacquire_ctx.wait());
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));
502 } // namespace librbd