Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / test_mock_Journal.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/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"
26 #include <functional>
27 #include <list>
28 #include <boost/scope_exit.hpp>
29
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_rbd
32
33 namespace librbd {
34
35 namespace {
36
37 struct MockJournalImageCtx : public MockImageCtx {
38   MockJournalImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
39   }
40 };
41
42 } // anonymous namespace
43
44 namespace journal {
45
46 template <>
47 struct TypeTraits<MockJournalImageCtx> {
48   typedef ::journal::MockJournalerProxy Journaler;
49   typedef ::journal::MockFutureProxy  Future;
50   typedef ::journal::MockReplayEntryProxy ReplayEntry;
51 };
52
53 struct MockReplay {
54   static MockReplay *s_instance;
55   static MockReplay &get_instance() {
56     assert(s_instance != nullptr);
57     return *s_instance;
58   }
59
60   MockReplay() {
61     s_instance = this;
62   }
63
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 *));
68 };
69
70 template <>
71 class Replay<MockJournalImageCtx> {
72 public:
73   static Replay *create(MockJournalImageCtx &image_ctx) {
74     return new Replay();
75   }
76
77   void shut_down(bool cancel_ops, Context *on_finish) {
78     MockReplay::get_instance().shut_down(cancel_ops, on_finish);
79   }
80
81   int decode(bufferlist::iterator *it, EventEntry *event_entry) {
82     return MockReplay::get_instance().decode(it, event_entry);
83   }
84
85   void process(const EventEntry& event_entry, Context *on_ready,
86                Context *on_commit) {
87     MockReplay::get_instance().process(event_entry, on_ready, on_commit);
88   }
89
90   void replay_op_ready(uint64_t op_tid, Context *on_resume) {
91     MockReplay::get_instance().replay_op_ready(op_tid, on_resume);
92   }
93 };
94
95 MockReplay *MockReplay::s_instance = nullptr;
96
97 struct MockRemove {
98   static MockRemove *s_instance;
99   static MockRemove &get_instance() {
100     assert(s_instance != nullptr);
101     return *s_instance;
102   }
103
104   MockRemove() {
105     s_instance = this;
106   }
107
108   MOCK_METHOD0(send, void());
109 };
110
111 template <>
112 class RemoveRequest<MockJournalImageCtx> {
113 public:
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();
118   }
119
120   void send() {
121     MockRemove::get_instance().send();
122   }
123 };
124
125 MockRemove *MockRemove::s_instance = nullptr;
126
127 struct MockCreate {
128   static MockCreate *s_instance;
129   static MockCreate &get_instance() {
130     assert(s_instance != nullptr);
131     return *s_instance;
132   }
133
134   MockCreate() {
135     s_instance = this;
136   }
137
138   MOCK_METHOD0(send, void());
139 };
140
141 template<>
142 class CreateRequest<MockJournalImageCtx> {
143 public:
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();
151   }
152
153   void send() {
154     MockCreate::get_instance().send();
155   }
156 };
157
158 MockCreate *MockCreate::s_instance = nullptr;
159
160 template<>
161 class OpenRequest<MockJournalImageCtx> {
162 public:
163   TagData *tag_data;
164   Context *on_finish;
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;
174     return s_instance;
175   }
176
177   OpenRequest() {
178     s_instance = this;
179   }
180
181   MOCK_METHOD0(send, void());
182 };
183
184 OpenRequest<MockJournalImageCtx> *OpenRequest<MockJournalImageCtx>::s_instance = nullptr;
185
186
187 template <>
188 class PromoteRequest<MockJournalImageCtx> {
189 public:
190   static PromoteRequest s_instance;
191   static PromoteRequest *create(MockJournalImageCtx *image_ctx, bool force,
192                                 Context *on_finish) {
193     return &s_instance;
194   }
195
196   MOCK_METHOD0(send, void());
197 };
198
199 PromoteRequest<MockJournalImageCtx> PromoteRequest<MockJournalImageCtx>::s_instance;
200
201 } // namespace journal
202 } // namespace librbd
203
204 // template definitions
205 #include "librbd/Journal.cc"
206
207 using ::testing::_;
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;
218
219 ACTION_P2(StartReplay, wq, ctx) {
220   wq->queue(ctx, 0);
221 }
222
223 namespace librbd {
224
225 class TestMockJournal : public TestMockFixture {
226 public:
227   typedef journal::MockReplay MockJournalReplay;
228   typedef Journal<MockJournalImageCtx> MockJournal;
229   typedef journal::OpenRequest<MockJournalImageCtx> MockJournalOpenRequest;
230
231   typedef std::function<void(::journal::ReplayHandler*)> ReplayAction;
232   typedef std::list<Context *> Contexts;
233
234   TestMockJournal() : m_lock("lock") {
235   }
236
237   ~TestMockJournal() override {
238     assert(m_commit_contexts.empty());
239   }
240
241   Mutex m_lock;
242   Cond m_cond;
243   Contexts m_commit_contexts;
244
245   struct C_ReplayAction : public Context {
246     ::journal::ReplayHandler **replay_handler;
247     ReplayAction replay_action;
248
249     C_ReplayAction(::journal::ReplayHandler **replay_handler,
250                    const ReplayAction &replay_action)
251       : replay_handler(replay_handler), replay_action(replay_action) {
252     }
253     void finish(int r) override {
254       if (replay_action) {
255         replay_action(*replay_handler);
256       }
257     }
258   };
259
260   void expect_construct_journaler(::journal::MockJournaler &mock_journaler) {
261     EXPECT_CALL(mock_journaler, construct());
262   }
263
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]() {
272                                     if (!primary) {
273                                       mock_open_request.tag_data->mirror_uuid = "remote mirror uuid";
274                                     }
275                                   }),
276                                   FinishRequest(&mock_open_request, r,
277                                                 &mock_image_ctx)));
278   }
279
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)));
284   }
285
286   void expect_get_max_append_size(::journal::MockJournaler &mock_journaler,
287                                   uint32_t max_size) {
288     EXPECT_CALL(mock_journaler, get_max_append_size())
289                   .WillOnce(Return(max_size));
290   }
291
292   void expect_get_journaler_cached_client(::journal::MockJournaler &mock_journaler,
293                                           const journal::ImageClientMeta &client_meta,
294                                           int r) {
295     journal::ClientData client_data;
296     client_data.client_meta = client_meta;
297
298     cls::journal::Client client;
299     ::encode(client_data, client.data);
300
301     EXPECT_CALL(mock_journaler, get_cached_client("", _))
302                   .WillOnce(DoAll(SetArgPointee<1>(client),
303                                   Return(r)));
304   }
305
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))));
313   }
314
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,
322                                                           action))));
323   }
324
325   void expect_stop_replay(::journal::MockJournaler &mock_journaler) {
326     EXPECT_CALL(mock_journaler, stop_replay(_))
327                   .WillOnce(CompleteContext(0, static_cast<ContextWQ*>(NULL)));
328   }
329
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);})));
336   }
337
338   void expect_get_data(::journal::MockReplayEntry &mock_replay_entry) {
339     EXPECT_CALL(mock_replay_entry, get_data())
340                   .WillOnce(Return(bufferlist()));
341   }
342
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,
352                                                                  action)),
353                                   Return(entries_available)));
354     if (entries_available) {
355       expect_get_data(mock_replay_entry);
356     }
357   }
358
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))));
365   }
366
367   void expect_start_append(::journal::MockJournaler &mock_journaler) {
368     EXPECT_CALL(mock_journaler, start_append(_, _, _));
369   }
370
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)));
374   }
375
376   void expect_committed(::journal::MockJournaler &mock_journaler,
377                         size_t events) {
378     EXPECT_CALL(mock_journaler, committed(MatcherCast<const ::journal::MockReplayEntryProxy&>(_)))
379                   .Times(events);
380   }
381
382   void expect_append_journaler(::journal::MockJournaler &mock_journaler) {
383     EXPECT_CALL(mock_journaler, append(_, _))
384                   .WillOnce(Return(::journal::MockFutureProxy()));
385   }
386
387   void expect_wait_future(::journal::MockFuture &mock_future,
388                           Context **on_safe) {
389     EXPECT_CALL(mock_future, wait(_))
390                   .WillOnce(SaveArg<0>(on_safe));
391   }
392
393   void expect_future_committed(::journal::MockJournaler &mock_journaler) {
394     EXPECT_CALL(mock_journaler, committed(MatcherCast<const ::journal::MockFutureProxy&>(_)));
395   }
396
397   void expect_future_is_valid(::journal::MockFuture &mock_future) {
398     EXPECT_CALL(mock_future, is_valid()).WillOnce(Return(false));
399   }
400
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)));
404   }
405
406   int when_open(MockJournal &mock_journal) {
407     C_SaferCond ctx;
408     mock_journal.open(&ctx);
409     return ctx.wait();
410   }
411
412   int when_close(MockJournal &mock_journal) {
413     C_SaferCond ctx;
414     mock_journal.close(&ctx);
415     return ctx.wait();
416   }
417
418   uint64_t when_append_write_event(MockJournalImageCtx &mock_image_ctx,
419                                    MockJournal &mock_journal, uint64_t length) {
420     bufferlist bl;
421     bl.append_zero(length);
422
423     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
424     return mock_journal.append_write_event(0, length, bl, {}, false);
425   }
426
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);
434     }
435     return mock_journal.append_io_event(
436       journal::EventEntry{journal::AioFlushEvent{}}, object_requests, 0, 0,
437       false);
438   }
439
440   void save_commit_context(Context *ctx) {
441     Mutex::Locker locker(m_lock);
442     m_commit_contexts.push_back(ctx);
443     m_cond.Signal();
444   }
445
446   void wake_up() {
447     Mutex::Locker locker(m_lock);
448     m_cond.Signal();
449   }
450
451   void commit_replay(MockJournalImageCtx &mock_image_ctx, Context *on_flush,
452                      int r) {
453     Contexts commit_contexts;
454     std::swap(commit_contexts, m_commit_contexts);
455
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);
459     }
460
461     on_flush = new FunctionContext([on_flush](int r) {
462         derr << "FLUSH START" << dendl;
463         on_flush->complete(r);
464         derr << "FLUSH FINISH" << dendl;
465       });
466     mock_image_ctx.image_ctx->op_work_queue->queue(on_flush, 0);
467     derr << "SHUT DOWN REPLAY FINISH" << dendl;
468   }
469
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);
476
477     InSequence seq;
478     expect_construct_journaler(mock_journaler);
479     expect_open_journaler(mock_image_ctx, mock_journaler, mock_open_request,
480                           primary, 0);
481     expect_get_max_append_size(mock_journaler, 1 << 16);
482     expect_start_replay(
483       mock_image_ctx, mock_journaler,
484       std::bind(&invoke_replay_complete, _1, 0));
485
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));
492   }
493
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));
498   }
499
500   static void invoke_replay_ready(::journal::ReplayHandler *handler) {
501     handler->handle_entries_available();
502   }
503
504   static void invoke_replay_complete(::journal::ReplayHandler *handler, int r) {
505     handler->handle_complete(r);
506   }
507
508   ::journal::ReplayHandler *m_replay_handler = nullptr;
509   ::journal::JournalMetadataListener *m_listener = nullptr;
510 };
511
512 TEST_F(TestMockJournal, StateTransitions) {
513   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
514
515   librbd::ImageCtx *ictx;
516   ASSERT_EQ(0, open_image(m_image_name, &ictx));
517
518   MockJournalImageCtx mock_image_ctx(*ictx);
519   MockJournal mock_journal(mock_image_ctx);
520   expect_op_work_queue(mock_image_ctx);
521
522   InSequence seq;
523
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,
528                         true, 0);
529   expect_get_max_append_size(mock_journaler, 1 << 16);
530   expect_start_replay(
531     mock_image_ctx, mock_journaler,
532     std::bind(&invoke_replay_ready, _1));
533
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));
546
547   expect_stop_replay(mock_journaler);
548   expect_shut_down_replay(mock_image_ctx, mock_journal_replay, 0);
549   expect_committed(mock_journaler, 3);
550
551   expect_start_append(mock_journaler);
552
553   ASSERT_EQ(0, when_open(mock_journal));
554
555   expect_stop_append(mock_journaler, 0);
556   expect_shut_down_journaler(mock_journaler);
557   ASSERT_EQ(0, when_close(mock_journal));
558 }
559
560 TEST_F(TestMockJournal, InitError) {
561   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
562
563   librbd::ImageCtx *ictx;
564   ASSERT_EQ(0, open_image(m_image_name, &ictx));
565
566   MockJournalImageCtx mock_image_ctx(*ictx);
567   MockJournal mock_journal(mock_image_ctx);
568   expect_op_work_queue(mock_image_ctx);
569
570   InSequence seq;
571
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,
576                         true, -EINVAL);
577   expect_shut_down_journaler(mock_journaler);
578   ASSERT_EQ(-EINVAL, when_open(mock_journal));
579 }
580
581 TEST_F(TestMockJournal, ReplayCompleteError) {
582   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
583
584   librbd::ImageCtx *ictx;
585   ASSERT_EQ(0, open_image(m_image_name, &ictx));
586
587   MockJournalImageCtx mock_image_ctx(*ictx);
588   MockJournal mock_journal(mock_image_ctx);
589   expect_op_work_queue(mock_image_ctx);
590
591   InSequence seq;
592
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,
597                         true, 0);
598   expect_get_max_append_size(mock_journaler, 1 << 16);
599   expect_start_replay(
600     mock_image_ctx, mock_journaler,
601     std::bind(&invoke_replay_complete, _1, -EINVAL));
602
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);
607
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,
611                         true, 0);
612   expect_get_max_append_size(mock_journaler, 1 << 16);
613   expect_start_replay(
614     mock_image_ctx, mock_journaler,
615     std::bind(&invoke_replay_complete, _1, 0));
616
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));
621
622   expect_stop_append(mock_journaler, 0);
623   expect_shut_down_journaler(mock_journaler);
624   ASSERT_EQ(0, when_close(mock_journal));
625 }
626
627 TEST_F(TestMockJournal, FlushReplayError) {
628   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
629
630   librbd::ImageCtx *ictx;
631   ASSERT_EQ(0, open_image(m_image_name, &ictx));
632
633   MockJournalImageCtx mock_image_ctx(*ictx);
634   MockJournal mock_journal(mock_image_ctx);
635   expect_op_work_queue(mock_image_ctx);
636
637   InSequence seq;
638
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,
643                         true, 0);
644   expect_get_max_append_size(mock_journaler, 1 << 16);
645   expect_start_replay(
646     mock_image_ctx, mock_journaler,
647     std::bind(&invoke_replay_ready, _1));
648
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);
658
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,
662                         true, 0);
663   expect_get_max_append_size(mock_journaler, 1 << 16);
664   expect_start_replay(
665     mock_image_ctx, mock_journaler,
666     std::bind(&invoke_replay_complete, _1, 0));
667
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));
672
673   expect_stop_append(mock_journaler, 0);
674   expect_shut_down_journaler(mock_journaler);
675   ASSERT_EQ(0, when_close(mock_journal));
676 }
677
678 TEST_F(TestMockJournal, CorruptEntry) {
679   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
680
681   librbd::ImageCtx *ictx;
682   ASSERT_EQ(0, open_image(m_image_name, &ictx));
683
684   MockJournalImageCtx mock_image_ctx(*ictx);
685   MockJournal mock_journal(mock_image_ctx);
686   expect_op_work_queue(mock_image_ctx);
687
688   InSequence seq;
689
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,
694                         true, 0);
695   expect_get_max_append_size(mock_journaler, 1 << 16);
696   expect_start_replay(
697     mock_image_ctx, mock_journaler,
698     std::bind(&invoke_replay_ready, _1));
699
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);
707
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,
711                         true, 0);
712   expect_get_max_append_size(mock_journaler, 1 << 16);
713   expect_start_replay(
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));
720
721   expect_stop_append(mock_journaler, -EINVAL);
722   expect_shut_down_journaler(mock_journaler);
723   ASSERT_EQ(-EINVAL, when_close(mock_journal));
724 }
725
726 TEST_F(TestMockJournal, StopError) {
727   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
728
729   librbd::ImageCtx *ictx;
730   ASSERT_EQ(0, open_image(m_image_name, &ictx));
731
732   MockJournalImageCtx mock_image_ctx(*ictx);
733   MockJournal mock_journal(mock_image_ctx);
734   expect_op_work_queue(mock_image_ctx);
735
736   InSequence seq;
737
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,
742                         true, 0);
743   expect_get_max_append_size(mock_journaler, 1 << 16);
744   expect_start_replay(
745     mock_image_ctx, mock_journaler,
746     std::bind(&invoke_replay_complete, _1, 0));
747
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));
753
754   expect_stop_append(mock_journaler, -EINVAL);
755   expect_shut_down_journaler(mock_journaler);
756   ASSERT_EQ(-EINVAL, when_close(mock_journal));
757 }
758
759 TEST_F(TestMockJournal, ReplayOnDiskPreFlushError) {
760   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
761
762   librbd::ImageCtx *ictx;
763   ASSERT_EQ(0, open_image(m_image_name, &ictx));
764
765   MockJournalImageCtx mock_image_ctx(*ictx);
766   MockJournal mock_journal(mock_image_ctx);
767   expect_op_work_queue(mock_image_ctx);
768
769   InSequence seq;
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,
774                         true, 0);
775   expect_get_max_append_size(mock_journaler, 1 << 16);
776
777   expect_start_replay(
778     mock_image_ctx, mock_journaler,
779     std::bind(&invoke_replay_ready, _1));
780
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);
784
785   EXPECT_CALL(mock_journal_replay, decode(_, _))
786                 .WillOnce(Return(0));
787   Context *on_ready;
788   EXPECT_CALL(mock_journal_replay, process(_, _, _))
789                 .WillOnce(DoAll(SaveArg<1>(&on_ready),
790                                 WithArg<2>(Invoke(this, &TestMockJournal::save_commit_context))));
791
792   expect_try_pop_front(mock_image_ctx, mock_journaler, false,
793                        mock_replay_entry);
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);
797
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,
801                         true, 0);
802   expect_get_max_append_size(mock_journaler, 1 << 16);
803   expect_start_replay(
804     mock_image_ctx, mock_journaler, {
805       std::bind(&invoke_replay_complete, _1, 0)
806     });
807
808   expect_stop_replay(mock_journaler);
809   expect_shut_down_replay(mock_image_ctx, mock_journal_replay, 0);
810   expect_start_append(mock_journaler);
811
812   C_SaferCond ctx;
813   mock_journal.open(&ctx);
814
815   // wait for the process callback
816   {
817     Mutex::Locker locker(m_lock);
818     while (m_commit_contexts.empty()) {
819       m_cond.Wait(m_lock);
820     }
821   }
822   on_ready->complete(0);
823
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);
828
829   // flag the replay as complete
830   m_replay_handler->handle_complete(0);
831
832   ASSERT_EQ(0, ctx.wait());
833
834   expect_stop_append(mock_journaler, 0);
835   expect_shut_down_journaler(mock_journaler);
836   ASSERT_EQ(0, when_close(mock_journal));
837 }
838
839 TEST_F(TestMockJournal, ReplayOnDiskPostFlushError) {
840   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
841
842   librbd::ImageCtx *ictx;
843   ASSERT_EQ(0, open_image(m_image_name, &ictx));
844
845   MockJournalImageCtx mock_image_ctx(*ictx);
846   MockJournal mock_journal(mock_image_ctx);
847   expect_op_work_queue(mock_image_ctx);
848
849   InSequence seq;
850
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,
855                         true, 0);
856   expect_get_max_append_size(mock_journaler, 1 << 16);
857   expect_start_replay(
858     mock_image_ctx, mock_journaler,
859     std::bind(&invoke_replay_ready, _1));
860
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);
868
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)));
873
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,
878                         true, 0);
879   expect_get_max_append_size(mock_journaler, 1 << 16);
880   expect_start_replay(
881     mock_image_ctx, mock_journaler,
882     std::bind(&invoke_replay_complete, _1, 0));
883
884   expect_stop_replay(mock_journaler);
885   expect_shut_down_replay(mock_image_ctx, mock_journal_replay, 0);
886   expect_start_append(mock_journaler);
887
888   C_SaferCond ctx;
889   mock_journal.open(&ctx);
890
891   // proceed with the flush
892   {
893     // wait for on_flush callback
894     Mutex::Locker locker(m_lock);
895     while (on_flush == nullptr) {
896       m_cond.Wait(m_lock);
897     }
898   }
899
900   {
901     // wait for the on_safe process callback
902     Mutex::Locker locker(m_lock);
903     while (m_commit_contexts.empty()) {
904       m_cond.Wait(m_lock);
905     }
906   }
907   m_commit_contexts.front()->complete(-EINVAL);
908   m_commit_contexts.clear();
909   on_flush->complete(0);
910
911   ASSERT_EQ(0, ctx.wait());
912
913   expect_stop_append(mock_journaler, 0);
914   expect_shut_down_journaler(mock_journaler);
915   ASSERT_EQ(0, when_close(mock_journal));
916 }
917
918 TEST_F(TestMockJournal, EventAndIOCommitOrder) {
919   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
920
921   librbd::ImageCtx *ictx;
922   ASSERT_EQ(0, open_image(m_image_name, &ictx));
923
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);
931   };
932
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();
939
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();
945
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);
951
952   // commit IO event followed by journal event (cache overwrite)
953   mock_journal.commit_io_event(2U, 0);
954   expect_future_committed(mock_journaler);
955
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());
961
962   expect_shut_down_journaler(mock_journaler);
963 }
964
965 TEST_F(TestMockJournal, AppendWriteEvent) {
966   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
967
968   librbd::ImageCtx *ictx;
969   ASSERT_EQ(0, open_image(m_image_name, &ictx));
970
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);
978   };
979
980   InSequence seq;
981
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();
990
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());
995
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();
1001
1002   expect_shut_down_journaler(mock_journaler);
1003 }
1004
1005 TEST_F(TestMockJournal, EventCommitError) {
1006   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1007
1008   librbd::ImageCtx *ictx;
1009   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1010
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);
1018   };
1019
1020   C_SaferCond object_request_ctx;
1021   auto object_request = new io::ObjectRemoveRequest(
1022     ictx, "oid", 0, {}, {}, &object_request_ctx);
1023
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,
1029                                      object_request));
1030   mock_journal.get_work_queue()->drain();
1031
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());
1036
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());
1042
1043   expect_shut_down_journaler(mock_journaler);
1044 }
1045
1046 TEST_F(TestMockJournal, EventCommitErrorWithPendingWriteback) {
1047   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1048
1049   librbd::ImageCtx *ictx;
1050   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1051
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);
1059   };
1060
1061   C_SaferCond object_request_ctx;
1062   auto object_request = new io::ObjectRemoveRequest(
1063     ictx, "oid", 0, {}, {}, &object_request_ctx);
1064
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,
1070                                      object_request));
1071   mock_journal.get_work_queue()->drain();
1072
1073   expect_future_is_valid(mock_future);
1074   C_SaferCond flush_ctx;
1075   mock_journal.flush_event(1U, &flush_ctx);
1076
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());
1081
1082   // cache should receive the error if waiting
1083   ASSERT_EQ(-EINVAL, flush_ctx.wait());
1084
1085   expect_shut_down_journaler(mock_journaler);
1086 }
1087
1088 TEST_F(TestMockJournal, IOCommitError) {
1089   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1090
1091   librbd::ImageCtx *ictx;
1092   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1093
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);
1101   };
1102
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();
1109
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);
1114
1115   expect_shut_down_journaler(mock_journaler);
1116 }
1117
1118 TEST_F(TestMockJournal, FlushCommitPosition) {
1119   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1120
1121   librbd::ImageCtx *ictx;
1122   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1123
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);
1131   };
1132
1133   expect_flush_commit_position(mock_journaler);
1134   C_SaferCond ctx;
1135   mock_journal.flush_commit_position(&ctx);
1136   ASSERT_EQ(0, ctx.wait());
1137
1138   expect_shut_down_journaler(mock_journaler);
1139 }
1140
1141 TEST_F(TestMockJournal, ExternalReplay) {
1142   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1143
1144   librbd::ImageCtx *ictx;
1145   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1146
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);
1154   };
1155
1156   InSequence seq;
1157   expect_stop_append(mock_journaler, 0);
1158   expect_start_append(mock_journaler);
1159   expect_shut_down_journaler(mock_journaler);
1160
1161   C_SaferCond start_ctx;
1162
1163   journal::Replay<MockJournalImageCtx> *journal_replay = nullptr;
1164   mock_journal.start_external_replay(&journal_replay, &start_ctx);
1165   ASSERT_EQ(0, start_ctx.wait());
1166
1167   mock_journal.stop_external_replay();
1168 }
1169
1170 TEST_F(TestMockJournal, ExternalReplayFailure) {
1171   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1172
1173   librbd::ImageCtx *ictx;
1174   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1175
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);
1183   };
1184
1185   InSequence seq;
1186   expect_stop_append(mock_journaler, -EINVAL);
1187   expect_start_append(mock_journaler);
1188   expect_shut_down_journaler(mock_journaler);
1189
1190   C_SaferCond start_ctx;
1191
1192   journal::Replay<MockJournalImageCtx> *journal_replay = nullptr;
1193   mock_journal.start_external_replay(&journal_replay, &start_ctx);
1194   ASSERT_EQ(-EINVAL, start_ctx.wait());
1195 }
1196
1197 TEST_F(TestMockJournal, AppendDisabled) {
1198   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1199
1200   librbd::ImageCtx *ictx;
1201   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1202
1203   MockJournalImageCtx mock_image_ctx(*ictx);
1204   MockJournal mock_journal(mock_image_ctx);
1205   MockJournalPolicy mock_journal_policy;
1206
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);
1212   };
1213
1214   InSequence seq;
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());
1219
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());
1224
1225   expect_shut_down_journaler(mock_journaler);
1226 }
1227
1228 TEST_F(TestMockJournal, CloseListenerEvent) {
1229   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1230
1231   librbd::ImageCtx *ictx;
1232   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1233
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);
1239
1240   struct Listener : public journal::Listener {
1241     C_SaferCond ctx;
1242     void handle_close() override {
1243       ctx.complete(0);
1244     }
1245     void handle_resync() override {
1246       ADD_FAILURE() << "unexpected resync request";
1247     }
1248     void handle_promoted() override {
1249       ADD_FAILURE() << "unexpected promotion event";
1250     }
1251   } listener;
1252   mock_journal.add_listener(&listener);
1253
1254   expect_shut_down_journaler(mock_journaler);
1255   close_journal(mock_journal, mock_journaler);
1256
1257   ASSERT_EQ(0, listener.ctx.wait());
1258   mock_journal.remove_listener(&listener);
1259 }
1260
1261 TEST_F(TestMockJournal, ResyncRequested) {
1262   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1263
1264   librbd::ImageCtx *ictx;
1265   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1266
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,
1272                false);
1273
1274   struct Listener : public journal::Listener {
1275     C_SaferCond ctx;
1276     void handle_close() override {
1277       ADD_FAILURE() << "unexpected close action";
1278     }
1279     void handle_resync() override {
1280       ctx.complete(0);
1281     }
1282     void handle_promoted() override {
1283       ADD_FAILURE() << "unexpected promotion event";
1284     }
1285   } listener;
1286   mock_journal.add_listener(&listener);
1287
1288   BOOST_SCOPE_EXIT_ALL(&) {
1289     mock_journal.remove_listener(&listener);
1290     close_journal(mock_journal, mock_journaler);
1291   };
1292
1293   InSequence seq;
1294
1295   journal::TagData tag_data;
1296   tag_data.mirror_uuid = Journal<>::LOCAL_MIRROR_UUID;
1297
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);
1302
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);
1308
1309   m_listener->handle_update(nullptr);
1310   ASSERT_EQ(0, listener.ctx.wait());
1311 }
1312
1313 TEST_F(TestMockJournal, ForcePromoted) {
1314   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
1315
1316   librbd::ImageCtx *ictx;
1317   ASSERT_EQ(0, open_image(m_image_name, &ictx));
1318
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,
1324                false);
1325
1326   struct Listener : public journal::Listener {
1327     C_SaferCond ctx;
1328     void handle_close() override {
1329       ADD_FAILURE() << "unexpected close action";
1330     }
1331     void handle_resync() override {
1332       ADD_FAILURE() << "unexpected resync event";
1333     }
1334     void handle_promoted() override {
1335       ctx.complete(0);
1336     }
1337   } listener;
1338   mock_journal.add_listener(&listener);
1339
1340   BOOST_SCOPE_EXIT_ALL(&) {
1341     mock_journal.remove_listener(&listener);
1342     close_journal(mock_journal, mock_journaler);
1343   };
1344
1345   InSequence seq;
1346
1347   journal::TagData tag_data;
1348   tag_data.mirror_uuid = Journal<>::LOCAL_MIRROR_UUID;
1349
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);
1354
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);
1359
1360   m_listener->handle_update(nullptr);
1361   ASSERT_EQ(0, listener.ctx.wait());
1362 }
1363
1364 } // namespace librbd