]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
tests: unit test cases for all available journal events
authorJason Dillaman <dillaman@redhat.com>
Thu, 17 Dec 2015 20:29:40 +0000 (15:29 -0500)
committerJason Dillaman <dillaman@redhat.com>
Fri, 15 Jan 2016 15:40:29 +0000 (10:40 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/Makefile-client.am
src/test/librbd/journal/test_Replay.cc
src/test/librbd/journal/test_mock_Replay.cc [new file with mode: 0644]
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/mock/MockOperations.h [new file with mode: 0644]

index 3b275d4fda4938d60bf819b3f13ac64683ac2358..72877d20a462568f332ece38838de046789af072 100644 (file)
@@ -365,6 +365,7 @@ unittest_librbd_SOURCES = \
        test/librbd/test_mock_Journal.cc \
        test/librbd/exclusive_lock/test_mock_AcquireRequest.cc \
        test/librbd/exclusive_lock/test_mock_ReleaseRequest.cc \
+       test/librbd/journal/test_mock_Replay.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 \
@@ -421,6 +422,7 @@ noinst_HEADERS += \
        test/librbd/mock/MockImageWatcher.h \
        test/librbd/mock/MockJournal.h \
        test/librbd/mock/MockObjectMap.h \
+       test/librbd/mock/MockOperations.h \
        test/librbd/mock/MockReadahead.h \
        test/librbd/object_map/mock/MockInvalidateRequest.h
 
index 076596c738b1b0d41e16dc5eb138fc8d99b0818c..f0f0409418394b272fa4b2e1788344ea3ca4dc80 100644 (file)
@@ -141,8 +141,8 @@ TEST_F(TestJournalReplay, AioFlushEvent) {
   librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
   {
     RWLock::RLocker owner_lock(ictx->owner_lock);
-    librbd::AioImageRequest::aio_write(ictx, aio_comp, 0, payload.size(),
-                                       payload.c_str(), 0);
+    librbd::AioImageRequest<>::aio_write(ictx, aio_comp, 0, payload.size(),
+                                         payload.c_str(), 0);
   }
   ictx->journal = journal;
 
diff --git a/src/test/librbd/journal/test_mock_Replay.cc b/src/test/librbd/journal/test_mock_Replay.cc
new file mode 100644 (file)
index 0000000..539a135
--- /dev/null
@@ -0,0 +1,452 @@
+// -*- 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 "librbd/AioImageRequest.h"
+#include "librbd/journal/Entries.h"
+#include "librbd/journal/Replay.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace librbd {
+
+template <>
+struct AioImageRequest<MockImageCtx> {
+  static AioImageRequest *s_instance;
+
+  MOCK_METHOD5(aio_write, void(AioCompletion *c, uint64_t off, size_t len,
+                               const char *buf, int op_flags));
+  static void aio_write(MockImageCtx *ictx, AioCompletion *c, uint64_t off,
+                        size_t len, const char *buf, int op_flags) {
+    assert(s_instance != nullptr);
+    s_instance->aio_write(c, off, len, buf, op_flags);
+  }
+
+  MOCK_METHOD3(aio_discard, void(AioCompletion *c, uint64_t off, uint64_t len));
+  static void aio_discard(MockImageCtx *ictx, AioCompletion *c, uint64_t off,
+                          uint64_t len) {
+    assert(s_instance != nullptr);
+    s_instance->aio_discard(c, off, len);
+  }
+
+  MOCK_METHOD1(aio_flush, void(AioCompletion *c));
+  static void aio_flush(MockImageCtx *ictx, AioCompletion *c) {
+    assert(s_instance != nullptr);
+    s_instance->aio_flush(c);
+  }
+
+  AioImageRequest() {
+    s_instance = this;
+  }
+};
+
+AioImageRequest<MockImageCtx> *AioImageRequest<MockImageCtx>::s_instance = nullptr;
+
+}
+
+// template definitions
+#include "librbd/journal/Replay.cc"
+template class librbd::journal::Replay<librbd::MockImageCtx>;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::WithArgs;
+
+MATCHER_P(CStrEq, str, "") {
+  return (strncmp(arg, str, strlen(str)) == 0);
+}
+
+namespace librbd {
+namespace journal {
+
+class TestMockJournalReplay : public TestMockFixture {
+public:
+  typedef AioImageRequest<MockImageCtx> MockAioImageRequest;
+  typedef Replay<MockImageCtx> MockJournalReplay;
+
+  void expect_aio_discard(MockAioImageRequest &mock_aio_image_request,
+                          AioCompletion **aio_comp, uint64_t off,
+                          uint64_t len) {
+    EXPECT_CALL(mock_aio_image_request, aio_discard(_, off, len))
+                  .WillOnce(SaveArg<0>(aio_comp));
+  }
+
+  void expect_aio_flush(MockAioImageRequest &mock_aio_image_request,
+                        AioCompletion **aio_comp) {
+    EXPECT_CALL(mock_aio_image_request, aio_flush(_))
+                  .WillOnce(SaveArg<0>(aio_comp));
+  }
+
+  void expect_aio_write(MockAioImageRequest &mock_aio_image_request,
+                        AioCompletion **aio_comp, uint64_t off,
+                        uint64_t len, const char *data) {
+    EXPECT_CALL(mock_aio_image_request,
+                aio_write(_, off, len, CStrEq(data), _))
+                  .WillOnce(SaveArg<0>(aio_comp));
+  }
+
+  void expect_flatten(MockImageCtx &mock_image_ctx, Context **on_finish) {
+    EXPECT_CALL(*mock_image_ctx.operations, flatten(_, _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_rename(MockImageCtx &mock_image_ctx, Context **on_finish,
+                     const char *image_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, rename(CStrEq(image_name), _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_resize(MockImageCtx &mock_image_ctx, Context **on_finish,
+                     uint64_t size) {
+    EXPECT_CALL(*mock_image_ctx.operations, resize(size, _, _))
+                  .WillOnce(SaveArg<2>(on_finish));
+  }
+
+  void expect_snap_create(MockImageCtx &mock_image_ctx,
+                          Context **on_finish, const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_create(CStrEq(snap_name), _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_snap_remove(MockImageCtx &mock_image_ctx,
+                          Context **on_finish, const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_remove(CStrEq(snap_name), _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_snap_rename(MockImageCtx &mock_image_ctx,
+                          Context **on_finish, uint64_t snap_id,
+                          const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_rename(snap_id, CStrEq(snap_name), _))
+                  .WillOnce(SaveArg<2>(on_finish));
+  }
+
+  void expect_snap_protect(MockImageCtx &mock_image_ctx,
+                           Context **on_finish, const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_protect(CStrEq(snap_name), _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_snap_unprotect(MockImageCtx &mock_image_ctx,
+                             Context **on_finish, const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_unprotect(CStrEq(snap_name), _))
+                  .WillOnce(SaveArg<1>(on_finish));
+  }
+
+  void expect_snap_rollback(MockImageCtx &mock_image_ctx,
+                            Context **on_finish, const char *snap_name) {
+    EXPECT_CALL(*mock_image_ctx.operations, snap_rollback(CStrEq(snap_name), _, _))
+                  .WillOnce(SaveArg<2>(on_finish));
+  }
+
+  void when_process(MockJournalReplay &mock_journal_replay,
+                    EventEntry &&event_entry, Context *on_safe) {
+    bufferlist bl;
+    ::encode(event_entry, bl);
+
+    bufferlist::iterator it = bl.begin();
+    mock_journal_replay.process(it, on_safe);
+  }
+
+  void when_complete(MockImageCtx &mock_image_ctx, AioCompletion *aio_comp,
+                     int r) {
+    aio_comp->get();
+    aio_comp->set_request_count(mock_image_ctx.cct, 1);
+    aio_comp->complete_request(mock_image_ctx.cct, r);
+  }
+
+  bufferlist to_bl(const std::string &str) {
+    bufferlist bl;
+    bl.append(str);
+    return bl;
+  }
+};
+
+TEST_F(TestMockJournalReplay, AioDiscard) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+  MockAioImageRequest mock_aio_image_request;
+
+  InSequence seq;
+  AioCompletion *aio_comp;
+  C_SaferCond on_safe;
+  expect_aio_discard(mock_aio_image_request, &aio_comp, 123, 456);
+  when_process(mock_journal_replay,
+               EventEntry{AioDiscardEvent(123, 456)},
+               &on_safe);
+
+  when_complete(mock_image_ctx, aio_comp, 0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, AioWrite) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+  MockAioImageRequest mock_aio_image_request;
+
+  InSequence seq;
+  AioCompletion *aio_comp;
+  C_SaferCond on_safe;
+  expect_aio_write(mock_aio_image_request, &aio_comp, 123, 456, "test");
+  when_process(mock_journal_replay,
+               EventEntry{AioWriteEvent(123, 456, to_bl("test"))},
+               &on_safe);
+
+  when_complete(mock_image_ctx, aio_comp, 0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, AioFlush) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+  MockAioImageRequest mock_aio_image_request;
+
+  InSequence seq;
+  AioCompletion *aio_comp;
+  C_SaferCond on_safe;
+  expect_aio_flush(mock_aio_image_request, &aio_comp);
+  when_process(mock_journal_replay, EventEntry{AioFlushEvent()}, &on_safe);
+
+  when_complete(mock_image_ctx, aio_comp, 0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, IOError) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+  MockAioImageRequest mock_aio_image_request;
+
+  InSequence seq;
+  AioCompletion *aio_comp;
+  C_SaferCond on_safe;
+  expect_aio_discard(mock_aio_image_request, &aio_comp, 123, 456);
+  when_process(mock_journal_replay,
+               EventEntry{AioDiscardEvent(123, 456)},
+               &on_safe);
+
+  when_complete(mock_image_ctx, aio_comp, -EINVAL);
+  ASSERT_EQ(-EINVAL, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SynchronousUntilFlush) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+  // TODO
+}
+
+TEST_F(TestMockJournalReplay, SnapCreateEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_create(mock_image_ctx, &on_finish, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{SnapCreateEvent(123, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SnapRemoveEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_remove(mock_image_ctx, &on_finish, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{SnapRemoveEvent(123, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SnapRenameEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_rename(mock_image_ctx, &on_finish, 234, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay,
+               EventEntry{SnapRenameEvent(123, 234, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SnapProtectEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_protect(mock_image_ctx, &on_finish, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{SnapProtectEvent(123, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SnapUnprotectEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_unprotect(mock_image_ctx, &on_finish, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{SnapUnprotectEvent(123, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, SnapRollbackEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_snap_rollback(mock_image_ctx, &on_finish, "snap");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{SnapRollbackEvent(123, "snap")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, RenameEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_rename(mock_image_ctx, &on_finish, "image");
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{RenameEvent(123, "image")},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, ResizeEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_resize(mock_image_ctx, &on_finish, 234);
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{ResizeEvent(123, 234)},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+TEST_F(TestMockJournalReplay, FlattenEvent) {
+  REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockJournalReplay mock_journal_replay(mock_image_ctx);
+
+  InSequence seq;
+  Context *on_finish;
+  expect_flatten(mock_image_ctx, &on_finish);
+
+  C_SaferCond on_safe;
+  when_process(mock_journal_replay, EventEntry{FlattenEvent(123)},
+               &on_safe);
+
+  on_finish->complete(0);
+  ASSERT_EQ(0, on_safe.wait());
+}
+
+} // namespace journal
+} // namespace librbd
index d75364138ae49c9581facd4cf1da65da13a3bbb9..1883819a6d851fabe2c5ce0d5ee8620076106e17 100644 (file)
@@ -10,6 +10,7 @@
 #include "test/librbd/mock/MockImageWatcher.h"
 #include "test/librbd/mock/MockJournal.h"
 #include "test/librbd/mock/MockObjectMap.h"
+#include "test/librbd/mock/MockOperations.h"
 #include "test/librbd/mock/MockReadahead.h"
 #include "common/RWLock.h"
 #include "common/WorkQueue.h"
@@ -46,7 +47,8 @@ struct MockImageCtx {
       layout(image_ctx.layout),
       aio_work_queue(new MockAioImageRequestWQ()),
       op_work_queue(new MockContextWQ()),
-      parent(NULL), image_watcher(NULL), object_map(NULL),
+      parent(NULL), operations(new MockOperations()),
+      image_watcher(NULL), object_map(NULL),
       exclusive_lock(NULL), journal(NULL),
       concurrent_management_ops(image_ctx.concurrent_management_ops),
       blacklist_on_break_lock(image_ctx.blacklist_on_break_lock),
@@ -72,6 +74,7 @@ struct MockImageCtx {
     image_ctx->md_ctx.aio_flush();
     image_ctx->data_ctx.aio_flush();
     image_ctx->op_work_queue->drain();
+    delete operations;
     delete image_watcher;
     delete op_work_queue;
     delete aio_work_queue;
@@ -161,6 +164,7 @@ struct MockImageCtx {
   MockReadahead readahead;
 
   MockImageCtx *parent;
+  MockOperations *operations;
 
   MockImageWatcher *image_watcher;
   MockObjectMap *object_map;
diff --git a/src/test/librbd/mock/MockOperations.h b/src/test/librbd/mock/MockOperations.h
new file mode 100644 (file)
index 0000000..b3dde8c
--- /dev/null
@@ -0,0 +1,34 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_LIBRBD_MOCK_OPERATIONS_H
+#define CEPH_TEST_LIBRBD_MOCK_OPERATIONS_H
+
+#include "include/int_types.h"
+#include "gmock/gmock.h"
+
+class Context;
+
+namespace librbd {
+
+struct MockOperations {
+  MOCK_METHOD2(flatten, void(ProgressContext &prog_ctx, Context *on_finish));
+  MOCK_METHOD2(rebuild_object_map, void(ProgressContext &prog_ctx,
+                                        Context *on_finish));
+  MOCK_METHOD2(rename, void(const char *dstname, Context *on_finish));
+  MOCK_METHOD3(resize, void(uint64_t size, ProgressContext &prog_ctx,
+                            Context *on_finish));
+  MOCK_METHOD2(snap_create, void(const char *snap_name, Context *on_finish));
+  MOCK_METHOD2(snap_remove, void(const char *snap_name, Context *on_finish));
+  MOCK_METHOD3(snap_rename, void(uint64_t src_snap_id, const char *snap_name,
+                                 Context *on_finish));
+  MOCK_METHOD3(snap_rollback, void(const char *snap_name,
+                                   ProgressContext &prog_ctx,
+                                   Context *on_finish));
+  MOCK_METHOD2(snap_protect, void(const char *snap_name, Context *on_finish));
+  MOCK_METHOD2(snap_unprotect, void(const char *snap_name, Context *on_finish));
+};
+
+} // namespace librbd
+
+#endif // CEPH_TEST_LIBRBD_MOCK_OPERATIONS_H