]>
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 "librbd/Utils.h" | |
5 | #include "test/librbd/mock/MockImageCtx.h" | |
6 | #include "test/rbd_mirror/test_mock_fixture.h" | |
7 | #include "tools/rbd_mirror/LeaderWatcher.h" | |
8 | #include "tools/rbd_mirror/Threads.h" | |
9 | ||
10 | using librbd::util::create_async_context_callback; | |
11 | ||
12 | namespace librbd { | |
13 | ||
14 | namespace { | |
15 | ||
16 | struct MockTestImageCtx : public MockImageCtx { | |
17 | MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
18 | : librbd::MockImageCtx(image_ctx) { | |
19 | } | |
20 | }; | |
21 | ||
22 | } // anonymous namespace | |
23 | ||
24 | struct MockManagedLock { | |
25 | static MockManagedLock *s_instance; | |
26 | static MockManagedLock &get_instance() { | |
27 | assert(s_instance != nullptr); | |
28 | return *s_instance; | |
29 | } | |
30 | ||
31 | MockManagedLock() { | |
32 | s_instance = this; | |
33 | } | |
34 | ||
35 | bool m_release_lock_on_shutdown = false; | |
36 | ||
37 | MOCK_METHOD0(construct, void()); | |
38 | MOCK_METHOD0(destroy, void()); | |
39 | ||
40 | MOCK_CONST_METHOD0(is_lock_owner, bool()); | |
41 | ||
42 | MOCK_METHOD1(shut_down, void(Context *)); | |
43 | MOCK_METHOD1(try_acquire_lock, void(Context *)); | |
44 | MOCK_METHOD1(release_lock, void(Context *)); | |
91327a77 | 45 | MOCK_METHOD0(reacquire_lock, void()); |
7c673cae FG |
46 | MOCK_METHOD3(break_lock, void(const managed_lock::Locker &, bool, Context *)); |
47 | MOCK_METHOD2(get_locker, void(managed_lock::Locker *, Context *)); | |
48 | ||
49 | MOCK_METHOD0(set_state_post_acquiring, void()); | |
50 | ||
51 | MOCK_CONST_METHOD0(is_shutdown, bool()); | |
52 | ||
53 | MOCK_CONST_METHOD0(is_state_post_acquiring, bool()); | |
31f18b77 | 54 | MOCK_CONST_METHOD0(is_state_pre_releasing, bool()); |
7c673cae FG |
55 | MOCK_CONST_METHOD0(is_state_locked, bool()); |
56 | }; | |
57 | ||
58 | MockManagedLock *MockManagedLock::s_instance = nullptr; | |
59 | ||
60 | template <> | |
61 | struct ManagedLock<MockTestImageCtx> { | |
62 | ManagedLock(librados::IoCtx& ioctx, ContextWQ *work_queue, | |
63 | const std::string& oid, librbd::Watcher *watcher, | |
64 | managed_lock::Mode mode, bool blacklist_on_break_lock, | |
65 | uint32_t blacklist_expire_seconds) | |
66 | : m_work_queue(work_queue), m_lock("ManagedLock::m_lock") { | |
67 | MockManagedLock::get_instance().construct(); | |
68 | } | |
69 | ||
70 | virtual ~ManagedLock() { | |
71 | MockManagedLock::get_instance().destroy(); | |
72 | } | |
73 | ||
74 | ContextWQ *m_work_queue; | |
75 | ||
76 | mutable Mutex m_lock; | |
77 | ||
78 | bool is_lock_owner() const { | |
79 | return MockManagedLock::get_instance().is_lock_owner(); | |
80 | } | |
81 | ||
82 | void shut_down(Context *on_shutdown) { | |
83 | if (MockManagedLock::get_instance().m_release_lock_on_shutdown) { | |
84 | on_shutdown = new FunctionContext( | |
85 | [this, on_shutdown](int r) { | |
86 | MockManagedLock::get_instance().m_release_lock_on_shutdown = false; | |
87 | shut_down(on_shutdown); | |
88 | }); | |
89 | release_lock(on_shutdown); | |
90 | return; | |
91 | } | |
92 | ||
93 | MockManagedLock::get_instance().shut_down(on_shutdown); | |
94 | } | |
95 | ||
96 | void try_acquire_lock(Context *on_acquired) { | |
97 | Context *post_acquire_ctx = create_async_context_callback( | |
98 | m_work_queue, new FunctionContext( | |
99 | [this, on_acquired](int r) { | |
100 | post_acquire_lock_handler(r, on_acquired); | |
101 | })); | |
102 | MockManagedLock::get_instance().try_acquire_lock(post_acquire_ctx); | |
103 | } | |
104 | ||
105 | void release_lock(Context *on_released) { | |
106 | Context *post_release_ctx = new FunctionContext( | |
107 | [this, on_released](int r) { | |
108 | post_release_lock_handler(false, r, on_released); | |
109 | }); | |
110 | ||
111 | Context *release_ctx = new FunctionContext( | |
112 | [this, on_released, post_release_ctx](int r) { | |
113 | if (r < 0) { | |
114 | on_released->complete(r); | |
115 | } else { | |
116 | MockManagedLock::get_instance().release_lock(post_release_ctx); | |
117 | } | |
118 | }); | |
119 | ||
120 | Context *pre_release_ctx = new FunctionContext( | |
121 | [this, release_ctx](int r) { | |
122 | bool shutting_down = | |
123 | MockManagedLock::get_instance().m_release_lock_on_shutdown; | |
124 | pre_release_lock_handler(shutting_down, release_ctx); | |
125 | }); | |
126 | ||
127 | m_work_queue->queue(pre_release_ctx, 0); | |
128 | } | |
129 | ||
91327a77 AA |
130 | void reacquire_lock(Context* on_finish) { |
131 | MockManagedLock::get_instance().reacquire_lock(); | |
132 | } | |
133 | ||
7c673cae FG |
134 | void get_locker(managed_lock::Locker *locker, Context *on_finish) { |
135 | MockManagedLock::get_instance().get_locker(locker, on_finish); | |
136 | } | |
137 | ||
138 | void break_lock(const managed_lock::Locker &locker, bool force_break_lock, | |
139 | Context *on_finish) { | |
140 | MockManagedLock::get_instance().break_lock(locker, force_break_lock, | |
141 | on_finish); | |
142 | } | |
143 | ||
144 | void set_state_post_acquiring() { | |
145 | MockManagedLock::get_instance().set_state_post_acquiring(); | |
146 | } | |
147 | ||
148 | bool is_shutdown() const { | |
149 | return MockManagedLock::get_instance().is_shutdown(); | |
150 | } | |
151 | ||
152 | bool is_state_post_acquiring() const { | |
153 | return MockManagedLock::get_instance().is_state_post_acquiring(); | |
154 | } | |
155 | ||
31f18b77 FG |
156 | bool is_state_pre_releasing() const { |
157 | return MockManagedLock::get_instance().is_state_pre_releasing(); | |
158 | } | |
159 | ||
7c673cae FG |
160 | bool is_state_locked() const { |
161 | return MockManagedLock::get_instance().is_state_locked(); | |
162 | } | |
163 | ||
164 | virtual void post_acquire_lock_handler(int r, Context *on_finish) = 0; | |
165 | virtual void pre_release_lock_handler(bool shutting_down, | |
166 | Context *on_finish) = 0; | |
167 | virtual void post_release_lock_handler(bool shutting_down, int r, | |
168 | Context *on_finish) = 0; | |
169 | }; | |
170 | ||
171 | } // namespace librbd | |
172 | ||
173 | namespace rbd { | |
174 | namespace mirror { | |
175 | ||
176 | template <> | |
177 | struct Threads<librbd::MockTestImageCtx> { | |
178 | Mutex &timer_lock; | |
179 | SafeTimer *timer; | |
180 | ContextWQ *work_queue; | |
181 | ||
182 | Threads(Threads<librbd::ImageCtx> *threads) | |
183 | : timer_lock(threads->timer_lock), timer(threads->timer), | |
184 | work_queue(threads->work_queue) { | |
185 | } | |
186 | }; | |
187 | ||
188 | template <> | |
189 | struct MirrorStatusWatcher<librbd::MockTestImageCtx> { | |
190 | static MirrorStatusWatcher* s_instance; | |
191 | ||
192 | static MirrorStatusWatcher *create(librados::IoCtx &io_ctx, | |
193 | ContextWQ *work_queue) { | |
194 | assert(s_instance != nullptr); | |
195 | return s_instance; | |
196 | } | |
197 | ||
198 | MirrorStatusWatcher() { | |
199 | assert(s_instance == nullptr); | |
200 | s_instance = this; | |
201 | } | |
202 | ||
203 | ~MirrorStatusWatcher() { | |
204 | assert(s_instance == this); | |
205 | s_instance = nullptr; | |
206 | } | |
207 | ||
208 | MOCK_METHOD0(destroy, void()); | |
209 | MOCK_METHOD1(init, void(Context *)); | |
210 | MOCK_METHOD1(shut_down, void(Context *)); | |
211 | }; | |
212 | ||
213 | MirrorStatusWatcher<librbd::MockTestImageCtx> *MirrorStatusWatcher<librbd::MockTestImageCtx>::s_instance = nullptr; | |
214 | ||
215 | template <> | |
216 | struct Instances<librbd::MockTestImageCtx> { | |
217 | static Instances* s_instance; | |
218 | ||
219 | static Instances *create(Threads<librbd::MockTestImageCtx> *threads, | |
220 | librados::IoCtx &ioctx) { | |
221 | assert(s_instance != nullptr); | |
222 | return s_instance; | |
223 | } | |
224 | ||
225 | Instances() { | |
226 | assert(s_instance == nullptr); | |
227 | s_instance = this; | |
228 | } | |
229 | ||
230 | ~Instances() { | |
231 | assert(s_instance == this); | |
232 | s_instance = nullptr; | |
233 | } | |
234 | ||
235 | MOCK_METHOD0(destroy, void()); | |
236 | MOCK_METHOD1(init, void(Context *)); | |
237 | MOCK_METHOD1(shut_down, void(Context *)); | |
238 | MOCK_METHOD1(notify, void(const std::string &)); | |
239 | }; | |
240 | ||
241 | Instances<librbd::MockTestImageCtx> *Instances<librbd::MockTestImageCtx>::s_instance = nullptr; | |
242 | ||
243 | } // namespace mirror | |
244 | } // namespace rbd | |
245 | ||
246 | ||
247 | // template definitions | |
248 | #include "tools/rbd_mirror/LeaderWatcher.cc" | |
249 | ||
250 | namespace rbd { | |
251 | namespace mirror { | |
252 | ||
253 | using ::testing::_; | |
254 | using ::testing::AtLeast; | |
255 | using ::testing::DoAll; | |
256 | using ::testing::InSequence; | |
257 | using ::testing::Invoke; | |
258 | using ::testing::Return; | |
259 | ||
260 | using librbd::MockManagedLock; | |
261 | ||
262 | struct MockListener : public LeaderWatcher<librbd::MockTestImageCtx>::Listener { | |
263 | static MockListener* s_instance; | |
264 | ||
265 | MockListener() { | |
266 | assert(s_instance == nullptr); | |
267 | s_instance = this; | |
268 | } | |
269 | ||
270 | ~MockListener() override { | |
271 | assert(s_instance == this); | |
272 | s_instance = nullptr; | |
273 | } | |
274 | ||
275 | MOCK_METHOD1(post_acquire_handler, void(Context *)); | |
276 | MOCK_METHOD1(pre_release_handler, void(Context *)); | |
31f18b77 FG |
277 | |
278 | MOCK_METHOD1(update_leader_handler, void(const std::string &)); | |
7c673cae FG |
279 | }; |
280 | ||
281 | MockListener *MockListener::s_instance = nullptr; | |
282 | ||
283 | class TestMockLeaderWatcher : public TestMockFixture { | |
284 | public: | |
285 | typedef MirrorStatusWatcher<librbd::MockTestImageCtx> MockMirrorStatusWatcher; | |
286 | typedef Instances<librbd::MockTestImageCtx> MockInstances; | |
287 | typedef LeaderWatcher<librbd::MockTestImageCtx> MockLeaderWatcher; | |
288 | typedef Threads<librbd::MockTestImageCtx> MockThreads; | |
289 | ||
290 | void SetUp() override { | |
291 | TestMockFixture::SetUp(); | |
292 | m_mock_threads = new MockThreads(m_threads); | |
293 | } | |
294 | ||
295 | void TearDown() override { | |
296 | delete m_mock_threads; | |
297 | TestMockFixture::TearDown(); | |
298 | } | |
299 | ||
300 | void expect_construct(MockManagedLock &mock_managed_lock) { | |
301 | EXPECT_CALL(mock_managed_lock, construct()); | |
302 | } | |
303 | ||
304 | void expect_destroy(MockManagedLock &mock_managed_lock) { | |
305 | EXPECT_CALL(mock_managed_lock, destroy()); | |
306 | } | |
307 | ||
308 | void expect_is_lock_owner(MockManagedLock &mock_managed_lock, bool owner) { | |
309 | EXPECT_CALL(mock_managed_lock, is_lock_owner()) | |
310 | .WillOnce(Return(owner)); | |
311 | } | |
312 | ||
313 | void expect_shut_down(MockManagedLock &mock_managed_lock, | |
314 | bool release_lock_on_shutdown, int r) { | |
315 | mock_managed_lock.m_release_lock_on_shutdown = release_lock_on_shutdown; | |
316 | EXPECT_CALL(mock_managed_lock, shut_down(_)) | |
317 | .WillOnce(CompleteContext(r)); | |
318 | } | |
319 | ||
320 | void expect_try_acquire_lock(MockManagedLock &mock_managed_lock, int r) { | |
321 | EXPECT_CALL(mock_managed_lock, try_acquire_lock(_)) | |
322 | .WillOnce(CompleteContext(r)); | |
323 | if (r == 0) { | |
324 | expect_set_state_post_acquiring(mock_managed_lock); | |
325 | } | |
326 | } | |
327 | ||
328 | void expect_release_lock(MockManagedLock &mock_managed_lock, int r, | |
329 | Context *on_finish = nullptr) { | |
330 | EXPECT_CALL(mock_managed_lock, release_lock(_)) | |
331 | .WillOnce(Invoke([on_finish, r](Context *ctx) { | |
332 | ctx->complete(r); | |
333 | if (on_finish != nullptr) { | |
334 | on_finish->complete(0); | |
335 | } | |
336 | })); | |
337 | } | |
338 | ||
339 | void expect_get_locker(MockManagedLock &mock_managed_lock, | |
340 | const librbd::managed_lock::Locker &locker, int r) { | |
341 | EXPECT_CALL(mock_managed_lock, get_locker(_, _)) | |
342 | .WillOnce(Invoke([r, locker](librbd::managed_lock::Locker *out, | |
343 | Context *ctx) { | |
344 | if (r == 0) { | |
345 | *out = locker; | |
346 | } | |
347 | ctx->complete(r); | |
348 | })); | |
349 | } | |
350 | ||
351 | void expect_break_lock(MockManagedLock &mock_managed_lock, | |
352 | const librbd::managed_lock::Locker &locker, int r, | |
353 | Context *on_finish) { | |
354 | EXPECT_CALL(mock_managed_lock, break_lock(locker, true, _)) | |
355 | .WillOnce(Invoke([on_finish, r](const librbd::managed_lock::Locker &, | |
356 | bool, Context *ctx) { | |
357 | ctx->complete(r); | |
358 | on_finish->complete(0); | |
359 | })); | |
360 | } | |
361 | ||
362 | void expect_set_state_post_acquiring(MockManagedLock &mock_managed_lock) { | |
363 | EXPECT_CALL(mock_managed_lock, set_state_post_acquiring()); | |
364 | } | |
365 | ||
366 | void expect_is_shutdown(MockManagedLock &mock_managed_lock) { | |
367 | EXPECT_CALL(mock_managed_lock, is_shutdown()) | |
368 | .Times(AtLeast(0)).WillRepeatedly(Return(false)); | |
369 | } | |
370 | ||
371 | void expect_is_leader(MockManagedLock &mock_managed_lock, bool post_acquiring, | |
372 | bool locked) { | |
373 | EXPECT_CALL(mock_managed_lock, is_state_post_acquiring()) | |
374 | .WillOnce(Return(post_acquiring)); | |
375 | if (!post_acquiring) { | |
376 | EXPECT_CALL(mock_managed_lock, is_state_locked()) | |
377 | .WillOnce(Return(locked)); | |
378 | } | |
379 | } | |
380 | ||
381 | void expect_is_leader(MockManagedLock &mock_managed_lock) { | |
382 | EXPECT_CALL(mock_managed_lock, is_state_post_acquiring()) | |
383 | .Times(AtLeast(0)).WillRepeatedly(Return(false)); | |
384 | EXPECT_CALL(mock_managed_lock, is_state_locked()) | |
385 | .Times(AtLeast(0)).WillRepeatedly(Return(false)); | |
31f18b77 FG |
386 | EXPECT_CALL(mock_managed_lock, is_state_pre_releasing()) |
387 | .Times(AtLeast(0)).WillRepeatedly(Return(false)); | |
7c673cae FG |
388 | } |
389 | ||
390 | void expect_notify_heartbeat(MockManagedLock &mock_managed_lock, | |
391 | Context *on_finish) { | |
392 | // is_leader in notify_heartbeat | |
393 | EXPECT_CALL(mock_managed_lock, is_state_post_acquiring()) | |
394 | .WillOnce(Return(false)); | |
395 | EXPECT_CALL(mock_managed_lock, is_state_locked()) | |
396 | .WillOnce(Return(true)); | |
397 | ||
398 | // is_leader in handle_notify_heartbeat | |
399 | EXPECT_CALL(mock_managed_lock, is_state_post_acquiring()) | |
400 | .WillOnce(Return(false)); | |
401 | EXPECT_CALL(mock_managed_lock, is_state_locked()) | |
402 | .WillOnce(DoAll(Invoke([on_finish]() { | |
403 | on_finish->complete(0); | |
404 | }), | |
405 | Return(true))); | |
406 | } | |
407 | ||
408 | void expect_destroy(MockMirrorStatusWatcher &mock_mirror_status_watcher) { | |
409 | EXPECT_CALL(mock_mirror_status_watcher, destroy()); | |
410 | } | |
411 | ||
412 | void expect_init(MockMirrorStatusWatcher &mock_mirror_status_watcher, int r) { | |
413 | EXPECT_CALL(mock_mirror_status_watcher, init(_)) | |
414 | .WillOnce(CompleteContext(m_mock_threads->work_queue, r)); | |
415 | } | |
416 | ||
417 | void expect_shut_down(MockMirrorStatusWatcher &mock_mirror_status_watcher, int r) { | |
418 | EXPECT_CALL(mock_mirror_status_watcher, shut_down(_)) | |
419 | .WillOnce(CompleteContext(m_mock_threads->work_queue, r)); | |
420 | expect_destroy(mock_mirror_status_watcher); | |
421 | } | |
422 | ||
423 | void expect_destroy(MockInstances &mock_instances) { | |
424 | EXPECT_CALL(mock_instances, destroy()); | |
425 | } | |
426 | ||
427 | void expect_init(MockInstances &mock_instances, int r) { | |
428 | EXPECT_CALL(mock_instances, init(_)) | |
429 | .WillOnce(CompleteContext(m_mock_threads->work_queue, r)); | |
430 | } | |
431 | ||
432 | void expect_shut_down(MockInstances &mock_instances, int r) { | |
433 | EXPECT_CALL(mock_instances, shut_down(_)) | |
434 | .WillOnce(CompleteContext(m_mock_threads->work_queue, r)); | |
435 | expect_destroy(mock_instances); | |
436 | } | |
437 | ||
438 | void expect_acquire_notify(MockManagedLock &mock_managed_lock, | |
439 | MockListener &mock_listener, int r) { | |
440 | expect_is_leader(mock_managed_lock, true, false); | |
441 | EXPECT_CALL(mock_listener, post_acquire_handler(_)) | |
442 | .WillOnce(CompleteContext(r)); | |
443 | expect_is_leader(mock_managed_lock, true, false); | |
444 | } | |
445 | ||
446 | void expect_release_notify(MockManagedLock &mock_managed_lock, | |
447 | MockListener &mock_listener, int r) { | |
448 | expect_is_leader(mock_managed_lock, false, false); | |
449 | EXPECT_CALL(mock_listener, pre_release_handler(_)) | |
450 | .WillOnce(CompleteContext(r)); | |
451 | expect_is_leader(mock_managed_lock, false, false); | |
452 | } | |
453 | ||
454 | MockThreads *m_mock_threads; | |
455 | }; | |
456 | ||
457 | TEST_F(TestMockLeaderWatcher, InitShutdown) { | |
458 | MockManagedLock mock_managed_lock; | |
459 | MockMirrorStatusWatcher mock_mirror_status_watcher; | |
460 | MockInstances mock_instances; | |
461 | MockListener listener; | |
462 | ||
463 | expect_is_shutdown(mock_managed_lock); | |
464 | expect_destroy(mock_managed_lock); | |
465 | ||
466 | InSequence seq; | |
467 | ||
468 | expect_construct(mock_managed_lock); | |
469 | MockLeaderWatcher leader_watcher(m_mock_threads, m_local_io_ctx, &listener); | |
470 | ||
471 | // Inint | |
472 | C_SaferCond on_heartbeat_finish; | |
473 | expect_is_leader(mock_managed_lock, false, false); | |
474 | expect_try_acquire_lock(mock_managed_lock, 0); | |
475 | expect_init(mock_mirror_status_watcher, 0); | |
476 | expect_init(mock_instances, 0); | |
477 | expect_acquire_notify(mock_managed_lock, listener, 0); | |
478 | expect_notify_heartbeat(mock_managed_lock, &on_heartbeat_finish); | |
479 | ||
480 | ASSERT_EQ(0, leader_watcher.init()); | |
481 | ASSERT_EQ(0, on_heartbeat_finish.wait()); | |
482 | ||
483 | // Shutdown | |
484 | expect_release_notify(mock_managed_lock, listener, 0); | |
485 | expect_shut_down(mock_instances, 0); | |
486 | expect_shut_down(mock_mirror_status_watcher, 0); | |
487 | expect_is_leader(mock_managed_lock, false, false); | |
488 | expect_release_lock(mock_managed_lock, 0); | |
489 | expect_shut_down(mock_managed_lock, true, 0); | |
490 | expect_is_leader(mock_managed_lock, false, false); | |
491 | ||
492 | leader_watcher.shut_down(); | |
493 | } | |
494 | ||
495 | TEST_F(TestMockLeaderWatcher, InitReleaseShutdown) { | |
496 | MockManagedLock mock_managed_lock; | |
497 | MockMirrorStatusWatcher mock_mirror_status_watcher; | |
498 | MockInstances mock_instances; | |
499 | MockListener listener; | |
500 | ||
501 | expect_is_shutdown(mock_managed_lock); | |
502 | expect_destroy(mock_managed_lock); | |
503 | ||
504 | InSequence seq; | |
505 | ||
506 | expect_construct(mock_managed_lock); | |
507 | MockLeaderWatcher leader_watcher(m_mock_threads, m_local_io_ctx, &listener); | |
508 | ||
509 | // Inint | |
510 | C_SaferCond on_heartbeat_finish; | |
511 | expect_is_leader(mock_managed_lock, false, false); | |
512 | expect_try_acquire_lock(mock_managed_lock, 0); | |
513 | expect_init(mock_mirror_status_watcher, 0); | |
514 | expect_init(mock_instances, 0); | |
515 | expect_acquire_notify(mock_managed_lock, listener, 0); | |
516 | expect_notify_heartbeat(mock_managed_lock, &on_heartbeat_finish); | |
517 | ||
518 | ASSERT_EQ(0, leader_watcher.init()); | |
519 | ASSERT_EQ(0, on_heartbeat_finish.wait()); | |
520 | ||
521 | // Release | |
522 | expect_is_leader(mock_managed_lock, false, true); | |
523 | expect_release_notify(mock_managed_lock, listener, 0); | |
524 | expect_shut_down(mock_instances, 0); | |
525 | expect_shut_down(mock_mirror_status_watcher, 0); | |
526 | expect_is_leader(mock_managed_lock, false, false); | |
527 | C_SaferCond on_release; | |
528 | expect_release_lock(mock_managed_lock, 0, &on_release); | |
529 | ||
530 | leader_watcher.release_leader(); | |
531 | ASSERT_EQ(0, on_release.wait()); | |
532 | ||
533 | // Shutdown | |
534 | expect_shut_down(mock_managed_lock, false, 0); | |
535 | expect_is_leader(mock_managed_lock, false, false); | |
536 | ||
537 | leader_watcher.shut_down(); | |
538 | } | |
539 | ||
540 | TEST_F(TestMockLeaderWatcher, AcquireError) { | |
541 | MockManagedLock mock_managed_lock; | |
542 | MockMirrorStatusWatcher mock_mirror_status_watcher; | |
543 | MockInstances mock_instances; | |
544 | MockListener listener; | |
545 | ||
546 | expect_is_shutdown(mock_managed_lock); | |
547 | expect_is_leader(mock_managed_lock); | |
548 | expect_destroy(mock_managed_lock); | |
549 | ||
550 | InSequence seq; | |
551 | ||
552 | expect_construct(mock_managed_lock); | |
553 | MockLeaderWatcher leader_watcher(m_mock_threads, m_local_io_ctx, &listener); | |
554 | ||
555 | // Inint | |
556 | C_SaferCond on_heartbeat_finish; | |
557 | expect_is_leader(mock_managed_lock, false, false); | |
558 | expect_try_acquire_lock(mock_managed_lock, -EAGAIN); | |
559 | expect_get_locker(mock_managed_lock, librbd::managed_lock::Locker(), -ENOENT); | |
560 | expect_try_acquire_lock(mock_managed_lock, 0); | |
561 | expect_init(mock_mirror_status_watcher, 0); | |
562 | expect_init(mock_instances, 0); | |
563 | expect_acquire_notify(mock_managed_lock, listener, 0); | |
564 | expect_notify_heartbeat(mock_managed_lock, &on_heartbeat_finish); | |
565 | ||
566 | ASSERT_EQ(0, leader_watcher.init()); | |
567 | ASSERT_EQ(0, on_heartbeat_finish.wait()); | |
568 | ||
569 | // Shutdown | |
570 | expect_release_notify(mock_managed_lock, listener, 0); | |
571 | expect_shut_down(mock_instances, 0); | |
572 | expect_shut_down(mock_mirror_status_watcher, 0); | |
573 | expect_is_leader(mock_managed_lock, false, false); | |
574 | expect_release_lock(mock_managed_lock, 0); | |
575 | expect_shut_down(mock_managed_lock, true, 0); | |
576 | expect_is_leader(mock_managed_lock, false, false); | |
577 | ||
578 | leader_watcher.shut_down(); | |
579 | } | |
580 | ||
581 | TEST_F(TestMockLeaderWatcher, ReleaseError) { | |
582 | MockManagedLock mock_managed_lock; | |
583 | MockMirrorStatusWatcher mock_mirror_status_watcher; | |
584 | MockInstances mock_instances; | |
585 | MockListener listener; | |
586 | ||
587 | expect_is_shutdown(mock_managed_lock); | |
588 | expect_destroy(mock_managed_lock); | |
589 | ||
590 | InSequence seq; | |
591 | ||
592 | expect_construct(mock_managed_lock); | |
593 | MockLeaderWatcher leader_watcher(m_mock_threads, m_local_io_ctx, &listener); | |
594 | ||
595 | // Inint | |
596 | C_SaferCond on_heartbeat_finish; | |
597 | expect_is_leader(mock_managed_lock, false, false); | |
598 | expect_try_acquire_lock(mock_managed_lock, 0); | |
599 | expect_init(mock_mirror_status_watcher, 0); | |
600 | expect_init(mock_instances, 0); | |
601 | expect_acquire_notify(mock_managed_lock, listener, 0); | |
602 | expect_notify_heartbeat(mock_managed_lock, &on_heartbeat_finish); | |
603 | ||
604 | ASSERT_EQ(0, leader_watcher.init()); | |
605 | ASSERT_EQ(0, on_heartbeat_finish.wait()); | |
606 | ||
607 | // Release | |
608 | expect_is_leader(mock_managed_lock, false, true); | |
609 | expect_release_notify(mock_managed_lock, listener, -EINVAL); | |
610 | expect_shut_down(mock_instances, 0); | |
611 | expect_shut_down(mock_mirror_status_watcher, -EINVAL); | |
612 | expect_is_leader(mock_managed_lock, false, false); | |
613 | C_SaferCond on_release; | |
614 | expect_release_lock(mock_managed_lock, -EINVAL, &on_release); | |
615 | ||
616 | leader_watcher.release_leader(); | |
617 | ASSERT_EQ(0, on_release.wait()); | |
618 | ||
619 | // Shutdown | |
620 | expect_shut_down(mock_managed_lock, false, 0); | |
621 | expect_is_leader(mock_managed_lock, false, false); | |
622 | ||
623 | leader_watcher.shut_down(); | |
624 | } | |
625 | ||
626 | TEST_F(TestMockLeaderWatcher, Break) { | |
627 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_leader_heartbeat_interval", "1")); | |
628 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_leader_max_missed_heartbeats", | |
629 | "1")); | |
630 | CephContext *cct = reinterpret_cast<CephContext *>(m_local_io_ctx.cct()); | |
181888fb FG |
631 | int max_acquire_attempts = cct->_conf->get_val<int64_t>( |
632 | "rbd_mirror_leader_max_acquire_attempts_before_break"); | |
7c673cae FG |
633 | |
634 | MockManagedLock mock_managed_lock; | |
635 | MockMirrorStatusWatcher mock_mirror_status_watcher; | |
636 | MockInstances mock_instances; | |
637 | MockListener listener; | |
638 | librbd::managed_lock::Locker | |
639 | locker{entity_name_t::CLIENT(1), "auto 123", "1.2.3.4:0/0", 123}; | |
640 | ||
641 | expect_is_shutdown(mock_managed_lock); | |
642 | expect_is_leader(mock_managed_lock); | |
643 | expect_destroy(mock_managed_lock); | |
31f18b77 | 644 | EXPECT_CALL(listener, update_leader_handler(_)); |
7c673cae FG |
645 | |
646 | InSequence seq; | |
647 | ||
648 | expect_construct(mock_managed_lock); | |
649 | MockLeaderWatcher leader_watcher(m_mock_threads, m_local_io_ctx, &listener); | |
650 | ||
651 | // Init | |
652 | expect_is_leader(mock_managed_lock, false, false); | |
653 | for (int i = 0; i < max_acquire_attempts; i++) { | |
654 | expect_try_acquire_lock(mock_managed_lock, -EAGAIN); | |
655 | expect_get_locker(mock_managed_lock, locker, 0); | |
656 | } | |
657 | C_SaferCond on_break; | |
658 | expect_break_lock(mock_managed_lock, locker, 0, &on_break); | |
659 | C_SaferCond on_heartbeat_finish; | |
660 | expect_try_acquire_lock(mock_managed_lock, 0); | |
661 | expect_init(mock_mirror_status_watcher, 0); | |
662 | expect_init(mock_instances, 0); | |
663 | expect_acquire_notify(mock_managed_lock, listener, 0); | |
664 | expect_notify_heartbeat(mock_managed_lock, &on_heartbeat_finish); | |
665 | ||
666 | ASSERT_EQ(0, leader_watcher.init()); | |
667 | ASSERT_EQ(0, on_heartbeat_finish.wait()); | |
668 | ||
669 | // Shutdown | |
670 | expect_release_notify(mock_managed_lock, listener, 0); | |
671 | expect_shut_down(mock_instances, 0); | |
672 | expect_shut_down(mock_mirror_status_watcher, 0); | |
673 | expect_is_leader(mock_managed_lock, false, false); | |
674 | expect_release_lock(mock_managed_lock, 0); | |
675 | expect_shut_down(mock_managed_lock, true, 0); | |
676 | expect_is_leader(mock_managed_lock, false, false); | |
677 | ||
678 | leader_watcher.shut_down(); | |
679 | } | |
680 | ||
681 | } // namespace mirror | |
682 | } // namespace rbd |