]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
test: test cases for rbd-mirror image sync point state machines
authorJason Dillaman <dillaman@redhat.com>
Fri, 11 Mar 2016 15:36:52 +0000 (10:36 -0500)
committerJason Dillaman <dillaman@redhat.com>
Sun, 13 Mar 2016 03:40:16 +0000 (22:40 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/Makefile-client.am
src/test/librbd/mock/MockOperations.h
src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc
src/test/rbd_mirror/image_sync/test_mock_SyncPointCreateRequest.cc [new file with mode: 0644]
src/test/rbd_mirror/image_sync/test_mock_SyncPointPruneRequest.cc [new file with mode: 0644]
src/test/rbd_mirror/mock/MockJournaler.cc [new file with mode: 0644]
src/test/rbd_mirror/mock/MockJournaler.h [new file with mode: 0644]

index f17dcdde4fba3ee1ac58eb3a6bee4a144d498712..861e271a1d2cba48f7c976bc423dfb45100d613c 100644 (file)
@@ -442,20 +442,24 @@ librbd_mirror_test_la_SOURCES = \
        test/rbd_mirror/test_ClusterWatcher.cc \
        test/rbd_mirror/test_PoolWatcher.cc \
        test/rbd_mirror/test_ImageReplayer.cc \
-       test/rbd_mirror/test_fixture.cc \
-       test/rbd_mirror/test_mock_fixture.cc
+       test/rbd_mirror/test_fixture.cc
 
 noinst_HEADERS += \
        test/rbd_mirror/test_fixture.h \
-       test/rbd_mirror/test_mock_fixture.h
+       test/rbd_mirror/test_mock_fixture.h \
+       test/rbd_mirror/mock/MockJournaler.h
 
 librbd_mirror_test_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 noinst_LTLIBRARIES += librbd_mirror_test.la
 
 unittest_rbd_mirror_SOURCES = \
        test/rbd_mirror/test_main.cc \
+       test/rbd_mirror/test_mock_fixture.cc \
        test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc \
-       test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc
+       test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc \
+       test/rbd_mirror/image_sync/test_mock_SyncPointCreateRequest.cc \
+       test/rbd_mirror/image_sync/test_mock_SyncPointPruneRequest.cc \
+       test/rbd_mirror/mock/MockJournaler.cc
 unittest_rbd_mirror_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 unittest_rbd_mirror_LDADD = \
        librbd_mirror_test.la \
index 0dabac184cb278105bc60d45fcba6015da20e73a..61501256501caff9a06da674377a2a1baeb5908e 100644 (file)
@@ -20,9 +20,11 @@ struct MockOperations {
   MOCK_METHOD4(execute_resize, void(uint64_t size, ProgressContext &prog_ctx,
                                     Context *on_finish,
                                     uint64_t journal_op_tid));
+  MOCK_METHOD2(snap_create, void(const char *snap_name, Context *on_finish));
   MOCK_METHOD3(execute_snap_create, void(const char *snap_name,
                                          Context *on_finish,
                                          uint64_t journal_op_tid));
+  MOCK_METHOD2(snap_remove, void(const char *snap_name, Context *on_finish));
   MOCK_METHOD2(execute_snap_remove, void(const char *snap_name,
                                          Context *on_finish));
   MOCK_METHOD3(execute_snap_rename, void(uint64_t src_snap_id,
index a8bee2ccdc8b8ef73e5542cefe388ff42d96374a..506eeddc90d8e71e84174874ca128b57b0c4accb 100644 (file)
@@ -8,40 +8,10 @@
 #include "librbd/Operations.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "test/librbd/mock/MockImageCtx.h"
+#include "test/rbd_mirror/mock/MockJournaler.h"
 #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
 #include "tools/rbd_mirror/Threads.h"
 
-namespace journal {
-
-struct MockJournaler {
-  static MockJournaler *s_instance;
-  static MockJournaler &get_instance() {
-    assert(s_instance != nullptr);
-    return *s_instance;
-  }
-
-  MockJournaler() {
-    s_instance = this;
-  }
-
-  MOCK_METHOD2(update_client, void(const bufferlist&, Context *on_safe));
-};
-
-MockJournaler *MockJournaler::s_instance = nullptr;
-
-} // namespace journal
-
-namespace librbd {
-namespace journal {
-
-template <>
-struct TypeTraits<MockImageCtx> {
-  typedef ::journal::MockJournaler Journaler;
-};
-
-} // namespace journal
-} // namespace librbd
-
 // template definitions
 #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc"
 template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::MockImageCtx>;
diff --git a/src/test/rbd_mirror/image_sync/test_mock_SyncPointCreateRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SyncPointCreateRequest.cc
new file mode 100644 (file)
index 0000000..e983402
--- /dev/null
@@ -0,0 +1,142 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/rbd_mirror/test_mock_fixture.h"
+#include "include/rbd/librbd.hpp"
+#include "librbd/journal/Types.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/rbd_mirror/mock/MockJournaler.h"
+#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
+
+// template definitions
+#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.cc"
+template class rbd::mirror::image_sync::SyncPointCreateRequest<librbd::MockImageCtx>;
+
+namespace rbd {
+namespace mirror {
+namespace image_sync {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::WithArg;
+
+class TestMockImageSyncSyncPointCreateRequest : public TestMockFixture {
+public:
+  typedef SyncPointCreateRequest<librbd::MockImageCtx> MockSyncPointCreateRequest;
+
+  virtual void SetUp() {
+    TestMockFixture::SetUp();
+
+    librbd::RBD rbd;
+    ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
+    ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
+  }
+
+  void expect_update_client(journal::MockJournaler &mock_journaler, int r) {
+    EXPECT_CALL(mock_journaler, update_client(_, _))
+      .WillOnce(WithArg<1>(CompleteContext(r)));
+  }
+
+  void expect_image_refresh(librbd::MockImageCtx &mock_remote_image_ctx, int r) {
+    EXPECT_CALL(*mock_remote_image_ctx.state, refresh(_))
+      .WillOnce(CompleteContext(r));
+  }
+
+  void expect_snap_create(librbd::MockImageCtx &mock_remote_image_ctx, int r) {
+    EXPECT_CALL(*mock_remote_image_ctx.operations, snap_create(_, _))
+      .WillOnce(WithArg<1>(CompleteContext(r)));
+  }
+
+  MockSyncPointCreateRequest *create_request(librbd::MockImageCtx &mock_remote_image_ctx,
+                                             journal::MockJournaler &mock_journaler,
+                                             Context *ctx) {
+    return new MockSyncPointCreateRequest(&mock_remote_image_ctx, "uuid",
+                                          &mock_journaler, &m_client_meta, ctx);
+  }
+
+  librbd::ImageCtx *m_remote_image_ctx;
+  librbd::journal::MirrorPeerClientMeta m_client_meta;
+};
+
+TEST_F(TestMockImageSyncSyncPointCreateRequest, Success) {
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_update_client(mock_journaler, 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_snap_create(mock_remote_image_ctx, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointCreateRequest *req = create_request(mock_remote_image_ctx,
+                                                   mock_journaler, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  ASSERT_EQ(1U, m_client_meta.sync_points.size());
+}
+
+TEST_F(TestMockImageSyncSyncPointCreateRequest, ResyncSuccess) {
+  m_client_meta.sync_points.emplace_front("start snap", "", boost::none);
+  auto sync_point = m_client_meta.sync_points.front();
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_update_client(mock_journaler, 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_snap_create(mock_remote_image_ctx, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointCreateRequest *req = create_request(mock_remote_image_ctx,
+                                                   mock_journaler, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  ASSERT_EQ(2U, m_client_meta.sync_points.size());
+  ASSERT_EQ(sync_point, m_client_meta.sync_points.front());
+  ASSERT_EQ("start snap", m_client_meta.sync_points.back().from_snap_name);
+}
+
+TEST_F(TestMockImageSyncSyncPointCreateRequest, SnapshotExists) {
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_update_client(mock_journaler, 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_snap_create(mock_remote_image_ctx, -EEXIST);
+  expect_update_client(mock_journaler, 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_snap_create(mock_remote_image_ctx, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointCreateRequest *req = create_request(mock_remote_image_ctx,
+                                                   mock_journaler, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  ASSERT_EQ(1U, m_client_meta.sync_points.size());
+}
+
+TEST_F(TestMockImageSyncSyncPointCreateRequest, ClientUpdateError) {
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_update_client(mock_journaler, -EINVAL);
+
+  C_SaferCond ctx;
+  MockSyncPointCreateRequest *req = create_request(mock_remote_image_ctx,
+                                                   mock_journaler, &ctx);
+  req->send();
+  ASSERT_EQ(-EINVAL, ctx.wait());
+
+  ASSERT_TRUE(m_client_meta.sync_points.empty());
+}
+
+} // namespace image_sync
+} // namespace mirror
+} // namespace rbd
diff --git a/src/test/rbd_mirror/image_sync/test_mock_SyncPointPruneRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SyncPointPruneRequest.cc
new file mode 100644 (file)
index 0000000..4558d6c
--- /dev/null
@@ -0,0 +1,219 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/rbd_mirror/test_mock_fixture.h"
+#include "include/rbd/librbd.hpp"
+#include "librbd/journal/Types.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/rbd_mirror/mock/MockJournaler.h"
+#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
+
+// template definitions
+#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.cc"
+template class rbd::mirror::image_sync::SyncPointPruneRequest<librbd::MockImageCtx>;
+
+namespace rbd {
+namespace mirror {
+namespace image_sync {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::StrEq;
+using ::testing::WithArg;
+
+class TestMockImageSyncSyncPointPruneRequest : public TestMockFixture {
+public:
+  typedef SyncPointPruneRequest<librbd::MockImageCtx> MockSyncPointPruneRequest;
+
+  virtual void SetUp() {
+    TestMockFixture::SetUp();
+
+    librbd::RBD rbd;
+    ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
+    ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
+  }
+
+  void expect_update_client(journal::MockJournaler &mock_journaler, int r) {
+    EXPECT_CALL(mock_journaler, update_client(_, _))
+      .WillOnce(WithArg<1>(CompleteContext(r)));
+  }
+
+  void expect_image_refresh(librbd::MockImageCtx &mock_remote_image_ctx, int r) {
+    EXPECT_CALL(*mock_remote_image_ctx.state, refresh(_))
+      .WillOnce(CompleteContext(r));
+  }
+
+  void expect_snap_remove(librbd::MockImageCtx &mock_remote_image_ctx,
+                          const std::string &snap_name, int r) {
+    EXPECT_CALL(*mock_remote_image_ctx.operations, snap_remove(StrEq(snap_name), _))
+      .WillOnce(WithArg<1>(CompleteContext(r)));
+  }
+
+  MockSyncPointPruneRequest *create_request(librbd::MockImageCtx &mock_remote_image_ctx,
+                                            journal::MockJournaler &mock_journaler,
+                                            bool sync_complete, Context *ctx) {
+    return new MockSyncPointPruneRequest(&mock_remote_image_ctx, sync_complete,
+                                         &mock_journaler, &m_client_meta, ctx);
+  }
+
+  librbd::ImageCtx *m_remote_image_ctx;
+  librbd::journal::MirrorPeerClientMeta m_client_meta;
+};
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressSuccess) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, false, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+  ASSERT_EQ(client_meta, m_client_meta);
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedSyncInProgressSuccess) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_snap_remove(mock_remote_image_ctx, "snap2", 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, false, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  client_meta.sync_points.pop_back();
+  ASSERT_EQ(client_meta, m_client_meta);
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncCompleteSuccess) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_snap_remove(mock_remote_image_ctx, "snap1", 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, true, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+  ASSERT_TRUE(m_client_meta.sync_points.empty());
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedSyncCompleteSuccess) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, true, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+  client_meta.sync_points.pop_front();
+  ASSERT_EQ(client_meta, m_client_meta);
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, RestartedCatchUpSyncCompleteSuccess) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap3", "snap2", boost::none);
+  client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_snap_remove(mock_remote_image_ctx, "snap1", 0);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, true, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+  client_meta.sync_points.pop_front();
+  ASSERT_EQ(client_meta, m_client_meta);
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, SnapshotDNE) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_snap_remove(mock_remote_image_ctx, "snap1", -ENOENT);
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, 0);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, true, &ctx);
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+  ASSERT_TRUE(m_client_meta.sync_points.empty());
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, ClientUpdateError) {
+  librbd::journal::MirrorPeerClientMeta client_meta;
+  client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+  client_meta.sync_points.emplace_front("snap1", boost::none);
+  m_client_meta = client_meta;
+
+  librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+  journal::MockJournaler mock_journaler;
+
+  InSequence seq;
+  expect_image_refresh(mock_remote_image_ctx, 0);
+  expect_update_client(mock_journaler, -EINVAL);
+
+  C_SaferCond ctx;
+  MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+                                                  mock_journaler, true, &ctx);
+  req->send();
+  ASSERT_EQ(-EINVAL, ctx.wait());
+
+  ASSERT_EQ(client_meta, m_client_meta);
+}
+
+} // namespace image_sync
+} // namespace mirror
+} // namespace rbd
diff --git a/src/test/rbd_mirror/mock/MockJournaler.cc b/src/test/rbd_mirror/mock/MockJournaler.cc
new file mode 100644 (file)
index 0000000..43f23e8
--- /dev/null
@@ -0,0 +1,10 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "MockJournaler.h"
+
+namespace journal {
+
+MockJournaler *MockJournaler::s_instance = nullptr;
+
+} // namespace journal
diff --git a/src/test/rbd_mirror/mock/MockJournaler.h b/src/test/rbd_mirror/mock/MockJournaler.h
new file mode 100644 (file)
index 0000000..5613eda
--- /dev/null
@@ -0,0 +1,42 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef TEST_RBD_MIRROR_MOCK_JOURNALER_H
+#define TEST_RBD_MIRROR_MOCK_JOURNALER_H
+
+#include <gmock/gmock.h>
+#include "librbd/Journal.h"
+
+namespace journal {
+
+struct MockJournaler {
+  static MockJournaler *s_instance;
+  static MockJournaler &get_instance() {
+    assert(s_instance != nullptr);
+    return *s_instance;
+  }
+
+  MockJournaler() {
+    s_instance = this;
+  }
+
+  MOCK_METHOD2(update_client, void(const bufferlist&, Context *on_safe));
+};
+
+} // namespace journal
+
+namespace librbd {
+
+struct MockImageCtx;
+
+namespace journal {
+
+template <>
+struct TypeTraits<MockImageCtx> {
+  typedef ::journal::MockJournaler Journaler;
+};
+
+} // namespace journal
+} // namespace librbd
+
+#endif // TEST_RBD_MIRROR_MOCK_JOURNALER_H