]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
tests: mock test cases for new async object map lock/unlock/refresh ops
authorJason Dillaman <dillaman@redhat.com>
Sat, 5 Dec 2015 02:45:24 +0000 (21:45 -0500)
committerJason Dillaman <dillaman@redhat.com>
Tue, 15 Dec 2015 01:30:51 +0000 (20:30 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/Makefile-client.am
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/object_map/test_mock_LockRequest.cc [new file with mode: 0644]
src/test/librbd/object_map/test_mock_RefreshRequest.cc [new file with mode: 0644]
src/test/librbd/object_map/test_mock_UnlockRequest.cc [new file with mode: 0644]
src/test/librbd/test_mock_fixture.h

index 533e81beebbe39b824701c2d899882aa5c276e34..07efa48a5d858024460d6d937ef9063e05654e88 100644 (file)
@@ -354,10 +354,13 @@ unittest_librbd_SOURCES = \
         test/librbd/test_main.cc \
        test/librbd/test_mock_fixture.cc \
        test/librbd/object_map/test_mock_InvalidateRequest.cc \
+       test/librbd/object_map/test_mock_LockRequest.cc \
+       test/librbd/object_map/test_mock_RefreshRequest.cc \
        test/librbd/object_map/test_mock_ResizeRequest.cc \
        test/librbd/object_map/test_mock_SnapshotCreateRequest.cc \
        test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc \
        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_SnapshotCreateRequest.cc \
        test/librbd/operation/test_mock_SnapshotProtectRequest.cc \
index 1e70b1f27cfcb13c3821d0e73c9923128c0313c8..3633a5256f0c6d0c38f93b912bfb2a8ece3a4399 100644 (file)
@@ -35,6 +35,7 @@ struct MockImageCtx {
       header_oid(image_ctx.header_oid),
       id(image_ctx.id),
       parent_md(image_ctx.parent_md),
+      layout(image_ctx.layout),
       aio_work_queue(new MockAioImageRequestWQ()),
       op_work_queue(new MockContextWQ()),
       image_watcher(NULL), journal(NULL),
@@ -62,6 +63,7 @@ struct MockImageCtx {
     }
   }
 
+  MOCK_CONST_METHOD1(get_image_size, uint64_t(librados::snap_t));
   MOCK_CONST_METHOD1(get_snap_id, librados::snap_t(std::string in_snap_name));
   MOCK_CONST_METHOD1(get_snap_info, const SnapInfo*(librados::snap_t));
   MOCK_CONST_METHOD2(get_parent_spec, int(librados::snap_t in_snap_id,
@@ -105,6 +107,8 @@ struct MockImageCtx {
   std::string id;
   parent_info parent_md;
 
+  ceph_file_layout layout;
+
   xlist<AsyncRequest<MockImageCtx>*> async_requests;
   Cond async_requests_cond;
 
diff --git a/src/test/librbd/object_map/test_mock_LockRequest.cc b/src/test/librbd/object_map/test_mock_LockRequest.cc
new file mode 100644 (file)
index 0000000..e7a62fd
--- /dev/null
@@ -0,0 +1,215 @@
+// -*- 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 "cls/lock/cls_lock_ops.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/object_map/LockRequest.h"
+
+// template definitions
+#include "librbd/object_map/LockRequest.cc"
+
+namespace librbd {
+namespace object_map {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::WithArg;
+
+class TestMockObjectMapLockRequest : public TestMockFixture {
+public:
+  typedef LockRequest<MockImageCtx> MockLockRequest;
+
+  void expect_lock(MockImageCtx &mock_image_ctx, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, CEPH_NOSNAP));
+    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                exec(oid, _, "lock", "lock", _, _, _))
+                  .WillOnce(Return(r));
+  }
+
+  void expect_get_lock_info(MockImageCtx &mock_image_ctx, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, CEPH_NOSNAP));
+    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                               exec(oid, _, "lock", "get_info", _, _, _));
+    if (r < 0) {
+      expect.WillOnce(Return(r));
+    } else {
+      entity_name_t entity1(entity_name_t::CLIENT(1));
+      entity_name_t entity2(entity_name_t::CLIENT(2));
+
+      cls_lock_get_info_reply reply;
+      reply.lockers = decltype(reply.lockers){
+        {rados::cls::lock::locker_id_t(entity1, "cookie1"),
+         rados::cls::lock::locker_info_t()},
+        {rados::cls::lock::locker_id_t(entity2, "cookie2"),
+         rados::cls::lock::locker_info_t()}};
+
+      bufferlist bl;
+      ::encode(reply, bl);
+
+      std::string str(bl.c_str(), bl.length());
+      expect.WillOnce(DoAll(WithArg<5>(CopyInBufferlist(str)), Return(r)));
+    }
+  }
+
+  void expect_break_lock(MockImageCtx &mock_image_ctx, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, CEPH_NOSNAP));
+    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                               exec(oid, _, "lock", "break_lock", _, _, _));
+    if (r < 0) {
+      expect.WillOnce(Return(r));
+    } else {
+      expect.Times(2).WillRepeatedly(Return(0));
+    }
+  }
+};
+
+TEST_F(TestMockObjectMapLockRequest, Success) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, 0);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, LockBusy) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, 0);
+  expect_break_lock(mock_image_ctx, 0);
+  expect_lock(mock_image_ctx, 0);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, LockError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -ENOENT);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, GetLockInfoMissing) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, -ENOENT);
+  expect_lock(mock_image_ctx, 0);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, GetLockInfoError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, -EINVAL);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, BreakLockMissing) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, 0);
+  expect_break_lock(mock_image_ctx, -ENOENT);
+  expect_lock(mock_image_ctx, 0);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, BreakLockError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, 0);
+  expect_break_lock(mock_image_ctx, -EINVAL);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapLockRequest, LockErrorAfterBrokeLock) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockLockRequest *req = new MockLockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_lock(mock_image_ctx, -EBUSY);
+  expect_get_lock_info(mock_image_ctx, 0);
+  expect_break_lock(mock_image_ctx, 0);
+  expect_lock(mock_image_ctx, -EBUSY);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+} // namespace object_map
+} // namespace librbd
diff --git a/src/test/librbd/object_map/test_mock_RefreshRequest.cc b/src/test/librbd/object_map/test_mock_RefreshRequest.cc
new file mode 100644 (file)
index 0000000..043ad35
--- /dev/null
@@ -0,0 +1,291 @@
+// -*- 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/object_map/mock/MockInvalidateRequest.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "common/bit_vector.hpp"
+#include "librbd/ObjectMap.h"
+#include "librbd/object_map/RefreshRequest.h"
+
+// template definitions
+#include "librbd/object_map/RefreshRequest.cc"
+
+namespace librbd {
+namespace object_map {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::DoDefault;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::WithArg;
+
+class TestMockObjectMapRefreshRequest : public TestMockFixture {
+public:
+  static const uint64_t TEST_SNAP_ID = 123;
+
+  typedef RefreshRequest<MockImageCtx> MockRefreshRequest;
+
+  void expect_object_map_load(MockImageCtx &mock_image_ctx,
+                              ceph::BitVector<2> *object_map, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, TEST_SNAP_ID));
+    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                               exec(oid, _, "rbd", "object_map_load", _, _, _));
+    if (r < 0) {
+      expect.WillOnce(Return(r));
+    } else {
+      assert(object_map);
+      object_map->set_crc_enabled(false);
+
+      bufferlist bl;
+      ::encode(*object_map, bl);
+
+      std::string str(bl.c_str(), bl.length());
+      expect.WillOnce(DoAll(WithArg<5>(CopyInBufferlist(str)), Return(0)));
+    }
+  }
+
+  void expect_get_image_size(MockImageCtx &mock_image_ctx, uint64_t size) {
+    EXPECT_CALL(mock_image_ctx, get_image_size(TEST_SNAP_ID))
+                  .WillOnce(Return(size));
+  }
+
+  void expect_invalidate_request(MockImageCtx &mock_image_ctx,
+                                 MockInvalidateRequest &invalidate_request) {
+    EXPECT_CALL(invalidate_request, send())
+                  .WillOnce(FinishRequest(&invalidate_request, 0,
+                                          &mock_image_ctx));
+  }
+
+  void expect_truncate_request(MockImageCtx &mock_image_ctx) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, TEST_SNAP_ID));
+    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), truncate(oid, 0, _))
+                  .WillOnce(Return(0));
+  }
+
+  void expect_object_map_resize(MockImageCtx &mock_image_ctx,
+                                uint64_t num_objects, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, TEST_SNAP_ID));
+    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                               exec(oid, _, "rbd", "object_map_resize", _, _, _));
+    expect.WillOnce(Return(r));
+  }
+
+  void init_object_map(MockImageCtx &mock_image_ctx,
+                       ceph::BitVector<2> *object_map) {
+    uint64_t num_objs = Striper::get_num_objects(
+      mock_image_ctx.layout, mock_image_ctx.image_ctx->size);
+    object_map->resize(num_objs);
+    for (uint64_t i = 0; i < num_objs; ++i) {
+      (*object_map)[i] = rand() % 3;
+    }
+  }
+
+  void when_apply_refresh_request(MockImageCtx &mock_image_ctx,
+                                 MockRefreshRequest *req) {
+    RWLock::WLocker snap_locker(mock_image_ctx.snap_lock);
+    RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock);
+    expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+    req->apply();
+  }
+};
+
+TEST_F(TestMockObjectMapRefreshRequest, Success) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, &on_disk_object_map, 0);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+  ASSERT_EQ(on_disk_object_map, object_map);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, LoadError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, nullptr, -ENOENT);
+
+  MockInvalidateRequest invalidate_request;
+  expect_invalidate_request(mock_image_ctx, invalidate_request);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, LoadCorrupt) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, nullptr, -EINVAL);
+
+  MockInvalidateRequest invalidate_request;
+  expect_invalidate_request(mock_image_ctx, invalidate_request);
+  expect_truncate_request(mock_image_ctx);
+  expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), 0);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, TooSmall) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  ceph::BitVector<2> small_object_map;
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, &small_object_map, 0);
+
+  MockInvalidateRequest invalidate_request;
+  expect_invalidate_request(mock_image_ctx, invalidate_request);
+  expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), 0);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, TooLarge) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  ceph::BitVector<2> large_object_map;
+  large_object_map.resize(on_disk_object_map.size() * 2);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, &large_object_map, 0);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, ResizeError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  ceph::BitVector<2> on_disk_object_map;
+  init_object_map(mock_image_ctx, &on_disk_object_map);
+
+  ceph::BitVector<2> small_object_map;
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+
+  InSequence seq;
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
+  expect_object_map_load(mock_image_ctx, &small_object_map, 0);
+
+  MockInvalidateRequest invalidate_request;
+  expect_invalidate_request(mock_image_ctx, invalidate_request);
+  expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), -ESTALE);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  when_apply_refresh_request(mock_image_ctx, req);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, StaleRefresh) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+  ASSERT_THROW(when_apply_refresh_request(mock_image_ctx, req),
+               ceph::FailedAssertion);
+}
+
+TEST_F(TestMockObjectMapRefreshRequest, Discard) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  ceph::BitVector<2> object_map;
+  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
+                                                   TEST_SNAP_ID, &ctx);
+  req->discard();
+}
+
+} // namespace object_map
+} // namespace librbd
+
diff --git a/src/test/librbd/object_map/test_mock_UnlockRequest.cc b/src/test/librbd/object_map/test_mock_UnlockRequest.cc
new file mode 100644 (file)
index 0000000..4cd2db4
--- /dev/null
@@ -0,0 +1,67 @@
+// -*- 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 "cls/lock/cls_lock_ops.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/object_map/UnlockRequest.h"
+
+// template definitions
+#include "librbd/object_map/UnlockRequest.cc"
+
+namespace librbd {
+namespace object_map {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+
+class TestMockObjectMapUnlockRequest : public TestMockFixture {
+public:
+  typedef UnlockRequest<MockImageCtx> MockUnlockRequest;
+
+  void expect_unlock(MockImageCtx &mock_image_ctx, int r) {
+    std::string oid(ObjectMap::object_map_name(mock_image_ctx.id, CEPH_NOSNAP));
+    EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                exec(oid, _, "lock", "unlock", _, _, _))
+                  .WillOnce(Return(r));
+  }
+};
+
+TEST_F(TestMockObjectMapUnlockRequest, Success) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockUnlockRequest *req = new MockUnlockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_unlock(mock_image_ctx, 0);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockObjectMapUnlockRequest, UnlockError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+
+  C_SaferCond ctx;
+  MockUnlockRequest *req = new MockUnlockRequest(mock_image_ctx, &ctx);
+
+  InSequence seq;
+  expect_unlock(mock_image_ctx, -ENOENT);
+  req->send();
+
+  ASSERT_EQ(0, ctx.wait());
+}
+
+} // namespace object_map
+} // namespace librbd
index 150e312f259b3972575293a432f63ec891bb3705..320fd1a76aa879ae6105492947b83e76b70e4233 100644 (file)
@@ -5,6 +5,7 @@
 #define CEPH_TEST_LIBRBD_TEST_MOCK_FIXTURE_H
 
 #include "test/librbd/test_fixture.h"
+#include "test/librbd/mock/MockImageCtx.h"
 #include "common/WorkQueue.h"
 #include <boost/shared_ptr.hpp>
 #include <gmock/gmock.h>
@@ -18,6 +19,10 @@ namespace librbd {
 class MockImageCtx;
 }
 
+ACTION_P(CopyInBufferlist, str) {
+  arg0->append(str);
+}
+
 ACTION_P2(CompleteContext, r, wq) {
   ContextWQ *context_wq = reinterpret_cast<ContextWQ *>(wq);
   if (context_wq != NULL) {
@@ -31,6 +36,12 @@ ACTION_P(DispatchContext, wq) {
   wq->queue(arg0, arg1);
 }
 
+ACTION_P3(FinishRequest, request, r, mock) {
+  librbd::MockImageCtx *mock_image_ctx =
+    reinterpret_cast<librbd::MockImageCtx *>(mock);
+  mock_image_ctx->image_ctx->op_work_queue->queue(request->on_finish, r);
+}
+
 ACTION_P(GetReference, ref_object) {
   ref_object->get();
 }