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/journal/mock/MockJournaler.h"
6 #include "test/librbd/test_support.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockJournalPolicy.h"
9 #include "common/Cond.h"
10 #include "common/Mutex.h"
11 #include "cls/journal/cls_journal_types.h"
12 #include "journal/Journaler.h"
13 #include "librbd/Journal.h"
14 #include "librbd/Utils.h"
15 #include "librbd/io/AioCompletion.h"
16 #include "librbd/io/ObjectRequest.h"
17 #include "librbd/journal/Replay.h"
18 #include "librbd/journal/RemoveRequest.h"
19 #include "librbd/journal/CreateRequest.h"
20 #include "librbd/journal/OpenRequest.h"
21 #include "librbd/journal/Types.h"
22 #include "librbd/journal/TypeTraits.h"
23 #include "librbd/journal/PromoteRequest.h"
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
28 #include <boost/scope_exit.hpp>
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_rbd
37 struct MockJournalImageCtx
: public MockImageCtx
{
38 MockJournalImageCtx(librbd::ImageCtx
& image_ctx
) : MockImageCtx(image_ctx
) {
42 } // anonymous namespace
47 struct TypeTraits
<MockJournalImageCtx
> {
48 typedef ::journal::MockJournalerProxy Journaler
;
49 typedef ::journal::MockFutureProxy Future
;
50 typedef ::journal::MockReplayEntryProxy ReplayEntry
;
54 static MockReplay
*s_instance
;
55 static MockReplay
&get_instance() {
56 assert(s_instance
!= nullptr);
64 MOCK_METHOD2(shut_down
, void(bool cancel_ops
, Context
*));
65 MOCK_METHOD2(decode
, int(bufferlist::iterator
*, EventEntry
*));
66 MOCK_METHOD3(process
, void(const EventEntry
&, Context
*, Context
*));
67 MOCK_METHOD2(replay_op_ready
, void(uint64_t, Context
*));
71 class Replay
<MockJournalImageCtx
> {
73 static Replay
*create(MockJournalImageCtx
&image_ctx
) {
77 void shut_down(bool cancel_ops
, Context
*on_finish
) {
78 MockReplay::get_instance().shut_down(cancel_ops
, on_finish
);
81 int decode(bufferlist::iterator
*it
, EventEntry
*event_entry
) {
82 return MockReplay::get_instance().decode(it
, event_entry
);
85 void process(const EventEntry
& event_entry
, Context
*on_ready
,
87 MockReplay::get_instance().process(event_entry
, on_ready
, on_commit
);
90 void replay_op_ready(uint64_t op_tid
, Context
*on_resume
) {
91 MockReplay::get_instance().replay_op_ready(op_tid
, on_resume
);
95 MockReplay
*MockReplay::s_instance
= nullptr;
98 static MockRemove
*s_instance
;
99 static MockRemove
&get_instance() {
100 assert(s_instance
!= nullptr);
108 MOCK_METHOD0(send
, void());
112 class RemoveRequest
<MockJournalImageCtx
> {
114 static RemoveRequest
*create(IoCtx
&ioctx
, const std::string
&imageid
,
115 const std::string
&client_id
,
116 ContextWQ
*op_work_queue
, Context
*on_finish
) {
117 return new RemoveRequest();
121 MockRemove::get_instance().send();
125 MockRemove
*MockRemove::s_instance
= nullptr;
128 static MockCreate
*s_instance
;
129 static MockCreate
&get_instance() {
130 assert(s_instance
!= nullptr);
138 MOCK_METHOD0(send
, void());
142 class CreateRequest
<MockJournalImageCtx
> {
144 static CreateRequest
*create(IoCtx
&ioctx
, const std::string
&imageid
,
145 uint8_t order
, uint8_t splay_width
,
146 const std::string
&object_pool
,
147 uint64_t tag_class
, TagData
&tag_data
,
148 const std::string
&client_id
,
149 ContextWQ
*op_work_queue
, Context
*on_finish
) {
150 return new CreateRequest();
154 MockCreate::get_instance().send();
158 MockCreate
*MockCreate::s_instance
= nullptr;
161 class OpenRequest
<MockJournalImageCtx
> {
165 static OpenRequest
*s_instance
;
166 static OpenRequest
*create(MockJournalImageCtx
*image_ctx
,
167 ::journal::MockJournalerProxy
*journaler
,
168 Mutex
*lock
, journal::ImageClientMeta
*client_meta
,
169 uint64_t *tag_tid
, journal::TagData
*tag_data
,
170 Context
*on_finish
) {
171 assert(s_instance
!= nullptr);
172 s_instance
->tag_data
= tag_data
;
173 s_instance
->on_finish
= on_finish
;
181 MOCK_METHOD0(send
, void());
184 OpenRequest
<MockJournalImageCtx
> *OpenRequest
<MockJournalImageCtx
>::s_instance
= nullptr;
188 class PromoteRequest
<MockJournalImageCtx
> {
190 static PromoteRequest s_instance
;
191 static PromoteRequest
*create(MockJournalImageCtx
*image_ctx
, bool force
,
192 Context
*on_finish
) {
196 MOCK_METHOD0(send
, void());
199 PromoteRequest
<MockJournalImageCtx
> PromoteRequest
<MockJournalImageCtx
>::s_instance
;
201 } // namespace journal
202 } // namespace librbd
204 // template definitions
205 #include "librbd/Journal.cc"
208 using ::testing::DoAll
;
209 using ::testing::InSequence
;
210 using ::testing::Invoke
;
211 using ::testing::InvokeWithoutArgs
;
212 using ::testing::MatcherCast
;
213 using ::testing::Return
;
214 using ::testing::SaveArg
;
215 using ::testing::SetArgPointee
;
216 using ::testing::WithArg
;
217 using namespace std::placeholders
;
219 ACTION_P2(StartReplay
, wq
, ctx
) {
225 class TestMockJournal
: public TestMockFixture
{
227 typedef journal::MockReplay MockJournalReplay
;
228 typedef Journal
<MockJournalImageCtx
> MockJournal
;
229 typedef journal::OpenRequest
<MockJournalImageCtx
> MockJournalOpenRequest
;
231 typedef std::function
<void(::journal::ReplayHandler
*)> ReplayAction
;
232 typedef std::list
<Context
*> Contexts
;
234 TestMockJournal() : m_lock("lock") {
237 ~TestMockJournal() override
{
238 assert(m_commit_contexts
.empty());
243 Contexts m_commit_contexts
;
245 struct C_ReplayAction
: public Context
{
246 ::journal::ReplayHandler
**replay_handler
;
247 ReplayAction replay_action
;
249 C_ReplayAction(::journal::ReplayHandler
**replay_handler
,
250 const ReplayAction
&replay_action
)
251 : replay_handler(replay_handler
), replay_action(replay_action
) {
253 void finish(int r
) override
{
255 replay_action(*replay_handler
);
260 void expect_construct_journaler(::journal::MockJournaler
&mock_journaler
) {
261 EXPECT_CALL(mock_journaler
, construct());
264 void expect_open_journaler(MockImageCtx
&mock_image_ctx
,
265 ::journal::MockJournaler
&mock_journaler
,
266 MockJournalOpenRequest
&mock_open_request
,
267 bool primary
, int r
) {
268 EXPECT_CALL(mock_journaler
, add_listener(_
))
269 .WillOnce(SaveArg
<0>(&m_listener
));
270 EXPECT_CALL(mock_open_request
, send())
271 .WillOnce(DoAll(Invoke([&mock_open_request
, primary
]() {
273 mock_open_request
.tag_data
->mirror_uuid
= "remote mirror uuid";
276 FinishRequest(&mock_open_request
, r
,
280 void expect_shut_down_journaler(::journal::MockJournaler
&mock_journaler
) {
281 EXPECT_CALL(mock_journaler
, remove_listener(_
));
282 EXPECT_CALL(mock_journaler
, shut_down(_
))
283 .WillOnce(CompleteContext(0, static_cast<ContextWQ
*>(NULL
)));
286 void expect_get_max_append_size(::journal::MockJournaler
&mock_journaler
,
288 EXPECT_CALL(mock_journaler
, get_max_append_size())
289 .WillOnce(Return(max_size
));
292 void expect_get_journaler_cached_client(::journal::MockJournaler
&mock_journaler
,
293 const journal::ImageClientMeta
&client_meta
,
295 journal::ClientData client_data
;
296 client_data
.client_meta
= client_meta
;
298 cls::journal::Client client
;
299 ::encode(client_data
, client
.data
);
301 EXPECT_CALL(mock_journaler
, get_cached_client("", _
))
302 .WillOnce(DoAll(SetArgPointee
<1>(client
),
306 void expect_get_journaler_tags(MockImageCtx
&mock_image_ctx
,
307 ::journal::MockJournaler
&mock_journaler
,
308 uint64_t start_after_tag_tid
,
309 ::journal::Journaler::Tags
&&tags
, int r
) {
310 EXPECT_CALL(mock_journaler
, get_tags(start_after_tag_tid
, 0, _
, _
))
311 .WillOnce(DoAll(SetArgPointee
<2>(tags
),
312 WithArg
<3>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
))));
315 void expect_start_replay(MockJournalImageCtx
&mock_image_ctx
,
316 ::journal::MockJournaler
&mock_journaler
,
317 const ReplayAction
&action
) {
318 EXPECT_CALL(mock_journaler
, start_replay(_
))
319 .WillOnce(DoAll(SaveArg
<0>(&m_replay_handler
),
320 StartReplay(mock_image_ctx
.image_ctx
->op_work_queue
,
321 new C_ReplayAction(&m_replay_handler
,
325 void expect_stop_replay(::journal::MockJournaler
&mock_journaler
) {
326 EXPECT_CALL(mock_journaler
, stop_replay(_
))
327 .WillOnce(CompleteContext(0, static_cast<ContextWQ
*>(NULL
)));
330 void expect_shut_down_replay(MockJournalImageCtx
&mock_image_ctx
,
331 MockJournalReplay
&mock_journal_replay
, int r
,
332 bool cancel_ops
= false) {
333 EXPECT_CALL(mock_journal_replay
, shut_down(cancel_ops
, _
))
334 .WillOnce(WithArg
<1>(Invoke([this, &mock_image_ctx
, r
](Context
*on_flush
) {
335 this->commit_replay(mock_image_ctx
, on_flush
, r
);})));
338 void expect_get_data(::journal::MockReplayEntry
&mock_replay_entry
) {
339 EXPECT_CALL(mock_replay_entry
, get_data())
340 .WillOnce(Return(bufferlist()));
343 void expect_try_pop_front(MockJournalImageCtx
&mock_image_ctx
,
344 ::journal::MockJournaler
&mock_journaler
,
345 bool entries_available
,
346 ::journal::MockReplayEntry
&mock_replay_entry
,
347 const ReplayAction
&action
= {}) {
348 EXPECT_CALL(mock_journaler
, try_pop_front(_
))
349 .WillOnce(DoAll(SetArgPointee
<0>(::journal::MockReplayEntryProxy()),
350 StartReplay(mock_image_ctx
.image_ctx
->op_work_queue
,
351 new C_ReplayAction(&m_replay_handler
,
353 Return(entries_available
)));
354 if (entries_available
) {
355 expect_get_data(mock_replay_entry
);
359 void expect_replay_process(MockJournalReplay
&mock_journal_replay
) {
360 EXPECT_CALL(mock_journal_replay
, decode(_
, _
))
361 .WillOnce(Return(0));
362 EXPECT_CALL(mock_journal_replay
, process(_
, _
, _
))
363 .WillOnce(DoAll(WithArg
<1>(CompleteContext(0, static_cast<ContextWQ
*>(NULL
))),
364 WithArg
<2>(Invoke(this, &TestMockJournal::save_commit_context
))));
367 void expect_start_append(::journal::MockJournaler
&mock_journaler
) {
368 EXPECT_CALL(mock_journaler
, start_append(_
, _
, _
));
371 void expect_stop_append(::journal::MockJournaler
&mock_journaler
, int r
) {
372 EXPECT_CALL(mock_journaler
, stop_append(_
))
373 .WillOnce(CompleteContext(r
, static_cast<ContextWQ
*>(NULL
)));
376 void expect_committed(::journal::MockJournaler
&mock_journaler
,
378 EXPECT_CALL(mock_journaler
, committed(MatcherCast
<const ::journal::MockReplayEntryProxy
&>(_
)))
382 void expect_append_journaler(::journal::MockJournaler
&mock_journaler
) {
383 EXPECT_CALL(mock_journaler
, append(_
, _
))
384 .WillOnce(Return(::journal::MockFutureProxy()));
387 void expect_wait_future(::journal::MockFuture
&mock_future
,
389 EXPECT_CALL(mock_future
, wait(_
))
390 .WillOnce(SaveArg
<0>(on_safe
));
393 void expect_future_committed(::journal::MockJournaler
&mock_journaler
) {
394 EXPECT_CALL(mock_journaler
, committed(MatcherCast
<const ::journal::MockFutureProxy
&>(_
)));
397 void expect_future_is_valid(::journal::MockFuture
&mock_future
) {
398 EXPECT_CALL(mock_future
, is_valid()).WillOnce(Return(false));
401 void expect_flush_commit_position(::journal::MockJournaler
&mock_journaler
) {
402 EXPECT_CALL(mock_journaler
, flush_commit_position(_
))
403 .WillOnce(CompleteContext(0, static_cast<ContextWQ
*>(NULL
)));
406 int when_open(MockJournal
&mock_journal
) {
408 mock_journal
.open(&ctx
);
412 int when_close(MockJournal
&mock_journal
) {
414 mock_journal
.close(&ctx
);
418 uint64_t when_append_write_event(MockJournalImageCtx
&mock_image_ctx
,
419 MockJournal
&mock_journal
, uint64_t length
) {
421 bl
.append_zero(length
);
423 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
424 return mock_journal
.append_write_event(0, length
, bl
, {}, false);
427 uint64_t when_append_io_event(MockJournalImageCtx
&mock_image_ctx
,
428 MockJournal
&mock_journal
,
429 io::ObjectRequest
<> *object_request
= nullptr) {
430 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
431 MockJournal::IOObjectRequests object_requests
;
432 if (object_request
!= nullptr) {
433 object_requests
.push_back(object_request
);
435 return mock_journal
.append_io_event(
436 journal::EventEntry
{journal::AioFlushEvent
{}}, object_requests
, 0, 0,
440 void save_commit_context(Context
*ctx
) {
441 Mutex::Locker
locker(m_lock
);
442 m_commit_contexts
.push_back(ctx
);
447 Mutex::Locker
locker(m_lock
);
451 void commit_replay(MockJournalImageCtx
&mock_image_ctx
, Context
*on_flush
,
453 Contexts commit_contexts
;
454 std::swap(commit_contexts
, m_commit_contexts
);
456 derr
<< "SHUT DOWN REPLAY START" << dendl
;
457 for (auto ctx
: commit_contexts
) {
458 mock_image_ctx
.image_ctx
->op_work_queue
->queue(ctx
, r
);
461 on_flush
= new FunctionContext([on_flush
](int r
) {
462 derr
<< "FLUSH START" << dendl
;
463 on_flush
->complete(r
);
464 derr
<< "FLUSH FINISH" << dendl
;
466 mock_image_ctx
.image_ctx
->op_work_queue
->queue(on_flush
, 0);
467 derr
<< "SHUT DOWN REPLAY FINISH" << dendl
;
470 void open_journal(MockJournalImageCtx
&mock_image_ctx
,
471 MockJournal
&mock_journal
,
472 ::journal::MockJournaler
&mock_journaler
,
473 MockJournalOpenRequest
&mock_open_request
,
474 bool primary
= true) {
475 expect_op_work_queue(mock_image_ctx
);
478 expect_construct_journaler(mock_journaler
);
479 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
481 expect_get_max_append_size(mock_journaler
, 1 << 16);
483 mock_image_ctx
, mock_journaler
,
484 std::bind(&invoke_replay_complete
, _1
, 0));
486 MockJournalReplay mock_journal_replay
;
487 expect_stop_replay(mock_journaler
);
488 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
489 expect_committed(mock_journaler
, 0);
490 expect_start_append(mock_journaler
);
491 ASSERT_EQ(0, when_open(mock_journal
));
494 void close_journal(MockJournal
&mock_journal
,
495 ::journal::MockJournaler
&mock_journaler
) {
496 expect_stop_append(mock_journaler
, 0);
497 ASSERT_EQ(0, when_close(mock_journal
));
500 static void invoke_replay_ready(::journal::ReplayHandler
*handler
) {
501 handler
->handle_entries_available();
504 static void invoke_replay_complete(::journal::ReplayHandler
*handler
, int r
) {
505 handler
->handle_complete(r
);
508 ::journal::ReplayHandler
*m_replay_handler
= nullptr;
509 ::journal::JournalMetadataListener
*m_listener
= nullptr;
512 TEST_F(TestMockJournal
, StateTransitions
) {
513 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
515 librbd::ImageCtx
*ictx
;
516 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
518 MockJournalImageCtx
mock_image_ctx(*ictx
);
519 MockJournal
mock_journal(mock_image_ctx
);
520 expect_op_work_queue(mock_image_ctx
);
524 ::journal::MockJournaler mock_journaler
;
525 MockJournalOpenRequest mock_open_request
;
526 expect_construct_journaler(mock_journaler
);
527 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
529 expect_get_max_append_size(mock_journaler
, 1 << 16);
531 mock_image_ctx
, mock_journaler
,
532 std::bind(&invoke_replay_ready
, _1
));
534 ::journal::MockReplayEntry mock_replay_entry
;
535 MockJournalReplay mock_journal_replay
;
536 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
537 expect_replay_process(mock_journal_replay
);
538 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
539 expect_replay_process(mock_journal_replay
);
540 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
541 std::bind(&invoke_replay_ready
, _1
));
542 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
543 expect_replay_process(mock_journal_replay
);
544 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
545 std::bind(&invoke_replay_complete
, _1
, 0));
547 expect_stop_replay(mock_journaler
);
548 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
549 expect_committed(mock_journaler
, 3);
551 expect_start_append(mock_journaler
);
553 ASSERT_EQ(0, when_open(mock_journal
));
555 expect_stop_append(mock_journaler
, 0);
556 expect_shut_down_journaler(mock_journaler
);
557 ASSERT_EQ(0, when_close(mock_journal
));
560 TEST_F(TestMockJournal
, InitError
) {
561 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
563 librbd::ImageCtx
*ictx
;
564 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
566 MockJournalImageCtx
mock_image_ctx(*ictx
);
567 MockJournal
mock_journal(mock_image_ctx
);
568 expect_op_work_queue(mock_image_ctx
);
572 ::journal::MockJournaler mock_journaler
;
573 MockJournalOpenRequest mock_open_request
;
574 expect_construct_journaler(mock_journaler
);
575 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
577 expect_shut_down_journaler(mock_journaler
);
578 ASSERT_EQ(-EINVAL
, when_open(mock_journal
));
581 TEST_F(TestMockJournal
, ReplayCompleteError
) {
582 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
584 librbd::ImageCtx
*ictx
;
585 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
587 MockJournalImageCtx
mock_image_ctx(*ictx
);
588 MockJournal
mock_journal(mock_image_ctx
);
589 expect_op_work_queue(mock_image_ctx
);
593 ::journal::MockJournaler mock_journaler
;
594 MockJournalOpenRequest mock_open_request
;
595 expect_construct_journaler(mock_journaler
);
596 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
598 expect_get_max_append_size(mock_journaler
, 1 << 16);
600 mock_image_ctx
, mock_journaler
,
601 std::bind(&invoke_replay_complete
, _1
, -EINVAL
));
603 MockJournalReplay mock_journal_replay
;
604 expect_stop_replay(mock_journaler
);
605 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
606 expect_shut_down_journaler(mock_journaler
);
608 // replay failure should result in replay-restart
609 expect_construct_journaler(mock_journaler
);
610 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
612 expect_get_max_append_size(mock_journaler
, 1 << 16);
614 mock_image_ctx
, mock_journaler
,
615 std::bind(&invoke_replay_complete
, _1
, 0));
617 expect_stop_replay(mock_journaler
);
618 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
619 expect_start_append(mock_journaler
);
620 ASSERT_EQ(0, when_open(mock_journal
));
622 expect_stop_append(mock_journaler
, 0);
623 expect_shut_down_journaler(mock_journaler
);
624 ASSERT_EQ(0, when_close(mock_journal
));
627 TEST_F(TestMockJournal
, FlushReplayError
) {
628 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
630 librbd::ImageCtx
*ictx
;
631 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
633 MockJournalImageCtx
mock_image_ctx(*ictx
);
634 MockJournal
mock_journal(mock_image_ctx
);
635 expect_op_work_queue(mock_image_ctx
);
639 ::journal::MockJournaler mock_journaler
;
640 MockJournalOpenRequest mock_open_request
;
641 expect_construct_journaler(mock_journaler
);
642 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
644 expect_get_max_append_size(mock_journaler
, 1 << 16);
646 mock_image_ctx
, mock_journaler
,
647 std::bind(&invoke_replay_ready
, _1
));
649 ::journal::MockReplayEntry mock_replay_entry
;
650 MockJournalReplay mock_journal_replay
;
651 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
652 expect_replay_process(mock_journal_replay
);
653 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
654 std::bind(&invoke_replay_complete
, _1
, 0));
655 expect_stop_replay(mock_journaler
);
656 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, -EINVAL
);
657 expect_shut_down_journaler(mock_journaler
);
659 // replay flush failure should result in replay-restart
660 expect_construct_journaler(mock_journaler
);
661 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
663 expect_get_max_append_size(mock_journaler
, 1 << 16);
665 mock_image_ctx
, mock_journaler
,
666 std::bind(&invoke_replay_complete
, _1
, 0));
668 expect_stop_replay(mock_journaler
);
669 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
670 expect_start_append(mock_journaler
);
671 ASSERT_EQ(0, when_open(mock_journal
));
673 expect_stop_append(mock_journaler
, 0);
674 expect_shut_down_journaler(mock_journaler
);
675 ASSERT_EQ(0, when_close(mock_journal
));
678 TEST_F(TestMockJournal
, CorruptEntry
) {
679 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
681 librbd::ImageCtx
*ictx
;
682 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
684 MockJournalImageCtx
mock_image_ctx(*ictx
);
685 MockJournal
mock_journal(mock_image_ctx
);
686 expect_op_work_queue(mock_image_ctx
);
690 ::journal::MockJournaler mock_journaler
;
691 MockJournalOpenRequest mock_open_request
;
692 expect_construct_journaler(mock_journaler
);
693 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
695 expect_get_max_append_size(mock_journaler
, 1 << 16);
697 mock_image_ctx
, mock_journaler
,
698 std::bind(&invoke_replay_ready
, _1
));
700 ::journal::MockReplayEntry mock_replay_entry
;
701 MockJournalReplay mock_journal_replay
;
702 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
703 EXPECT_CALL(mock_journal_replay
, decode(_
, _
)).WillOnce(Return(-EBADMSG
));
704 expect_stop_replay(mock_journaler
);
705 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
706 expect_shut_down_journaler(mock_journaler
);
708 // replay failure should result in replay-restart
709 expect_construct_journaler(mock_journaler
);
710 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
712 expect_get_max_append_size(mock_journaler
, 1 << 16);
714 mock_image_ctx
, mock_journaler
,
715 std::bind(&invoke_replay_complete
, _1
, 0));
716 expect_stop_replay(mock_journaler
);
717 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
718 expect_start_append(mock_journaler
);
719 ASSERT_EQ(0, when_open(mock_journal
));
721 expect_stop_append(mock_journaler
, -EINVAL
);
722 expect_shut_down_journaler(mock_journaler
);
723 ASSERT_EQ(-EINVAL
, when_close(mock_journal
));
726 TEST_F(TestMockJournal
, StopError
) {
727 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
729 librbd::ImageCtx
*ictx
;
730 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
732 MockJournalImageCtx
mock_image_ctx(*ictx
);
733 MockJournal
mock_journal(mock_image_ctx
);
734 expect_op_work_queue(mock_image_ctx
);
738 ::journal::MockJournaler mock_journaler
;
739 MockJournalOpenRequest mock_open_request
;
740 expect_construct_journaler(mock_journaler
);
741 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
743 expect_get_max_append_size(mock_journaler
, 1 << 16);
745 mock_image_ctx
, mock_journaler
,
746 std::bind(&invoke_replay_complete
, _1
, 0));
748 MockJournalReplay mock_journal_replay
;
749 expect_stop_replay(mock_journaler
);
750 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
751 expect_start_append(mock_journaler
);
752 ASSERT_EQ(0, when_open(mock_journal
));
754 expect_stop_append(mock_journaler
, -EINVAL
);
755 expect_shut_down_journaler(mock_journaler
);
756 ASSERT_EQ(-EINVAL
, when_close(mock_journal
));
759 TEST_F(TestMockJournal
, ReplayOnDiskPreFlushError
) {
760 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
762 librbd::ImageCtx
*ictx
;
763 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
765 MockJournalImageCtx
mock_image_ctx(*ictx
);
766 MockJournal
mock_journal(mock_image_ctx
);
767 expect_op_work_queue(mock_image_ctx
);
770 ::journal::MockJournaler mock_journaler
;
771 MockJournalOpenRequest mock_open_request
;
772 expect_construct_journaler(mock_journaler
);
773 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
775 expect_get_max_append_size(mock_journaler
, 1 << 16);
778 mock_image_ctx
, mock_journaler
,
779 std::bind(&invoke_replay_ready
, _1
));
781 ::journal::MockReplayEntry mock_replay_entry
;
782 MockJournalReplay mock_journal_replay
;
783 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
785 EXPECT_CALL(mock_journal_replay
, decode(_
, _
))
786 .WillOnce(Return(0));
788 EXPECT_CALL(mock_journal_replay
, process(_
, _
, _
))
789 .WillOnce(DoAll(SaveArg
<1>(&on_ready
),
790 WithArg
<2>(Invoke(this, &TestMockJournal::save_commit_context
))));
792 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false,
794 expect_stop_replay(mock_journaler
);
795 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
796 expect_shut_down_journaler(mock_journaler
);
798 // replay write-to-disk failure should result in replay-restart
799 expect_construct_journaler(mock_journaler
);
800 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
802 expect_get_max_append_size(mock_journaler
, 1 << 16);
804 mock_image_ctx
, mock_journaler
, {
805 std::bind(&invoke_replay_complete
, _1
, 0)
808 expect_stop_replay(mock_journaler
);
809 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
810 expect_start_append(mock_journaler
);
813 mock_journal
.open(&ctx
);
815 // wait for the process callback
817 Mutex::Locker
locker(m_lock
);
818 while (m_commit_contexts
.empty()) {
822 on_ready
->complete(0);
824 // inject RADOS error in the middle of replay
825 Context
*on_safe
= m_commit_contexts
.front();
826 m_commit_contexts
.clear();
827 on_safe
->complete(-EINVAL
);
829 // flag the replay as complete
830 m_replay_handler
->handle_complete(0);
832 ASSERT_EQ(0, ctx
.wait());
834 expect_stop_append(mock_journaler
, 0);
835 expect_shut_down_journaler(mock_journaler
);
836 ASSERT_EQ(0, when_close(mock_journal
));
839 TEST_F(TestMockJournal
, ReplayOnDiskPostFlushError
) {
840 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
842 librbd::ImageCtx
*ictx
;
843 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
845 MockJournalImageCtx
mock_image_ctx(*ictx
);
846 MockJournal
mock_journal(mock_image_ctx
);
847 expect_op_work_queue(mock_image_ctx
);
851 ::journal::MockJournaler mock_journaler
;
852 MockJournalOpenRequest mock_open_request
;
853 expect_construct_journaler(mock_journaler
);
854 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
856 expect_get_max_append_size(mock_journaler
, 1 << 16);
858 mock_image_ctx
, mock_journaler
,
859 std::bind(&invoke_replay_ready
, _1
));
861 ::journal::MockReplayEntry mock_replay_entry
;
862 MockJournalReplay mock_journal_replay
;
863 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
864 expect_replay_process(mock_journal_replay
);
865 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
866 std::bind(&invoke_replay_complete
, _1
, 0));
867 expect_stop_replay(mock_journaler
);
869 Context
*on_flush
= nullptr;
870 EXPECT_CALL(mock_journal_replay
, shut_down(false, _
))
871 .WillOnce(DoAll(SaveArg
<1>(&on_flush
),
872 InvokeWithoutArgs(this, &TestMockJournal::wake_up
)));
874 // replay write-to-disk failure should result in replay-restart
875 expect_shut_down_journaler(mock_journaler
);
876 expect_construct_journaler(mock_journaler
);
877 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
879 expect_get_max_append_size(mock_journaler
, 1 << 16);
881 mock_image_ctx
, mock_journaler
,
882 std::bind(&invoke_replay_complete
, _1
, 0));
884 expect_stop_replay(mock_journaler
);
885 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
886 expect_start_append(mock_journaler
);
889 mock_journal
.open(&ctx
);
891 // proceed with the flush
893 // wait for on_flush callback
894 Mutex::Locker
locker(m_lock
);
895 while (on_flush
== nullptr) {
901 // wait for the on_safe process callback
902 Mutex::Locker
locker(m_lock
);
903 while (m_commit_contexts
.empty()) {
907 m_commit_contexts
.front()->complete(-EINVAL
);
908 m_commit_contexts
.clear();
909 on_flush
->complete(0);
911 ASSERT_EQ(0, ctx
.wait());
913 expect_stop_append(mock_journaler
, 0);
914 expect_shut_down_journaler(mock_journaler
);
915 ASSERT_EQ(0, when_close(mock_journal
));
918 TEST_F(TestMockJournal
, EventAndIOCommitOrder
) {
919 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
921 librbd::ImageCtx
*ictx
;
922 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
924 MockJournalImageCtx
mock_image_ctx(*ictx
);
925 MockJournal
mock_journal(mock_image_ctx
);
926 ::journal::MockJournaler mock_journaler
;
927 MockJournalOpenRequest mock_open_request
;
928 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
929 BOOST_SCOPE_EXIT_ALL(&) {
930 close_journal(mock_journal
, mock_journaler
);
933 ::journal::MockFuture mock_future
;
934 Context
*on_journal_safe1
;
935 expect_append_journaler(mock_journaler
);
936 expect_wait_future(mock_future
, &on_journal_safe1
);
937 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
));
938 mock_journal
.get_work_queue()->drain();
940 Context
*on_journal_safe2
;
941 expect_append_journaler(mock_journaler
);
942 expect_wait_future(mock_future
, &on_journal_safe2
);
943 ASSERT_EQ(2U, when_append_io_event(mock_image_ctx
, mock_journal
));
944 mock_journal
.get_work_queue()->drain();
946 // commit journal event followed by IO event (standard)
947 on_journal_safe1
->complete(0);
948 ictx
->op_work_queue
->drain();
949 expect_future_committed(mock_journaler
);
950 mock_journal
.commit_io_event(1U, 0);
952 // commit IO event followed by journal event (cache overwrite)
953 mock_journal
.commit_io_event(2U, 0);
954 expect_future_committed(mock_journaler
);
956 C_SaferCond event_ctx
;
957 mock_journal
.wait_event(2U, &event_ctx
);
958 on_journal_safe2
->complete(0);
959 ictx
->op_work_queue
->drain();
960 ASSERT_EQ(0, event_ctx
.wait());
962 expect_shut_down_journaler(mock_journaler
);
965 TEST_F(TestMockJournal
, AppendWriteEvent
) {
966 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
968 librbd::ImageCtx
*ictx
;
969 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
971 MockJournalImageCtx
mock_image_ctx(*ictx
);
972 MockJournal
mock_journal(mock_image_ctx
);
973 ::journal::MockJournaler mock_journaler
;
974 MockJournalOpenRequest mock_open_request
;
975 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
976 BOOST_SCOPE_EXIT_ALL(&) {
977 close_journal(mock_journal
, mock_journaler
);
982 ::journal::MockFuture mock_future
;
983 Context
*on_journal_safe
= nullptr;
984 expect_append_journaler(mock_journaler
);
985 expect_append_journaler(mock_journaler
);
986 expect_append_journaler(mock_journaler
);
987 expect_wait_future(mock_future
, &on_journal_safe
);
988 ASSERT_EQ(1U, when_append_write_event(mock_image_ctx
, mock_journal
, 1 << 17));
989 mock_journal
.get_work_queue()->drain();
991 on_journal_safe
->complete(0);
992 C_SaferCond event_ctx
;
993 mock_journal
.wait_event(1U, &event_ctx
);
994 ASSERT_EQ(0, event_ctx
.wait());
996 expect_future_committed(mock_journaler
);
997 expect_future_committed(mock_journaler
);
998 expect_future_committed(mock_journaler
);
999 mock_journal
.commit_io_event(1U, 0);
1000 ictx
->op_work_queue
->drain();
1002 expect_shut_down_journaler(mock_journaler
);
1005 TEST_F(TestMockJournal
, EventCommitError
) {
1006 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1008 librbd::ImageCtx
*ictx
;
1009 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1011 MockJournalImageCtx
mock_image_ctx(*ictx
);
1012 MockJournal
mock_journal(mock_image_ctx
);
1013 ::journal::MockJournaler mock_journaler
;
1014 MockJournalOpenRequest mock_open_request
;
1015 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1016 BOOST_SCOPE_EXIT_ALL(&) {
1017 close_journal(mock_journal
, mock_journaler
);
1020 C_SaferCond object_request_ctx
;
1021 auto object_request
= new io::ObjectRemoveRequest(
1022 ictx
, "oid", 0, {}, {}, &object_request_ctx
);
1024 ::journal::MockFuture mock_future
;
1025 Context
*on_journal_safe
;
1026 expect_append_journaler(mock_journaler
);
1027 expect_wait_future(mock_future
, &on_journal_safe
);
1028 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
,
1030 mock_journal
.get_work_queue()->drain();
1032 // commit the event in the journal w/o waiting writeback
1033 expect_future_committed(mock_journaler
);
1034 on_journal_safe
->complete(-EINVAL
);
1035 ASSERT_EQ(-EINVAL
, object_request_ctx
.wait());
1037 // cache should receive the error after attempting writeback
1038 expect_future_is_valid(mock_future
);
1039 C_SaferCond flush_ctx
;
1040 mock_journal
.flush_event(1U, &flush_ctx
);
1041 ASSERT_EQ(-EINVAL
, flush_ctx
.wait());
1043 expect_shut_down_journaler(mock_journaler
);
1046 TEST_F(TestMockJournal
, EventCommitErrorWithPendingWriteback
) {
1047 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1049 librbd::ImageCtx
*ictx
;
1050 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1052 MockJournalImageCtx
mock_image_ctx(*ictx
);
1053 MockJournal
mock_journal(mock_image_ctx
);
1054 ::journal::MockJournaler mock_journaler
;
1055 MockJournalOpenRequest mock_open_request
;
1056 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1057 BOOST_SCOPE_EXIT_ALL(&) {
1058 close_journal(mock_journal
, mock_journaler
);
1061 C_SaferCond object_request_ctx
;
1062 auto object_request
= new io::ObjectRemoveRequest(
1063 ictx
, "oid", 0, {}, {}, &object_request_ctx
);
1065 ::journal::MockFuture mock_future
;
1066 Context
*on_journal_safe
;
1067 expect_append_journaler(mock_journaler
);
1068 expect_wait_future(mock_future
, &on_journal_safe
);
1069 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
,
1071 mock_journal
.get_work_queue()->drain();
1073 expect_future_is_valid(mock_future
);
1074 C_SaferCond flush_ctx
;
1075 mock_journal
.flush_event(1U, &flush_ctx
);
1077 // commit the event in the journal w/ waiting cache writeback
1078 expect_future_committed(mock_journaler
);
1079 on_journal_safe
->complete(-EINVAL
);
1080 ASSERT_EQ(-EINVAL
, object_request_ctx
.wait());
1082 // cache should receive the error if waiting
1083 ASSERT_EQ(-EINVAL
, flush_ctx
.wait());
1085 expect_shut_down_journaler(mock_journaler
);
1088 TEST_F(TestMockJournal
, IOCommitError
) {
1089 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1091 librbd::ImageCtx
*ictx
;
1092 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1094 MockJournalImageCtx
mock_image_ctx(*ictx
);
1095 MockJournal
mock_journal(mock_image_ctx
);
1096 ::journal::MockJournaler mock_journaler
;
1097 MockJournalOpenRequest mock_open_request
;
1098 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1099 BOOST_SCOPE_EXIT_ALL(&) {
1100 close_journal(mock_journal
, mock_journaler
);
1103 ::journal::MockFuture mock_future
;
1104 Context
*on_journal_safe
;
1105 expect_append_journaler(mock_journaler
);
1106 expect_wait_future(mock_future
, &on_journal_safe
);
1107 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
));
1108 mock_journal
.get_work_queue()->drain();
1110 // failed IO remains uncommitted in journal
1111 on_journal_safe
->complete(0);
1112 ictx
->op_work_queue
->drain();
1113 mock_journal
.commit_io_event(1U, -EINVAL
);
1115 expect_shut_down_journaler(mock_journaler
);
1118 TEST_F(TestMockJournal
, FlushCommitPosition
) {
1119 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1121 librbd::ImageCtx
*ictx
;
1122 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1124 MockJournalImageCtx
mock_image_ctx(*ictx
);
1125 MockJournal
mock_journal(mock_image_ctx
);
1126 ::journal::MockJournaler mock_journaler
;
1127 MockJournalOpenRequest mock_open_request
;
1128 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1129 BOOST_SCOPE_EXIT_ALL(&) {
1130 close_journal(mock_journal
, mock_journaler
);
1133 expect_flush_commit_position(mock_journaler
);
1135 mock_journal
.flush_commit_position(&ctx
);
1136 ASSERT_EQ(0, ctx
.wait());
1138 expect_shut_down_journaler(mock_journaler
);
1141 TEST_F(TestMockJournal
, ExternalReplay
) {
1142 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1144 librbd::ImageCtx
*ictx
;
1145 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1147 MockJournalImageCtx
mock_image_ctx(*ictx
);
1148 MockJournal
mock_journal(mock_image_ctx
);
1149 ::journal::MockJournaler mock_journaler
;
1150 MockJournalOpenRequest mock_open_request
;
1151 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1152 BOOST_SCOPE_EXIT_ALL(&) {
1153 close_journal(mock_journal
, mock_journaler
);
1157 expect_stop_append(mock_journaler
, 0);
1158 expect_start_append(mock_journaler
);
1159 expect_shut_down_journaler(mock_journaler
);
1161 C_SaferCond start_ctx
;
1163 journal::Replay
<MockJournalImageCtx
> *journal_replay
= nullptr;
1164 mock_journal
.start_external_replay(&journal_replay
, &start_ctx
);
1165 ASSERT_EQ(0, start_ctx
.wait());
1167 mock_journal
.stop_external_replay();
1170 TEST_F(TestMockJournal
, ExternalReplayFailure
) {
1171 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1173 librbd::ImageCtx
*ictx
;
1174 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1176 MockJournalImageCtx
mock_image_ctx(*ictx
);
1177 MockJournal
mock_journal(mock_image_ctx
);
1178 ::journal::MockJournaler mock_journaler
;
1179 MockJournalOpenRequest mock_open_request
;
1180 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1181 BOOST_SCOPE_EXIT_ALL(&) {
1182 close_journal(mock_journal
, mock_journaler
);
1186 expect_stop_append(mock_journaler
, -EINVAL
);
1187 expect_start_append(mock_journaler
);
1188 expect_shut_down_journaler(mock_journaler
);
1190 C_SaferCond start_ctx
;
1192 journal::Replay
<MockJournalImageCtx
> *journal_replay
= nullptr;
1193 mock_journal
.start_external_replay(&journal_replay
, &start_ctx
);
1194 ASSERT_EQ(-EINVAL
, start_ctx
.wait());
1197 TEST_F(TestMockJournal
, AppendDisabled
) {
1198 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1200 librbd::ImageCtx
*ictx
;
1201 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1203 MockJournalImageCtx
mock_image_ctx(*ictx
);
1204 MockJournal
mock_journal(mock_image_ctx
);
1205 MockJournalPolicy mock_journal_policy
;
1207 ::journal::MockJournaler mock_journaler
;
1208 MockJournalOpenRequest mock_open_request
;
1209 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1210 BOOST_SCOPE_EXIT_ALL(&) {
1211 close_journal(mock_journal
, mock_journaler
);
1215 RWLock::RLocker
snap_locker(mock_image_ctx
.snap_lock
);
1216 EXPECT_CALL(mock_image_ctx
, get_journal_policy()).WillOnce(
1217 Return(ictx
->get_journal_policy()));
1218 ASSERT_TRUE(mock_journal
.is_journal_appending());
1220 EXPECT_CALL(mock_image_ctx
, get_journal_policy()).WillOnce(
1221 Return(&mock_journal_policy
));
1222 EXPECT_CALL(mock_journal_policy
, append_disabled()).WillOnce(Return(true));
1223 ASSERT_FALSE(mock_journal
.is_journal_appending());
1225 expect_shut_down_journaler(mock_journaler
);
1228 TEST_F(TestMockJournal
, CloseListenerEvent
) {
1229 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1231 librbd::ImageCtx
*ictx
;
1232 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1234 MockJournalImageCtx
mock_image_ctx(*ictx
);
1235 MockJournal
mock_journal(mock_image_ctx
);
1236 ::journal::MockJournaler mock_journaler
;
1237 MockJournalOpenRequest mock_open_request
;
1238 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
);
1240 struct Listener
: public journal::Listener
{
1242 void handle_close() override
{
1245 void handle_resync() override
{
1246 ADD_FAILURE() << "unexpected resync request";
1248 void handle_promoted() override
{
1249 ADD_FAILURE() << "unexpected promotion event";
1252 mock_journal
.add_listener(&listener
);
1254 expect_shut_down_journaler(mock_journaler
);
1255 close_journal(mock_journal
, mock_journaler
);
1257 ASSERT_EQ(0, listener
.ctx
.wait());
1258 mock_journal
.remove_listener(&listener
);
1261 TEST_F(TestMockJournal
, ResyncRequested
) {
1262 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1264 librbd::ImageCtx
*ictx
;
1265 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1267 MockJournalImageCtx
mock_image_ctx(*ictx
);
1268 MockJournal
mock_journal(mock_image_ctx
);
1269 ::journal::MockJournaler mock_journaler
;
1270 MockJournalOpenRequest mock_open_request
;
1271 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
,
1274 struct Listener
: public journal::Listener
{
1276 void handle_close() override
{
1277 ADD_FAILURE() << "unexpected close action";
1279 void handle_resync() override
{
1282 void handle_promoted() override
{
1283 ADD_FAILURE() << "unexpected promotion event";
1286 mock_journal
.add_listener(&listener
);
1288 BOOST_SCOPE_EXIT_ALL(&) {
1289 mock_journal
.remove_listener(&listener
);
1290 close_journal(mock_journal
, mock_journaler
);
1295 journal::TagData tag_data
;
1296 tag_data
.mirror_uuid
= Journal
<>::LOCAL_MIRROR_UUID
;
1298 bufferlist tag_data_bl
;
1299 ::encode(tag_data
, tag_data_bl
);
1300 expect_get_journaler_tags(mock_image_ctx
, mock_journaler
, 0,
1301 {{0, 0, tag_data_bl
}}, 0);
1303 journal::ImageClientMeta image_client_meta
;
1304 image_client_meta
.tag_class
= 0;
1305 image_client_meta
.resync_requested
= true;
1306 expect_get_journaler_cached_client(mock_journaler
, image_client_meta
, 0);
1307 expect_shut_down_journaler(mock_journaler
);
1309 m_listener
->handle_update(nullptr);
1310 ASSERT_EQ(0, listener
.ctx
.wait());
1313 TEST_F(TestMockJournal
, ForcePromoted
) {
1314 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1316 librbd::ImageCtx
*ictx
;
1317 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1319 MockJournalImageCtx
mock_image_ctx(*ictx
);
1320 MockJournal
mock_journal(mock_image_ctx
);
1321 ::journal::MockJournaler mock_journaler
;
1322 MockJournalOpenRequest mock_open_request
;
1323 open_journal(mock_image_ctx
, mock_journal
, mock_journaler
, mock_open_request
,
1326 struct Listener
: public journal::Listener
{
1328 void handle_close() override
{
1329 ADD_FAILURE() << "unexpected close action";
1331 void handle_resync() override
{
1332 ADD_FAILURE() << "unexpected resync event";
1334 void handle_promoted() override
{
1338 mock_journal
.add_listener(&listener
);
1340 BOOST_SCOPE_EXIT_ALL(&) {
1341 mock_journal
.remove_listener(&listener
);
1342 close_journal(mock_journal
, mock_journaler
);
1347 journal::TagData tag_data
;
1348 tag_data
.mirror_uuid
= Journal
<>::LOCAL_MIRROR_UUID
;
1350 bufferlist tag_data_bl
;
1351 ::encode(tag_data
, tag_data_bl
);
1352 expect_get_journaler_tags(mock_image_ctx
, mock_journaler
, 0,
1353 {{100, 0, tag_data_bl
}}, 0);
1355 journal::ImageClientMeta image_client_meta
;
1356 image_client_meta
.tag_class
= 0;
1357 expect_get_journaler_cached_client(mock_journaler
, image_client_meta
, 0);
1358 expect_shut_down_journaler(mock_journaler
);
1360 m_listener
->handle_update(nullptr);
1361 ASSERT_EQ(0, listener
.ctx
.wait());
1364 } // namespace librbd