]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
test: unit test cases for disabling librbd journal by policy
authorJason Dillaman <dillaman@redhat.com>
Wed, 27 Jul 2016 03:28:43 +0000 (23:28 -0400)
committerMykola Golub <mgolub@mirantis.com>
Fri, 19 Aug 2016 19:59:07 +0000 (22:59 +0300)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
(cherry picked from commit 4a256f5044ac54a8a0a9598ee7fd151b8ea08f84)

Conflicts:
src/test/librbd/CMakeLists.txt (test_ConsistencyGroups.cc)

src/test/librbd/CMakeLists.txt
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/operation/test_mock_Request.cc [new file with mode: 0644]
src/test/librbd/test_mock_AioImageRequest.cc [new file with mode: 0644]
src/test/librbd/test_mock_Journal.cc
src/test/rbd_mirror/image_sync/test_mock_ImageCopyRequest.cc
src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc

index e51a96c1a52587fedd92f7ab83d6eddac3e980fb..aff27a628ca57ca780f98735f49a847783a74850 100644 (file)
@@ -16,28 +16,30 @@ set_target_properties(rbd_test PROPERTIES COMPILE_FLAGS ${UNITTEST_CXX_FLAGS})
 # doesn't use add_ceph_test because it is called by run-rbd-unit-tests.sh
 set(unittest_librbd_srcs
   test_main.cc
-  test_mock_fixture.cc 
-  test_mock_ExclusiveLock.cc 
-  test_mock_Journal.cc 
-  test_mock_ObjectWatcher.cc 
-  exclusive_lock/test_mock_AcquireRequest.cc 
-  exclusive_lock/test_mock_ReleaseRequest.cc 
+  test_mock_fixture.cc
+  test_mock_AioImageRequest.cc
+  test_mock_ExclusiveLock.cc
+  test_mock_Journal.cc
+  test_mock_ObjectWatcher.cc
+  exclusive_lock/test_mock_AcquireRequest.cc
+  exclusive_lock/test_mock_ReleaseRequest.cc
   image/test_mock_RefreshRequest.cc
-  journal/test_mock_Replay.cc 
-  object_map/test_mock_InvalidateRequest.cc 
-  object_map/test_mock_LockRequest.cc 
-  object_map/test_mock_RefreshRequest.cc 
-  object_map/test_mock_ResizeRequest.cc 
-  object_map/test_mock_SnapshotCreateRequest.cc 
-  object_map/test_mock_SnapshotRemoveRequest.cc 
-  object_map/test_mock_SnapshotRollbackRequest.cc 
-  object_map/test_mock_UnlockRequest.cc 
-  object_map/test_mock_UpdateRequest.cc 
-  operation/test_mock_ResizeRequest.cc 
-  operation/test_mock_SnapshotCreateRequest.cc 
-  operation/test_mock_SnapshotProtectRequest.cc 
-  operation/test_mock_SnapshotRemoveRequest.cc 
-  operation/test_mock_SnapshotRollbackRequest.cc 
+  journal/test_mock_Replay.cc
+  object_map/test_mock_InvalidateRequest.cc
+  object_map/test_mock_LockRequest.cc
+  object_map/test_mock_RefreshRequest.cc
+  object_map/test_mock_ResizeRequest.cc
+  object_map/test_mock_SnapshotCreateRequest.cc
+  object_map/test_mock_SnapshotRemoveRequest.cc
+  object_map/test_mock_SnapshotRollbackRequest.cc
+  object_map/test_mock_UnlockRequest.cc
+  object_map/test_mock_UpdateRequest.cc
+  operation/test_mock_Request.cc
+  operation/test_mock_ResizeRequest.cc
+  operation/test_mock_SnapshotCreateRequest.cc
+  operation/test_mock_SnapshotProtectRequest.cc
+  operation/test_mock_SnapshotRemoveRequest.cc
+  operation/test_mock_SnapshotRollbackRequest.cc
   operation/test_mock_SnapshotUnprotectRequest.cc
   mock/MockImageCtx.cc
   mock/MockJournal.cc
index e43927a9e0ab10865448c2951d5a2c2594c0fd7c..2818eb566dacf779d5b519317661b023e63f015a 100644 (file)
@@ -54,13 +54,13 @@ struct MockImageCtx {
       lockers(image_ctx.lockers),
       exclusive_locked(image_ctx.exclusive_locked),
       lock_tag(image_ctx.lock_tag),
-      owner_lock("owner_lock"),
-      md_lock("md_lock"),
-      cache_lock("cache_lock"),
-      snap_lock("snap_lock"),
-      parent_lock("parent_lock"),
-      object_map_lock("object_map_lock"),
-      async_ops_lock("async_ops_lock"),
+      owner_lock(image_ctx.owner_lock),
+      md_lock(image_ctx.md_lock),
+      cache_lock(image_ctx.cache_lock),
+      snap_lock(image_ctx.snap_lock),
+      parent_lock(image_ctx.parent_lock),
+      object_map_lock(image_ctx.object_map_lock),
+      async_ops_lock(image_ctx.async_ops_lock),
       order(image_ctx.order),
       size(image_ctx.size),
       features(image_ctx.features),
@@ -202,13 +202,13 @@ struct MockImageCtx {
   librados::IoCtx md_ctx;
   librados::IoCtx data_ctx;
 
-  RWLock owner_lock;
-  RWLock md_lock;
-  Mutex cache_lock;
-  RWLock snap_lock;
-  RWLock parent_lock;
-  RWLock object_map_lock;
-  Mutex async_ops_lock;
+  RWLock &owner_lock;
+  RWLock &md_lock;
+  Mutex &cache_lock;
+  RWLock &snap_lock;
+  RWLock &parent_lock;
+  RWLock &object_map_lock;
+  Mutex &async_ops_lock;
 
   uint8_t order;
   uint64_t size;
diff --git a/src/test/librbd/operation/test_mock_Request.cc b/src/test/librbd/operation/test_mock_Request.cc
new file mode 100644 (file)
index 0000000..397ffd8
--- /dev/null
@@ -0,0 +1,176 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/MockJournal.h"
+#include "librbd/AsyncRequest.h"
+#include "librbd/operation/Request.h"
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public MockImageCtx {
+  MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
+  }
+};
+
+} // anonymous namespace
+
+template <>
+struct AsyncRequest<librbd::MockTestImageCtx> {
+  librbd::MockTestImageCtx &m_image_ctx;
+  Context *m_on_finish;
+
+  AsyncRequest(librbd::MockTestImageCtx &image_ctx, Context *on_finish)
+    : m_image_ctx(image_ctx), m_on_finish(on_finish) {
+  }
+  virtual ~AsyncRequest() {
+  }
+
+  virtual void finish(int r) {
+    m_on_finish->complete(r);
+  }
+  virtual void finish_and_destroy(int r) {
+    finish(r);
+    delete this;
+  }
+};
+
+} // namespace librbd
+
+#include "librbd/operation/Request.cc"
+template class librbd::operation::Request<librbd::MockTestImageCtx>;
+
+namespace librbd {
+namespace journal {
+
+std::ostream& operator<<(std::ostream& os, const Event&) {
+  return os;
+}
+
+} // namespace journal
+
+namespace operation {
+
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+
+struct MockRequest : public Request<librbd::MockTestImageCtx> {
+  MockRequest(librbd::MockTestImageCtx &image_ctx, Context *on_finish,
+              uint64_t journal_op_tid)
+    : Request<librbd::MockTestImageCtx>(image_ctx, on_finish, journal_op_tid) {
+  }
+
+  void complete(int r) {
+    finish_and_destroy(r);
+  }
+
+  void send_op_impl(int r) {
+    bool appending = append_op_event<
+      MockRequest, &MockRequest::handle_send>(this);
+    if (!appending) {
+      complete(r);
+    }
+  }
+  MOCK_METHOD1(should_complete, bool(int));
+  MOCK_METHOD0(send_op, void());
+  MOCK_METHOD1(handle_send, Context*(int*));
+  MOCK_CONST_METHOD0(can_affect_io, bool());
+  MOCK_CONST_METHOD1(create_event, journal::Event(uint64_t));
+};
+
+struct TestMockOperationRequest : public TestMockFixture {
+  void expect_can_affect_io(MockRequest &mock_request, bool can_affect) {
+    EXPECT_CALL(mock_request, can_affect_io())
+      .WillOnce(Return(can_affect));
+  }
+
+  void expect_is_journal_replaying(MockJournal &mock_journal, bool replaying) {
+    EXPECT_CALL(mock_journal, is_journal_replaying())
+      .WillOnce(Return(replaying));
+  }
+
+  void expect_is_journal_appending(MockJournal &mock_journal, bool appending) {
+    EXPECT_CALL(mock_journal, is_journal_appending())
+      .WillOnce(Return(appending));
+  }
+
+  void expect_send_op(MockRequest &mock_request, int r) {
+    EXPECT_CALL(mock_request, send_op())
+      .WillOnce(Invoke([&mock_request, r]() {
+                  mock_request.complete(r);
+                }));
+  }
+
+  void expect_send_op_affects_io(MockImageCtx &mock_image_ctx,
+                                 MockRequest &mock_request, int r) {
+    EXPECT_CALL(mock_request, send_op())
+      .WillOnce(Invoke([&mock_image_ctx, &mock_request, r]() {
+                  mock_image_ctx.image_ctx->op_work_queue->queue(
+                    new FunctionContext([&mock_request, r](int _) {
+                      mock_request.send_op_impl(r);
+                    }), 0);
+                }));
+  }
+
+};
+
+TEST_F(TestMockOperationRequest, SendJournalDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+
+  C_SaferCond ctx;
+  MockRequest *mock_request = new MockRequest(mock_image_ctx, &ctx, 0);
+
+  InSequence seq;
+  expect_can_affect_io(*mock_request, false);
+  expect_is_journal_appending(mock_journal, false);
+  expect_send_op(*mock_request, 0);
+
+  {
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+    mock_request->send();
+  }
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockOperationRequest, SendAffectsIOJournalDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+
+  C_SaferCond ctx;
+  MockRequest *mock_request = new MockRequest(mock_image_ctx, &ctx, 0);
+
+  InSequence seq;
+  expect_can_affect_io(*mock_request, true);
+  expect_send_op_affects_io(mock_image_ctx, *mock_request, 0);
+  expect_can_affect_io(*mock_request, true);
+  expect_is_journal_replaying(mock_journal, false);
+  expect_is_journal_appending(mock_journal, false);
+
+  {
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+    mock_request->send();
+  }
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+} // namespace operation
+} // namespace librbd
diff --git a/src/test/librbd/test_mock_AioImageRequest.cc b/src/test/librbd/test_mock_AioImageRequest.cc
new file mode 100644 (file)
index 0000000..2cd6b16
--- /dev/null
@@ -0,0 +1,257 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/MockJournal.h"
+#include "librbd/AioImageRequest.h"
+#include "librbd/AioObjectRequest.h"
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public MockImageCtx {
+  MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
+  }
+};
+
+} // anonymous namespace
+
+namespace util {
+
+inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
+  return image_ctx->image_ctx;
+}
+
+} // namespace util
+
+template <>
+struct AioObjectRequest<librbd::MockTestImageCtx> : public AioObjectRequestHandle {
+  static AioObjectRequest* s_instance;
+  Context *on_finish = nullptr;
+
+  static AioObjectRequest* create_remove(librbd::MockTestImageCtx *ictx,
+                                         const std::string &oid,
+                                         uint64_t object_no,
+                                         const ::SnapContext &snapc,
+                                         Context *completion) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = completion;
+    return s_instance;
+  }
+
+  static AioObjectRequest* create_truncate(librbd::MockTestImageCtx *ictx,
+                                           const std::string &oid,
+                                           uint64_t object_no,
+                                           uint64_t object_off,
+                                           const ::SnapContext &snapc,
+                                           Context *completion) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = completion;
+    return s_instance;
+  }
+
+  static AioObjectRequest* create_write(librbd::MockTestImageCtx *ictx,
+                                        const std::string &oid,
+                                        uint64_t object_no,
+                                        uint64_t object_off,
+                                        const ceph::bufferlist &data,
+                                        const ::SnapContext &snapc,
+                                        Context *completion, int op_flags) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = completion;
+    return s_instance;
+  }
+
+  static AioObjectRequest* create_zero(librbd::MockTestImageCtx *ictx,
+                                       const std::string &oid,
+                                       uint64_t object_no, uint64_t object_off,
+                                       uint64_t object_len,
+                                       const ::SnapContext &snapc,
+                                       Context *completion) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = completion;
+    return s_instance;
+  }
+
+  AioObjectRequest() {
+    assert(s_instance == nullptr);
+    s_instance = this;
+  }
+  ~AioObjectRequest() {
+    s_instance = nullptr;
+  }
+
+  MOCK_METHOD1(complete, void(int));
+  MOCK_METHOD0(send, void());
+};
+
+template <>
+struct AioObjectRead<librbd::MockTestImageCtx> : public AioObjectRequest<librbd::MockTestImageCtx> {
+  typedef std::vector<std::pair<uint64_t, uint64_t> > Extents;
+  typedef std::map<uint64_t, uint64_t> ExtentMap;
+
+  static AioObjectRead* s_instance;
+
+  static AioObjectRead* create(librbd::MockTestImageCtx *ictx,
+                               const std::string &oid,
+                               uint64_t objectno, uint64_t offset,
+                               uint64_t len, Extents &buffer_extents,
+                               librados::snap_t snap_id, bool sparse,
+                               Context *completion, int op_flags) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = completion;
+    return s_instance;
+  }
+
+  AioObjectRead() {
+    assert(s_instance == nullptr);
+    s_instance = this;
+  }
+  ~AioObjectRead() {
+    s_instance = nullptr;
+  }
+
+  MOCK_CONST_METHOD0(get_offset, uint64_t());
+  MOCK_CONST_METHOD0(get_length, uint64_t());
+  MOCK_METHOD0(data, ceph::bufferlist &());
+  MOCK_CONST_METHOD0(get_buffer_extents, const Extents &());
+  MOCK_METHOD0(get_extent_map, ExtentMap &());
+
+};
+
+AioObjectRequest<librbd::MockTestImageCtx>* AioObjectRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+AioObjectRead<librbd::MockTestImageCtx>* AioObjectRead<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace librbd
+
+#include "librbd/AioImageRequest.cc"
+template class librbd::AioImageRequest<librbd::MockTestImageCtx>;
+
+namespace librbd {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::WithArg;
+
+struct TestMockAioImageRequest : public TestMockFixture {
+  typedef AioImageRequest<librbd::MockTestImageCtx> MockAioImageRequest;
+  typedef AioImageWrite<librbd::MockTestImageCtx> MockAioImageWrite;
+  typedef AioImageDiscard<librbd::MockTestImageCtx> MockAioImageDiscard;
+  typedef AioImageFlush<librbd::MockTestImageCtx> MockAioImageFlush;
+  typedef AioObjectRequest<librbd::MockTestImageCtx> MockAioObjectRequest;
+  typedef AioObjectRead<librbd::MockTestImageCtx> MockAioObjectRead;
+
+  void expect_is_journal_appending(MockJournal &mock_journal, bool appending) {
+    EXPECT_CALL(mock_journal, is_journal_appending())
+      .WillOnce(Return(appending));
+  }
+
+  void expect_write_to_cache(MockImageCtx &mock_image_ctx,
+                             const object_t &object,
+                             uint64_t offset, uint64_t length,
+                             uint64_t journal_tid, int r) {
+    EXPECT_CALL(mock_image_ctx, write_to_cache(object, _, length, offset, _, _,
+                journal_tid))
+      .WillOnce(WithArg<4>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
+  }
+
+  void expect_object_request_send(MockImageCtx &mock_image_ctx,
+                                  MockAioObjectRequest &mock_object_request,
+                                  int r) {
+    EXPECT_CALL(mock_object_request, send())
+      .WillOnce(Invoke([&mock_image_ctx, &mock_object_request, r]() {
+                  mock_image_ctx.image_ctx->op_work_queue->queue(
+                    mock_object_request.on_finish, r);
+                }));
+  }
+
+  void expect_flush(MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(mock_image_ctx, flush(_))
+      .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+  }
+};
+
+TEST_F(TestMockAioImageRequest, AioWriteJournalAppendDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockAioObjectRequest mock_aio_object_request;
+  MockTestImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+
+  InSequence seq;
+  expect_is_journal_appending(mock_journal, false);
+  expect_write_to_cache(mock_image_ctx, ictx->get_object_name(0),
+                        0, 1, 0, 0);
+
+  C_SaferCond aio_comp_ctx;
+  AioCompletion *aio_comp = AioCompletion::create_and_start(
+    &aio_comp_ctx, ictx, AIO_TYPE_WRITE);
+  MockAioImageWrite mock_aio_image_write(mock_image_ctx, aio_comp, 0, 1, "1",
+                                         0);
+  {
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+    mock_aio_image_write.send();
+  }
+  ASSERT_EQ(0, aio_comp_ctx.wait());
+}
+
+TEST_F(TestMockAioImageRequest, AioDiscardJournalAppendDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockAioObjectRequest mock_aio_object_request;
+  MockTestImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+
+  InSequence seq;
+  expect_is_journal_appending(mock_journal, false);
+  expect_object_request_send(mock_image_ctx, mock_aio_object_request, 0);
+
+  C_SaferCond aio_comp_ctx;
+  AioCompletion *aio_comp = AioCompletion::create_and_start(
+    &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
+  MockAioImageDiscard mock_aio_image_discard(mock_image_ctx, aio_comp, 0, 1);
+  {
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+    mock_aio_image_discard.send();
+  }
+  ASSERT_EQ(0, aio_comp_ctx.wait());
+}
+
+TEST_F(TestMockAioImageRequest, AioFlushJournalAppendDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal;
+  mock_image_ctx.journal = &mock_journal;
+
+  InSequence seq;
+  expect_is_journal_appending(mock_journal, false);
+  expect_flush(mock_image_ctx, 0);
+
+  C_SaferCond aio_comp_ctx;
+  AioCompletion *aio_comp = AioCompletion::create_and_start(
+    &aio_comp_ctx, ictx, AIO_TYPE_FLUSH);
+  MockAioImageFlush mock_aio_image_flush(mock_image_ctx, aio_comp);
+  {
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+    mock_aio_image_flush.send();
+  }
+  ASSERT_EQ(0, aio_comp_ctx.wait());
+}
+
+} // namespace librbd
index 1b8f0d64ce1318d4198162b13a94d3264b4f0a10..3785f2ce783e2a4e7fe208774f6925a9bd676e22 100644 (file)
@@ -5,6 +5,7 @@
 #include "test/journal/mock/MockJournaler.h"
 #include "test/librbd/test_support.h"
 #include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/MockJournalPolicy.h"
 #include "common/Cond.h"
 #include "common/Mutex.h"
 #include "cls/journal/cls_journal_types.h"
@@ -158,6 +159,7 @@ public:
   }
 
   void expect_shut_down_journaler(::journal::MockJournaler &mock_journaler) {
+    EXPECT_CALL(mock_journaler, remove_listener(_));
     EXPECT_CALL(mock_journaler, shut_down(_))
                   .WillOnce(CompleteContext(0, NULL));
   }
@@ -196,6 +198,7 @@ public:
     EXPECT_CALL(mock_journaler, get_tags(0, _, _))
                   .WillOnce(DoAll(SetArgPointee<1>(tags),
                                   WithArg<2>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))));
+    EXPECT_CALL(mock_journaler, add_listener(_));
   }
 
   void expect_start_replay(MockJournalImageCtx &mock_image_ctx,
@@ -714,6 +717,8 @@ TEST_F(TestMockJournal, ReplayOnDiskPreFlushError) {
   MockJournalReplay mock_journal_replay;
   expect_try_pop_front(mock_journaler, true, mock_replay_entry);
 
+  EXPECT_CALL(mock_journal_replay, decode(_, _))
+                .WillOnce(Return(0));
   Context *on_ready;
   EXPECT_CALL(mock_journal_replay, process(_, _, _))
                 .WillOnce(DoAll(SaveArg<1>(&on_ready),
@@ -1151,5 +1156,34 @@ TEST_F(TestMockJournal, ExternalReplayCloseRequest) {
   ASSERT_EQ(0, close_ctx.wait());
 }
 
+TEST_F(TestMockJournal, AppendDisabled) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockJournalImageCtx mock_image_ctx(*ictx);
+  MockJournal mock_journal(mock_image_ctx);
+  MockJournalPolicy mock_journal_policy;
+
+  ::journal::MockJournaler mock_journaler;
+  open_journal(mock_image_ctx, mock_journal, mock_journaler);
+  BOOST_SCOPE_EXIT_ALL(&) {
+    close_journal(mock_journal, mock_journaler);
+  };
+
+  InSequence seq;
+  RWLock::RLocker snap_locker(mock_image_ctx.snap_lock);
+  EXPECT_CALL(mock_image_ctx, get_journal_policy()).WillOnce(
+    Return(ictx->get_journal_policy()));
+  ASSERT_TRUE(mock_journal.is_journal_appending());
+
+  EXPECT_CALL(mock_image_ctx, get_journal_policy()).WillOnce(
+    Return(&mock_journal_policy));
+  EXPECT_CALL(mock_journal_policy, append_disabled()).WillOnce(Return(true));
+  ASSERT_FALSE(mock_journal.is_journal_appending());
+
+  expect_shut_down_journaler(mock_journaler);
+}
 
 } // namespace librbd
index d924a3cab287269895c944fb05b1a0b33cf03f5e..79e7fa85d9a7bb3db41bc25a29d25d051bed4e8d 100644 (file)
@@ -109,7 +109,7 @@ public:
   void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) {
     EXPECT_CALL(mock_image_ctx, get_snap_id(_))
       .WillRepeatedly(Invoke([&mock_image_ctx](std::string snap_name) {
-        RWLock::RLocker snap_locker(mock_image_ctx.image_ctx->snap_lock);
+        assert(mock_image_ctx.image_ctx->snap_lock.is_locked());
         return mock_image_ctx.image_ctx->get_snap_id(snap_name);
       }));
   }
index e27bcb6db17800a18e3eb8fd75132f0d4cc9d7c8..b018f16c21b3045be3b8f2c5677a5d846cfc9606 100644 (file)
@@ -179,8 +179,8 @@ public:
           })));
       } else {
         expect.WillOnce(WithArg<5>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) {
-            RWLock::RLocker snap_locker(mock_image_ctx.image_ctx->snap_lock);
-            RWLock::WLocker object_map_locker(mock_image_ctx.image_ctx->object_map_lock);
+            assert(mock_image_ctx.image_ctx->snap_lock.is_locked());
+            assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked());
             mock_image_ctx.image_ctx->object_map->aio_update(snap_id, 0, 1,
                                                              state,
                                                              boost::none, ctx);