]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tests: unit test case for librbd::operation::ResizeRequest
authorJason Dillaman <dillaman@redhat.com>
Thu, 17 Dec 2015 06:22:37 +0000 (01:22 -0500)
committerJason Dillaman <dillaman@redhat.com>
Fri, 15 Jan 2016 15:40:28 +0000 (10:40 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/Makefile-client.am
src/test/librados_test_stub/MockTestMemIoCtxImpl.h
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/mock/MockJournal.h
src/test/librbd/mock/MockObjectMap.h
src/test/librbd/operation/test_mock_ResizeRequest.cc [new file with mode: 0644]

index cdcadff7a3d3812cdda62bc7f6d2a532c0bf14b3..3b275d4fda4938d60bf819b3f13ac64683ac2358 100644 (file)
@@ -374,6 +374,7 @@ unittest_librbd_SOURCES = \
        test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc \
        test/librbd/object_map/test_mock_UnlockRequest.cc \
        test/librbd/object_map/test_mock_UpdateRequest.cc \
+       test/librbd/operation/test_mock_ResizeRequest.cc \
        test/librbd/operation/test_mock_SnapshotCreateRequest.cc \
        test/librbd/operation/test_mock_SnapshotProtectRequest.cc \
        test/librbd/operation/test_mock_SnapshotRemoveRequest.cc \
index b0a481b56708b03044953264c8409c22196c5e5e..3bc957e373ae09e604c41d3962197ad909003f96 100644 (file)
@@ -87,6 +87,13 @@ public:
     return TestMemIoCtxImpl::truncate(oid, size, snapc);
   }
 
+  MOCK_METHOD5(write, int(const std::string& oid, bufferlist& bl, size_t len,
+                          uint64_t off, const SnapContext &snapc));
+  int do_write(const std::string& oid, bufferlist& bl, size_t len, uint64_t off,
+                    const SnapContext &snapc) {
+    return TestMemIoCtxImpl::write(oid, bl, len, off, snapc);
+  }
+
   MOCK_METHOD3(write_full, int(const std::string& oid,
                                bufferlist& bl,
                                const SnapContext &snapc));
@@ -105,6 +112,7 @@ public:
     ON_CALL(*this, selfmanaged_snap_create(_)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_selfmanaged_snap_create));
     ON_CALL(*this, selfmanaged_snap_remove(_)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_selfmanaged_snap_remove));
     ON_CALL(*this, truncate(_,_,_)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_truncate));
+    ON_CALL(*this, write(_, _, _, _, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_write));
     ON_CALL(*this, write_full(_, _, _)).WillByDefault(Invoke(this, &MockTestMemIoCtxImpl::do_write_full));
   }
 
index f5af5d2164d6596ddc13de589f99cf255428d3fa..d75364138ae49c9581facd4cf1da65da13a3bbb9 100644 (file)
 
 namespace librbd {
 
+namespace operation {
+template <typename> class ResizeRequest;
+}
+
 struct MockImageCtx {
   MockImageCtx(librbd::ImageCtx &image_ctx)
     : image_ctx(&image_ctx),
@@ -106,6 +110,7 @@ struct MockImageCtx {
   MOCK_METHOD1(flush, void(Context *));
   MOCK_METHOD1(flush_copyup, void(Context *));
 
+  MOCK_METHOD1(invalidate_cache, void(Context *));
   MOCK_METHOD1(shut_down_cache, void(Context *));
 
   MOCK_CONST_METHOD1(test_features, bool(uint64_t test_features));
@@ -145,6 +150,7 @@ struct MockImageCtx {
 
   ceph_file_layout layout;
 
+  xlist<operation::ResizeRequest<MockImageCtx>*> resize_reqs;
   xlist<AsyncRequest<MockImageCtx>*> async_requests;
   std::list<Context*> async_requests_waiters;
 
index a8e077af361f67f910e7a4968612610ee1676895..9b3ecfffd6c0a7d89a874be8204d1ccfe5091fae 100644 (file)
@@ -20,7 +20,15 @@ struct MockJournal {
   MOCK_METHOD1(close, void(Context *));
 
   MOCK_METHOD0(allocate_op_tid, uint64_t());
-  MOCK_METHOD2(append_op_event, void(uint64_t, journal::EventEntry&));
+
+  MOCK_METHOD3(append_op_event_mock, void(uint64_t, const journal::EventEntry&,
+                                          Context *));
+  void append_op_event(uint64_t op_tid, journal::EventEntry &&event_entry,
+                       Context *on_safe) {
+    // googlemock doesn't support move semantics
+    append_op_event_mock(op_tid, event_entry, on_safe);
+  }
+
   MOCK_METHOD2(commit_op_event, void(uint64_t, int));
 };
 
index 78c036ce2130eb8373fb020fbd43bdacfd212714..6be9beaab32a9721785c93d121b2712e7c4892e8 100644 (file)
@@ -16,6 +16,9 @@ struct MockObjectMap {
   MOCK_METHOD1(lock, void(Context *on_finish));
   MOCK_METHOD1(unlock, void(Context *on_finish));
 
+  MOCK_METHOD3(aio_resize, void(uint64_t new_size, uint8_t default_object_state,
+                                Context *on_finish));
+
   MOCK_METHOD2(snapshot_add, void(uint64_t snap_id, Context *on_finish));
   MOCK_METHOD2(snapshot_remove, void(uint64_t snap_id, Context *on_finish));
 };
diff --git a/src/test/librbd/operation/test_mock_ResizeRequest.cc b/src/test/librbd/operation/test_mock_ResizeRequest.cc
new file mode 100644 (file)
index 0000000..6067b4f
--- /dev/null
@@ -0,0 +1,387 @@
+// -*- 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/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "common/bit_vector.hpp"
+#include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/operation/ResizeRequest.h"
+#include "librbd/operation/TrimRequest.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace librbd {
+namespace operation {
+
+template <>
+class TrimRequest<MockImageCtx> {
+public:
+  static TrimRequest *s_instance;
+  static TrimRequest *create(MockImageCtx &image_ctx, Context *on_finish,
+                             uint64_t original_size, uint64_t new_size,
+                             ProgressContext &prog_ctx) {
+    assert(s_instance != nullptr);
+    s_instance->on_finish = on_finish;
+    return s_instance;
+  }
+
+  Context *on_finish = nullptr;
+
+  TrimRequest() {
+    s_instance = this;
+  }
+
+  MOCK_METHOD0(send, void());
+};
+
+TrimRequest<MockImageCtx> *TrimRequest<MockImageCtx>::s_instance = nullptr;
+
+} // namespace operation
+} // namespace librbd
+
+// template definitions
+#include "librbd/operation/ResizeRequest.cc"
+#include "librbd/operation/TrimRequest.cc"
+
+namespace librbd {
+namespace operation {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::WithArg;
+
+class TestMockOperationResizeRequest : public TestMockFixture {
+public:
+  typedef ResizeRequest<MockImageCtx> MockResizeRequest;
+  typedef TrimRequest<MockImageCtx> MockTrimRequest;
+
+  void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
+                  .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+  }
+
+  void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
+    EXPECT_CALL(*mock_image_ctx.aio_work_queue, unblock_writes())
+                  .Times(1);
+  }
+
+  void expect_is_journal_replaying(MockJournal &mock_journal) {
+    EXPECT_CALL(mock_journal, is_journal_replaying()).WillOnce(Return(false));
+  }
+
+  void expect_is_journal_ready(MockJournal &mock_journal) {
+    EXPECT_CALL(mock_journal, is_journal_ready()).WillOnce(Return(true));
+  }
+
+  void expect_allocate_op_tid(MockImageCtx &mock_image_ctx) {
+    if (mock_image_ctx.journal != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.journal, allocate_op_tid())
+                    .WillOnce(Return(1U));
+    }
+  }
+
+  void expect_append_op_event(MockImageCtx &mock_image_ctx, int r) {
+    if (mock_image_ctx.journal != nullptr) {
+      expect_is_journal_replaying(*mock_image_ctx.journal);
+      expect_allocate_op_tid(mock_image_ctx);
+      EXPECT_CALL(*mock_image_ctx.journal, append_op_event_mock(_, _, _))
+                    .WillOnce(WithArg<2>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
+    }
+  }
+
+  void expect_commit_op_event(MockImageCtx &mock_image_ctx, int r) {
+    if (mock_image_ctx.journal != nullptr) {
+      expect_is_journal_replaying(*mock_image_ctx.journal);
+      expect_is_journal_ready(*mock_image_ctx.journal);
+      EXPECT_CALL(*mock_image_ctx.journal, commit_op_event(1U, r));
+    }
+  }
+
+  void expect_is_lock_owner(MockImageCtx &mock_image_ctx) {
+    if (mock_image_ctx.exclusive_lock != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
+                    .WillOnce(Return(true));
+    }
+  }
+
+  void expect_grow_object_map(MockImageCtx &mock_image_ctx) {
+    if (mock_image_ctx.object_map != nullptr) {
+      expect_is_lock_owner(mock_image_ctx);
+      EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
+                    .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
+    }
+  }
+
+  void expect_shrink_object_map(MockImageCtx &mock_image_ctx) {
+    if (mock_image_ctx.object_map != nullptr) {
+      expect_is_lock_owner(mock_image_ctx);
+      EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
+                    .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
+    }
+  }
+
+  void expect_update_header(MockImageCtx &mock_image_ctx, int r) {
+    if (mock_image_ctx.old_format) {
+      EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                  write(mock_image_ctx.header_oid, _, _, _, _))
+                    .WillOnce(Return(r));
+    } else {
+      expect_is_lock_owner(mock_image_ctx);
+      if (mock_image_ctx.exclusive_lock != nullptr) {
+        EXPECT_CALL(*mock_image_ctx.exclusive_lock, assert_header_locked(_));
+      }
+      EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                  exec(mock_image_ctx.header_oid, _, "rbd", "set_size", _, _, _))
+                    .WillOnce(Return(r));
+    }
+  }
+
+  void expect_trim(MockImageCtx &mock_image_ctx,
+                   MockTrimRequest &mock_trim_request, int r) {
+    EXPECT_CALL(mock_trim_request, send())
+                  .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
+  }
+
+  void expect_invalidate_cache(MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(mock_image_ctx, invalidate_cache(_))
+                  .WillOnce(CompleteContext(r, NULL));
+    expect_op_work_queue(mock_image_ctx);
+  }
+
+  void expect_resize_object_map(MockImageCtx &mock_image_ctx,
+                                uint64_t new_size) {
+    EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(new_size, _, _))
+                  .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
+  }
+
+  int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size) {
+    C_SaferCond cond_ctx;
+    librbd::NoOpProgressContext prog_ctx;
+    MockResizeRequest *req = new MockResizeRequest(
+      mock_image_ctx, &cond_ctx, new_size, prog_ctx);
+    {
+      RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
+      req->send();
+    }
+    return cond_ctx.wait();
+  }
+
+  void initialize_features(ImageCtx *ictx, MockImageCtx &mock_image_ctx,
+                           MockExclusiveLock &mock_exclusive_lock,
+                           MockJournal &mock_journal,
+                           MockObjectMap &mock_object_map) {
+    if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+      mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+    }
+    if (ictx->test_features(RBD_FEATURE_JOURNALING)) {
+      mock_image_ctx.journal = &mock_journal;
+    }
+    if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+      mock_image_ctx.object_map = &mock_object_map;
+    }
+  }
+};
+
+TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+  expect_commit_op_event(mock_image_ctx, 0);
+  ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size));
+}
+
+TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+  expect_grow_object_map(mock_image_ctx);
+  expect_block_writes(mock_image_ctx, 0);
+  expect_update_header(mock_image_ctx, 0);
+  expect_commit_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+  ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+
+  MockTrimRequest mock_trim_request;
+  expect_trim(mock_image_ctx, mock_trim_request, 0);
+  expect_invalidate_cache(mock_image_ctx, 0);
+  expect_block_writes(mock_image_ctx, 0);
+  expect_update_header(mock_image_ctx, 0);
+  expect_commit_op_event(mock_image_ctx, 0);
+  expect_shrink_object_map(mock_image_ctx);
+  expect_unblock_writes(mock_image_ctx);
+  ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, -EINVAL);
+  expect_unblock_writes(mock_image_ctx);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size));
+}
+
+TEST_F(TestMockOperationResizeRequest, TrimError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+
+  MockTrimRequest mock_trim_request;
+  expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
+  expect_commit_op_event(mock_image_ctx, -EINVAL);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+
+  MockTrimRequest mock_trim_request;
+  expect_trim(mock_image_ctx, mock_trim_request, 0);
+  expect_invalidate_cache(mock_image_ctx, -EINVAL);
+  expect_commit_op_event(mock_image_ctx, -EINVAL);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+  expect_grow_object_map(mock_image_ctx);
+  expect_block_writes(mock_image_ctx, -EINVAL);
+  expect_unblock_writes(mock_image_ctx);
+  expect_commit_op_event(mock_image_ctx, -EINVAL);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, 0);
+  expect_unblock_writes(mock_image_ctx);
+  expect_grow_object_map(mock_image_ctx);
+  expect_block_writes(mock_image_ctx, 0);
+  expect_update_header(mock_image_ctx, -EINVAL);
+  expect_unblock_writes(mock_image_ctx);
+  expect_commit_op_event(mock_image_ctx, -EINVAL);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2));
+}
+
+TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, -EINVAL);
+  expect_unblock_writes(mock_image_ctx);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size));
+}
+
+} // namespace operation
+} // namespace librbd