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