]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Added unit test suite for the Rados striping API.
authorSebastien Ponce <sebastien.ponce@cern.ch>
Thu, 6 Feb 2014 10:38:44 +0000 (11:38 +0100)
committerJosh Durgin <josh.durgin@inktank.com>
Sat, 7 Jun 2014 01:12:34 +0000 (18:12 -0700)
This includes tests for standard io and asynchronous io, similar to what is tested in the rados tests.
In addition, it includes in depth tests of the striping itself.

Signed-off-by: Sebastien Ponce <sebastien.ponce@cern.ch>
src/test/Makefile.am
src/test/librados/io.cc
src/test/libradosstriper/TestCase.cc [new file with mode: 0644]
src/test/libradosstriper/TestCase.h [new file with mode: 0644]
src/test/libradosstriper/aio.cc [new file with mode: 0644]
src/test/libradosstriper/io.cc [new file with mode: 0644]
src/test/libradosstriper/striping.cc [new file with mode: 0644]

index 79668ec6fec1ae2002d8437ba07ef754ec1403a1..3de19a4b555043642b9961f8af1dbf28632e5666 100644 (file)
@@ -629,6 +629,12 @@ noinst_LTLIBRARIES += libradostest.la
 libradostest_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 RADOS_TEST_LDADD = libradostest.la
 
+libradosstripertest_la_SOURCES = test/libradosstriper/TestCase.cc
+noinst_LTLIBRARIES += libradosstripertest.la
+libradosstripertest_la_LIBADD = $(RADOS_TEST_LDADD)
+libradosstripertest_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+RADOS_STRIPER_TEST_LDADD = libradosstripertest.la
+
 ceph_multi_stress_watch_SOURCES = test/multi_stress_watch.cc
 ceph_multi_stress_watch_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD)
 bin_DEBUGPROGRAMS += ceph_multi_stress_watch
@@ -775,6 +781,21 @@ ceph_test_rados_api_lock_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDAD
 ceph_test_rados_api_lock_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 bin_DEBUGPROGRAMS += ceph_test_rados_api_lock
 
+ceph_test_rados_striper_api_io_SOURCES = test/libradosstriper/io.cc
+ceph_test_rados_striper_api_io_LDADD = $(LIBRADOS) $(LIBRADOSSTRIPER) $(UNITTEST_LDADD) $(RADOS_STRIPER_TEST_LDADD)
+ceph_test_rados_striper_api_io_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+bin_DEBUGPROGRAMS += ceph_test_rados_striper_api_io
+
+ceph_test_rados_striper_api_aio_SOURCES = test/libradosstriper/aio.cc
+ceph_test_rados_striper_api_aio_LDADD = $(LIBRADOS) $(LIBRADOSSTRIPER) $(UNITTEST_LDADD) $(RADOS_STRIPER_TEST_LDADD)
+ceph_test_rados_striper_api_aio_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+bin_DEBUGPROGRAMS += ceph_test_rados_striper_api_aio
+
+ceph_test_rados_striper_api_striping_SOURCES = test/libradosstriper/striping.cc
+ceph_test_rados_striper_api_striping_LDADD = $(LIBRADOS) $(LIBRADOSSTRIPER) $(UNITTEST_LDADD) $(RADOS_STRIPER_TEST_LDADD)
+ceph_test_rados_striper_api_striping_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+bin_DEBUGPROGRAMS += ceph_test_rados_striper_api_striping
+
 ceph_test_libcephfs_SOURCES = \
        test/libcephfs/test.cc \
        test/libcephfs/readdir_r_cb.cc \
@@ -893,6 +914,7 @@ noinst_HEADERS += \
        test/kv_store_bench.h \
        test/librados/test.h \
        test/librados/TestCase.h \
+       test/libradosstriper/TestCase.h \
        test/ObjectMap/KeyValueDBMemory.h \
        test/omap_bench.h \
        test/osdc/FakeWriteback.h \
index 5daca3c15ec69b49a2dcfea102e2e5ed3c491672..ede81a326f5bc3e8dd5fc23f70e29549452b59be 100644 (file)
@@ -218,9 +218,9 @@ TEST_F(LibRadosIo, WriteFullRoundTrip) {
   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
   memset(buf2, 0xdd, sizeof(buf2));
   ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2)));
-  memset(buf3, 0xdd, sizeof(buf3));
+  memset(buf3, 0x00, sizeof(buf3));
   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
-  ASSERT_EQ(0, memcmp(buf2, buf2, sizeof(buf2)));
+  ASSERT_EQ(0, memcmp(buf2, buf3, sizeof(buf2)));
 }
 
 TEST_F(LibRadosIoPP, WriteFullRoundTripPP) {
diff --git a/src/test/libradosstriper/TestCase.cc b/src/test/libradosstriper/TestCase.cc
new file mode 100644 (file)
index 0000000..5e1d34a
--- /dev/null
@@ -0,0 +1,79 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <errno.h>
+#include "test/librados/test.h"
+#include "test/libradosstriper/TestCase.h"
+
+using namespace libradosstriper;
+
+std::string StriperTest::pool_name;
+rados_t StriperTest::s_cluster = NULL;
+
+void StriperTest::SetUpTestCase()
+{
+  pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &s_cluster));
+}
+
+void StriperTest::TearDownTestCase()
+{
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &s_cluster));
+}
+
+void StriperTest::SetUp()
+{
+  cluster = StriperTest::s_cluster;
+  ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx));
+  ASSERT_EQ(0, rados_striper_create(ioctx, &striper));
+}
+
+void StriperTest::TearDown()
+{
+  rados_striper_destroy(striper);
+  rados_ioctx_destroy(ioctx);
+}
+
+std::string StriperTestPP::pool_name;
+librados::Rados StriperTestPP::s_cluster;
+
+void StriperTestPP::SetUpTestCase()
+{
+  pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void StriperTestPP::TearDownTestCase()
+{
+  ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void StriperTestPP::SetUp()
+{
+  ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+  ASSERT_EQ(0, RadosStriper::striper_create(ioctx, &striper));
+}
+
+// this is pure copy and paste from previous class
+// but for the inheritance from TestWithParam
+// with gtest >= 1.6, we couldd avoid this by using
+// inheritance from WithParamInterface
+std::string StriperTestParam::pool_name;
+librados::Rados StriperTestParam::s_cluster;
+
+void StriperTestParam::SetUpTestCase()
+{
+  pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void StriperTestParam::TearDownTestCase()
+{
+  ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void StriperTestParam::SetUp()
+{
+  ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+  ASSERT_EQ(0, RadosStriper::striper_create(ioctx, &striper));
+}
diff --git a/src/test/libradosstriper/TestCase.h b/src/test/libradosstriper/TestCase.h
new file mode 100644 (file)
index 0000000..cfa9f72
--- /dev/null
@@ -0,0 +1,82 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_RADOS_TESTCASE_H
+#define CEPH_TEST_RADOS_TESTCASE_H
+
+#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
+#include "include/radosstriper/libradosstriper.h"
+#include "include/radosstriper/libradosstriper.hpp"
+#include "gtest/gtest.h"
+
+#include <string>
+
+/**
+ * These test cases create a temporary pool that lives as long as the
+ * test case.  Each test within a test case gets a new ioctx and striper
+ * set to a unique namespace within the pool.
+ *
+ * Since pool creation and deletion is slow, this allows many tests to
+ * run faster.
+ */
+class StriperTest : public ::testing::Test {
+public:
+  StriperTest() {}
+  virtual ~StriperTest() {}
+protected:
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+  static rados_t s_cluster;
+  static std::string pool_name;
+
+  virtual void SetUp();
+  virtual void TearDown();
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  rados_striper_t striper;
+};
+
+class StriperTestPP : public ::testing::Test {
+public:
+  StriperTestPP() : cluster(s_cluster) {}
+  virtual ~StriperTestPP() {}
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+protected:
+  static librados::Rados s_cluster;
+  static std::string pool_name;
+
+  virtual void SetUp();
+  librados::Rados &cluster;
+  librados::IoCtx ioctx;
+  libradosstriper::RadosStriper striper;
+};
+
+struct TestData {
+  uint32_t stripe_unit;
+  uint32_t stripe_count;
+  uint32_t object_size;
+  size_t size;
+};
+// this is pure copy and paste from previous class
+// but for the inheritance from TestWithParam
+// with gtest >= 1.6, we couldd avoid this by using
+// inheritance from WithParamInterface
+class StriperTestParam : public ::testing::TestWithParam<TestData> {
+public:
+  StriperTestParam() : cluster(s_cluster) {}
+  virtual ~StriperTestParam() {}
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+protected:
+  static librados::Rados s_cluster;
+  static std::string pool_name;
+
+  virtual void SetUp();
+  librados::Rados &cluster;
+  librados::IoCtx ioctx;
+  libradosstriper::RadosStriper striper;
+};
+
+#endif
diff --git a/src/test/libradosstriper/aio.cc b/src/test/libradosstriper/aio.cc
new file mode 100644 (file)
index 0000000..873c803
--- /dev/null
@@ -0,0 +1,542 @@
+#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
+#include "include/radosstriper/libradosstriper.h"
+#include "include/radosstriper/libradosstriper.hpp"
+#include "test/librados/test.h"
+#include "test/libradosstriper/TestCase.h"
+
+#include <semaphore.h>
+#include <errno.h>
+
+using namespace librados;
+using namespace libradosstriper;
+using std::pair;
+
+class AioTestData
+{
+public:
+  AioTestData() : m_complete(false), m_safe(false) {
+    sem_init(&m_sem, 0, 0);
+  }
+
+  ~AioTestData() {
+    sem_destroy(&m_sem);
+  }
+
+  sem_t m_sem;
+  bool m_complete;
+  bool m_safe;
+};
+
+void set_completion_complete(rados_completion_t cb, void *arg)
+{
+  AioTestData *test = static_cast<AioTestData*>(arg);
+  test->m_complete = true;
+  sem_post(&test->m_sem);
+}
+
+void set_completion_safe(rados_completion_t cb, void *arg)
+{
+  AioTestData *test = static_cast<AioTestData*>(arg);
+  test->m_safe = true;
+  sem_post(&test->m_sem);
+}
+
+TEST_F(StriperTest, SimpleWrite) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "StriperTest", my_completion, buf, sizeof(buf), 0));
+  TestAlarm alarm;
+  sem_wait(&test_data.m_sem);
+  sem_wait(&test_data.m_sem);
+  rados_aio_release(my_completion);
+}
+
+TEST_F(StriperTestPP, SimpleWritePP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("SimpleWritePP", my_completion, bl1, sizeof(buf), 0));
+  TestAlarm alarm;
+  sem_wait(&test_data.m_sem);
+  sem_wait(&test_data.m_sem);
+  my_completion->release();
+}
+
+TEST_F(StriperTest, WaitForSafe) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "WaitForSafe", my_completion, buf, sizeof(buf), 0));
+  TestAlarm alarm;
+  rados_aio_wait_for_safe(my_completion);
+  rados_aio_release(my_completion);
+}
+
+TEST_F(StriperTestPP, WaitForSafePP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("WaitForSafePP", my_completion, bl1, sizeof(buf), 0));
+  TestAlarm alarm;
+  my_completion->wait_for_safe();
+  my_completion->release();
+}
+
+TEST_F(StriperTest, RoundTrip) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "RoundTrip", my_completion, buf, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  char buf2[128];
+  memset(buf2, 0, sizeof(buf2));
+  rados_completion_t my_completion2;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "RoundTrip", my_completion2, buf2, sizeof(buf2), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion2);
+  }
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+}
+
+TEST_F(StriperTest, RoundTrip2) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "RoundTrip2", my_completion, buf, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  char buf2[128];
+  memset(buf2, 0, sizeof(buf2));
+  rados_completion_t my_completion2;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "RoundTrip2", my_completion2, buf2, sizeof(buf2), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_safe(my_completion2);
+  }
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+}
+
+TEST_F(StriperTestPP, RoundTripPP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("RoundTripPP", my_completion, bl1, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  bufferlist bl2;
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("RoundTripPP", my_completion2, &bl2, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_complete();
+  }
+  ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+  my_completion->release();
+  my_completion2->release();
+}
+
+TEST_F(StriperTestPP, RoundTripPP2) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("RoundTripPP2", my_completion, bl1, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  bufferlist bl2;
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("RoundTripPP2", my_completion2, &bl2, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_safe();
+  }
+  ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+  my_completion->release();
+  my_completion2->release();
+}
+
+TEST_F(StriperTest, IsComplete) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "IsComplete", my_completion, buf, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  char buf2[128];
+  memset(buf2, 0, sizeof(buf2));
+  rados_completion_t my_completion2;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "IsComplete", my_completion2, buf2, sizeof(buf2), 0));
+  {
+    TestAlarm alarm;
+    // Busy-wait until the AIO completes.
+    // Normally we wouldn't do this, but we want to test rados_aio_is_complete.
+    while (true) {
+      int is_complete = rados_aio_is_complete(my_completion2);
+      if (is_complete)
+       break;
+    }
+  }
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+}
+
+TEST_F(StriperTestPP, IsCompletePP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("IsCompletePP", my_completion, bl1, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    sem_wait(&test_data.m_sem);
+    sem_wait(&test_data.m_sem);
+  }
+  bufferlist bl2;
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("IsCompletePP", my_completion2, &bl2, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    // Busy-wait until the AIO completes.
+    // Normally we wouldn't do this, but we want to test rados_aio_is_complete.
+    while (true) {
+      int is_complete = my_completion2->is_complete();
+      if (is_complete)
+       break;
+    }
+  }
+  ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+  my_completion->release();
+  my_completion2->release();
+}
+
+TEST_F(StriperTest, IsSafe) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "IsSafe", my_completion, buf, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    // Busy-wait until the AIO completes.
+    // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
+    while (true) {
+      int is_safe = rados_aio_is_safe(my_completion);
+      if (is_safe)
+       break;
+    }
+  }
+  char buf2[128];
+  memset(buf2, 0, sizeof(buf2));
+  rados_completion_t my_completion2;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "IsSafe", my_completion2, buf2, sizeof(buf2), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion2);
+  }
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+}
+
+TEST_F(StriperTestPP, IsSafePP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("IsSafePP", my_completion, bl1, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    // Busy-wait until the AIO completes.
+    // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
+    while (true) {
+      int is_safe = my_completion->is_safe();
+      if (is_safe)
+       break;
+    }
+  }
+  bufferlist bl2;
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("IsSafePP", my_completion2, &bl2, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_complete();
+  }
+  ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+  my_completion->release();
+  my_completion2->release();
+}
+
+TEST_F(StriperTest, RoundTripAppend) {
+  AioTestData test_data;
+  rados_completion_t my_completion, my_completion2, my_completion3;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_append(striper, "RoundTripAppend", my_completion, buf, sizeof(buf)));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion);
+  }
+  char buf2[128];
+  memset(buf2, 0xdd, sizeof(buf2));
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_append(striper, "RoundTripAppend", my_completion2, buf2, sizeof(buf)));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion2);
+  }
+  char buf3[sizeof(buf) + sizeof(buf2)];
+  memset(buf3, 0, sizeof(buf3));
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "RoundTripAppend", my_completion3, buf3, sizeof(buf3), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion3);
+  }
+  ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), rados_aio_get_return_value(my_completion3));
+  ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf)));
+  ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+  rados_aio_release(my_completion3);
+}
+
+TEST_F(StriperTestPP, RoundTripAppendPP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_append("RoundTripAppendPP", my_completion, bl1, sizeof(buf)));
+  {
+    TestAlarm alarm;
+    my_completion->wait_for_complete();
+  }
+  char buf2[128];
+  memset(buf2, 0xdd, sizeof(buf2));
+  bufferlist bl2;
+  bl2.append(buf2, sizeof(buf2));
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_append("RoundTripAppendPP", my_completion2, bl2, sizeof(buf2)));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_complete();
+  }
+  bufferlist bl3;
+  AioCompletion *my_completion3 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("RoundTripAppendPP", my_completion3, &bl3, 2 * sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion3->wait_for_complete();
+  }
+  ASSERT_EQ(sizeof(buf) + sizeof(buf2), my_completion3->get_return_value());
+  ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+  ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2)));
+  my_completion->release();
+  my_completion2->release();
+  my_completion3->release();
+}
+
+TEST_F(StriperTest, Flush) {
+  AioTestData test_data;
+  rados_completion_t my_completion;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xee, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "Flush", my_completion, buf, sizeof(buf), 0));
+  rados_striper_aio_flush(striper);
+  char buf2[128];
+  memset(buf2, 0, sizeof(buf2));
+  rados_completion_t my_completion2;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "Flush", my_completion2, buf2, sizeof(buf2), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion2);
+  }
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+}
+
+TEST_F(StriperTestPP, FlushPP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xee, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("FlushPP", my_completion, bl1, sizeof(buf), 0));
+  striper.aio_flush();
+  bufferlist bl2;
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("FlushPP", my_completion2, &bl2, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_complete();
+  }
+  ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+  my_completion->release();
+  my_completion2->release();
+}
+
+TEST_F(StriperTest, RoundTripWriteFull) {
+  AioTestData test_data;
+  rados_completion_t my_completion, my_completion2, my_completion3;
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion));
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_aio_write(striper, "RoundTripWriteFull", my_completion, buf, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion);
+  }
+  char buf2[64];
+  memset(buf2, 0xdd, sizeof(buf2));
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2));
+  ASSERT_EQ(0, rados_striper_aio_write_full(striper, "RoundTripWriteFull", my_completion2, buf2, sizeof(buf2)));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion2);
+  }
+  char buf3[sizeof(buf) + sizeof(buf2)];
+  memset(buf3, 0, sizeof(buf3));
+  ASSERT_EQ(0, rados_aio_create_completion
+            ((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3));
+  ASSERT_EQ(0, rados_striper_aio_read(striper, "RoundTripWriteFull", my_completion3, buf3, sizeof(buf3), 0));
+  {
+    TestAlarm alarm;
+    rados_aio_wait_for_complete(my_completion3);
+  }
+  ASSERT_EQ(sizeof(buf2), rados_aio_get_return_value(my_completion3));
+  ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
+  rados_aio_release(my_completion);
+  rados_aio_release(my_completion2);
+  rados_aio_release(my_completion3);
+}
+
+TEST_F(StriperTestPP, RoundTripWriteFullPP) {
+  AioTestData test_data;
+  AioCompletion *my_completion = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.aio_write("RoundTripWriteFullPP", my_completion, bl1, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion->wait_for_complete();
+  }
+  char buf2[64];
+  memset(buf2, 0xdd, sizeof(buf2));
+  bufferlist bl2;
+  bl2.append(buf2, sizeof(buf2));
+  AioCompletion *my_completion2 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_write_full("RoundTripWriteFullPP", my_completion2, bl2));
+  {
+    TestAlarm alarm;
+    my_completion2->wait_for_complete();
+  }
+  bufferlist bl3;
+  AioCompletion *my_completion3 = librados::Rados::aio_create_completion
+    ((void*)&test_data, set_completion_complete, set_completion_safe);
+  ASSERT_EQ(0, striper.aio_read("RoundTripWriteFullPP", my_completion3, &bl3, sizeof(buf), 0));
+  {
+    TestAlarm alarm;
+    my_completion3->wait_for_complete();
+  }
+  ASSERT_EQ(sizeof(buf2), my_completion3->get_return_value());
+  ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+  my_completion->release();
+  my_completion2->release();
+  my_completion3->release();
+}
diff --git a/src/test/libradosstriper/io.cc b/src/test/libradosstriper/io.cc
new file mode 100644 (file)
index 0000000..9ea7bfc
--- /dev/null
@@ -0,0 +1,392 @@
+#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
+#include "include/radosstriper/libradosstriper.h"
+#include "include/radosstriper/libradosstriper.hpp"
+#include "test/librados/test.h"
+#include "test/libradosstriper/TestCase.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include "gtest/gtest.h"
+
+using namespace librados;
+using namespace libradosstriper;
+using std::string;
+
+TEST_F(StriperTest, SimpleWrite) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "SimpleWrite", buf, sizeof(buf), 0));
+}
+
+TEST_F(StriperTestPP, SimpleWritePP) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("SimpleWritePP", bl, sizeof(buf), 0));
+}
+
+TEST_F(StriperTest, Stat) {
+  uint64_t psize;
+  time_t pmtime;
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "Stat", buf, sizeof(buf), 0));
+  ASSERT_EQ(0, rados_striper_stat(striper, "Stat", &psize, &pmtime));
+  ASSERT_EQ(psize, sizeof(buf));
+  ASSERT_EQ(-ENOENT, rados_striper_stat(striper, "nonexistent", &psize, &pmtime));
+}
+
+TEST_F(StriperTestPP, StatPP) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("Statpp", bl, sizeof(buf), 0));
+  uint64_t psize;
+  time_t pmtime;
+  ASSERT_EQ(0, striper.stat("Statpp", &psize, &pmtime));
+  ASSERT_EQ(psize, sizeof(buf));
+  ASSERT_EQ(-ENOENT, striper.stat("nonexistent", &psize, &pmtime));
+}
+
+TEST_F(StriperTest, RoundTrip) {
+  char buf[128];
+  char buf2[sizeof(buf)];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "RoundTrip", buf, sizeof(buf), 0));
+  memset(buf2, 0, sizeof(buf2));
+  ASSERT_EQ((int)sizeof(buf2), rados_striper_read(striper, "RoundTrip", buf2, sizeof(buf2), 0));
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+}
+
+TEST_F(StriperTestPP, RoundTripPP) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("RoundTripPP", bl, sizeof(buf), 0));
+  bufferlist cl;
+  ASSERT_EQ((int)sizeof(buf), striper.read("RoundTripPP", &cl, sizeof(buf), 0));
+  ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
+}
+
+TEST_F(StriperTest, OverlappingWriteRoundTrip) {
+  char buf[128];
+  char buf2[64];
+  char buf3[sizeof(buf)];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "OverlappingWriteRoundTrip", buf, sizeof(buf), 0));
+  memset(buf2, 0xdd, sizeof(buf2));
+  ASSERT_EQ(0, rados_striper_write(striper, "OverlappingWriteRoundTrip", buf2, sizeof(buf2), 0));
+  memset(buf3, 0, sizeof(buf3));
+  ASSERT_EQ((int)sizeof(buf3), rados_striper_read(striper, "OverlappingWriteRoundTrip", buf3, sizeof(buf3), 0));
+  ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
+  ASSERT_EQ(0, memcmp(buf3 + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
+}
+
+TEST_F(StriperTestPP, OverlappingWriteRoundTripPP) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("OverlappingWriteRoundTripPP", bl1, sizeof(buf), 0));
+  char buf2[64];
+  memset(buf2, 0xdd, sizeof(buf2));
+  bufferlist bl2;
+  bl2.append(buf2, sizeof(buf2));
+  ASSERT_EQ(0, striper.write("OverlappingWriteRoundTripPP", bl2, sizeof(buf2), 0));
+  bufferlist bl3;
+  ASSERT_EQ((int)sizeof(buf), striper.read("OverlappingWriteRoundTripPP", &bl3, sizeof(buf), 0));
+  ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+  ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
+}
+
+TEST_F(StriperTest, SparseWriteRoundTrip) {
+  char buf[128];
+  char buf2[2*sizeof(buf)];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "SparseWriteRoundTrip", buf, sizeof(buf), 0));
+  ASSERT_EQ(0, rados_striper_write(striper, "SparseWriteRoundTrip", buf, sizeof(buf), 1000000000));
+  memset(buf2, 0xaa, sizeof(buf2));
+  ASSERT_EQ((int)sizeof(buf2), rados_striper_read(striper, "SparseWriteRoundTrip", buf2, sizeof(buf2), 0));
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  memset(buf, 0, sizeof(buf));
+  ASSERT_EQ(0, memcmp(buf, buf2+sizeof(buf), sizeof(buf)));
+  memset(buf2, 0xaa, sizeof(buf2));
+  ASSERT_EQ((int)sizeof(buf), rados_striper_read(striper, "SparseWriteRoundTrip", buf2, sizeof(buf), 500000000));
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+}
+
+TEST_F(StriperTestPP, SparseWriteRoundTripPP) {
+  char buf[128];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("SparseWriteRoundTripPP", bl1, sizeof(buf), 0));
+  ASSERT_EQ(0, striper.write("SparseWriteRoundTripPP", bl1, sizeof(buf), 1000000000));
+  bufferlist bl2;
+  ASSERT_EQ((int)(2*sizeof(buf)), striper.read("SparseWriteRoundTripPP", &bl2, 2*sizeof(buf), 0));
+  ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
+  memset(buf, 0, sizeof(buf));
+  ASSERT_EQ(0, memcmp(bl2.c_str()+sizeof(buf), buf, sizeof(buf)));
+  ASSERT_EQ((int)sizeof(buf), striper.read("SparseWriteRoundTripPP", &bl2, sizeof(buf), 500000000));
+  ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
+}
+
+TEST_F(StriperTest, WriteFullRoundTrip) {
+  char buf[128];
+  char buf2[64];
+  char buf3[128];
+  memset(buf, 0xcc, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "WriteFullRoundTrip", buf, sizeof(buf), 0));
+  memset(buf2, 0xdd, sizeof(buf2));
+  ASSERT_EQ(0, rados_striper_write_full(striper, "WriteFullRoundTrip", buf2, sizeof(buf2)));
+  memset(buf3, 0x00, sizeof(buf3));
+  ASSERT_EQ((int)sizeof(buf2), rados_striper_read(striper, "WriteFullRoundTrip", buf3, sizeof(buf3), 0));
+  ASSERT_EQ(0, memcmp(buf2, buf3, sizeof(buf2)));
+}
+
+TEST_F(StriperTestPP, WriteFullRoundTripPP) {
+  char buf[128];
+  char buf2[64];
+  memset(buf, 0xcc, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("WriteFullRoundTripPP", bl1, sizeof(buf), 0));
+  memset(buf2, 0xdd, sizeof(buf2));
+  bufferlist bl2;
+  bl2.append(buf2, sizeof(buf2));
+  ASSERT_EQ(0, striper.write_full("WriteFullRoundTripPP", bl2));
+  bufferlist bl3;
+  ASSERT_EQ((int)sizeof(buf2), striper.read("WriteFullRoundTripPP", &bl3, sizeof(buf), 0));
+  ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+}
+
+TEST_F(StriperTest, AppendRoundTrip) {
+  char buf[64];
+  char buf2[64];
+  char buf3[sizeof(buf) + sizeof(buf2)];
+  memset(buf, 0xde, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_append(striper, "AppendRoundTrip", buf, sizeof(buf)));
+  memset(buf2, 0xad, sizeof(buf2));
+  ASSERT_EQ(0, rados_striper_append(striper, "AppendRoundTrip", buf2, sizeof(buf2)));
+  memset(buf3, 0, sizeof(buf3));
+  ASSERT_EQ((int)sizeof(buf3), rados_striper_read(striper, "AppendRoundTrip", buf3, sizeof(buf3), 0));
+  ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf)));
+  ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2)));
+}
+
+TEST_F(StriperTestPP, AppendRoundTripPP) {
+  char buf[64];
+  char buf2[64];
+  memset(buf, 0xde, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.append("AppendRoundTripPP", bl1, sizeof(buf)));
+  memset(buf2, 0xad, sizeof(buf2));
+  bufferlist bl2;
+  bl2.append(buf2, sizeof(buf2));
+  ASSERT_EQ(0, striper.append("AppendRoundTripPP", bl2, sizeof(buf2)));
+  bufferlist bl3;
+  ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)),
+           striper.read("AppendRoundTripPP", &bl3, (sizeof(buf) + sizeof(buf2)), 0));
+  const char *bl3_str = bl3.c_str();
+  ASSERT_EQ(0, memcmp(bl3_str, buf, sizeof(buf)));
+  ASSERT_EQ(0, memcmp(bl3_str + sizeof(buf), buf2, sizeof(buf2)));
+}
+
+TEST_F(StriperTest, TruncTest) {
+  char buf[128];
+  char buf2[sizeof(buf)];
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_append(striper, "TruncTest", buf, sizeof(buf)));
+  ASSERT_EQ(0, rados_striper_trunc(striper, "TruncTest", sizeof(buf) / 2));
+  memset(buf2, 0, sizeof(buf2));
+  ASSERT_EQ((int)(sizeof(buf)/2), rados_striper_read(striper, "TruncTest", buf2, sizeof(buf2), 0));
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)/2));
+}
+
+TEST_F(StriperTestPP, TruncTestPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.append("TruncTestPP", bl, sizeof(buf)));
+  ASSERT_EQ(0, striper.trunc("TruncTestPP", sizeof(buf) / 2));
+  bufferlist bl2;
+  ASSERT_EQ((int)(sizeof(buf)/2), striper.read("TruncTestPP", &bl2, sizeof(buf), 0));
+  ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)/2));
+}
+
+TEST_F(StriperTest, TruncTestGrow) {
+  char buf[128];
+  char buf2[sizeof(buf)*2];
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_append(striper, "TruncTestGrow", buf, sizeof(buf)));
+  ASSERT_EQ(0, rados_striper_trunc(striper, "TruncTestGrow", sizeof(buf2)));
+  memset(buf2, 0xbb, sizeof(buf2));
+  ASSERT_EQ((int)sizeof(buf2), rados_striper_read(striper, "TruncTestGrow", buf2, sizeof(buf2), 0));
+  ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+  memset(buf, 0x00, sizeof(buf));
+  ASSERT_EQ(0, memcmp(buf, buf2+sizeof(buf), sizeof(buf)));
+}
+
+TEST_F(StriperTestPP, TruncTestGrowPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.append("TruncTestGrowPP", bl, sizeof(buf)));
+  ASSERT_EQ(0, striper.trunc("TruncTestGrowPP", sizeof(buf) * 2));
+  bufferlist bl2;
+  ASSERT_EQ(sizeof(buf)*2, striper.read("TruncTestGrowPP", &bl2, sizeof(buf)*2, 0));
+  ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
+  memset(buf, 0x00, sizeof(buf));
+  ASSERT_EQ(0, memcmp(bl2.c_str()+sizeof(buf), buf, sizeof(buf)));
+}
+
+TEST_F(StriperTest, RemoveTest) {
+  char buf[128];
+  char buf2[sizeof(buf)];
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "RemoveTest", buf, sizeof(buf), 0));
+  ASSERT_EQ(0, rados_striper_remove(striper, "RemoveTest"));
+  ASSERT_EQ(-ENOENT, rados_striper_read(striper, "RemoveTest", buf2, sizeof(buf2), 0));
+}
+
+TEST_F(StriperTestPP, RemoveTestPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl;
+  bl.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("RemoveTestPP", bl, sizeof(buf), 0));
+  ASSERT_EQ(0, striper.remove("RemoveTestPP"));
+  bufferlist bl2;
+  ASSERT_EQ(-ENOENT, striper.read("RemoveTestPP", &bl2, sizeof(buf), 0));
+}
+
+TEST_F(StriperTest, XattrsRoundTrip) {
+  char buf[128];
+  char attr1_buf[] = "foo bar baz";
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "XattrsRoundTrip", buf, sizeof(buf), 0));
+  ASSERT_EQ(-ENODATA, rados_striper_getxattr(striper, "XattrsRoundTrip", "attr1", buf, sizeof(buf)));
+  ASSERT_EQ(0, rados_striper_setxattr(striper, "XattrsRoundTrip", "attr1", attr1_buf, sizeof(attr1_buf)));
+  ASSERT_EQ((int)sizeof(attr1_buf), rados_striper_getxattr(striper, "XattrsRoundTrip", "attr1", buf, sizeof(buf)));
+  ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
+}
+
+TEST_F(StriperTestPP, XattrsRoundTripPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("XattrsRoundTripPP", bl1, sizeof(buf), 0));
+  char attr1_buf[] = "foo bar baz";
+  bufferlist bl2;
+  ASSERT_EQ(-ENODATA, striper.getxattr("XattrsRoundTripPP", "attr1", bl2));
+  bufferlist bl3;
+  bl3.append(attr1_buf, sizeof(attr1_buf));
+  ASSERT_EQ(0, striper.setxattr("XattrsRoundTripPP", "attr1", bl3));
+  bufferlist bl4;
+  ASSERT_EQ((int)sizeof(attr1_buf), striper.getxattr("XattrsRoundTripPP", "attr1", bl4));
+  ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
+}
+
+TEST_F(StriperTest, RmXattr) {
+  char buf[128];
+  char attr1_buf[] = "foo bar baz";
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "RmXattr", buf, sizeof(buf), 0));
+  ASSERT_EQ(0, rados_striper_setxattr(striper, "RmXattr", "attr1", attr1_buf, sizeof(attr1_buf)));
+  ASSERT_EQ(0, rados_striper_rmxattr(striper, "RmXattr", "attr1"));
+  ASSERT_EQ(-ENODATA, rados_striper_getxattr(striper, "RmXattr", "attr1", buf, sizeof(buf)));
+}
+
+TEST_F(StriperTestPP, RmXattrPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("RmXattrPP", bl1, sizeof(buf), 0));
+  char attr1_buf[] = "foo bar baz";
+  bufferlist bl2;
+  bl2.append(attr1_buf, sizeof(attr1_buf));
+  ASSERT_EQ(0, striper.setxattr("RmXattrPP", "attr1", bl2));
+  ASSERT_EQ(0, striper.rmxattr("RmXattrPP", "attr1"));
+  bufferlist bl3;
+  ASSERT_EQ(-ENODATA, striper.getxattr("RmXattrPP", "attr1", bl3));
+}
+
+TEST_F(StriperTest, XattrIter) {
+  char buf[128];
+  char attr1_buf[] = "foo bar baz";
+  char attr2_buf[256];
+  for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
+    attr2_buf[j] = j % 0xff;
+  }
+  memset(buf, 0xaa, sizeof(buf));
+  ASSERT_EQ(0, rados_striper_write(striper, "RmXattr", buf, sizeof(buf), 0));
+  ASSERT_EQ(0, rados_striper_setxattr(striper, "RmXattr", "attr1", attr1_buf, sizeof(attr1_buf)));
+  ASSERT_EQ(0, rados_striper_setxattr(striper, "RmXattr", "attr2", attr2_buf, sizeof(attr2_buf)));
+  rados_xattrs_iter_t iter;
+  ASSERT_EQ(0, rados_striper_getxattrs(striper, "RmXattr", &iter));
+  int num_seen = 0;
+  while (true) {
+    const char *name;
+    const char *val;
+    size_t len;
+    ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len));
+    if (name == NULL) {
+      break;
+    }
+    ASSERT_LT(num_seen, 2) << "Extra attribute : " << name;
+    if ((strcmp(name, "attr1") == 0) && (memcmp(val, attr1_buf, len) == 0)) {
+      num_seen++;
+      continue;
+    }
+    else if ((strcmp(name, "attr2") == 0) && (memcmp(val, attr2_buf, len) == 0)) {
+      num_seen++;
+      continue;
+    }
+    else {
+      ASSERT_EQ(0, 1) << "Unexpected attribute : " << name;;
+    }
+  }
+  rados_getxattrs_end(iter);
+}
+
+TEST_F(StriperTestPP, XattrListPP) {
+  char buf[128];
+  memset(buf, 0xaa, sizeof(buf));
+  bufferlist bl1;
+  bl1.append(buf, sizeof(buf));
+  ASSERT_EQ(0, striper.write("RmXattrPP", bl1, sizeof(buf), 0));
+  char attr1_buf[] = "foo bar baz";
+  bufferlist bl2;
+  bl2.append(attr1_buf, sizeof(attr1_buf));
+  ASSERT_EQ(0, striper.setxattr("RmXattrPP", "attr1", bl2));
+  char attr2_buf[256];
+  for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
+    attr2_buf[j] = j % 0xff;
+  }
+  bufferlist bl3;
+  bl3.append(attr2_buf, sizeof(attr2_buf));
+  ASSERT_EQ(0, striper.setxattr("RmXattrPP", "attr2", bl3));
+  std::map<std::string, bufferlist> attrset;
+  ASSERT_EQ(0, striper.getxattrs("RmXattrPP", attrset));
+  for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
+       i != attrset.end(); ++i) {
+    if (i->first == string("attr1")) {
+      ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
+    }
+    else if (i->first == string("attr2")) {
+      ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
+    }
+    else {
+      ASSERT_EQ(0, 1) << "Unexpected attribute : " << i->first;
+    }
+  }
+}
diff --git a/src/test/libradosstriper/striping.cc b/src/test/libradosstriper/striping.cc
new file mode 100644 (file)
index 0000000..c65f049
--- /dev/null
@@ -0,0 +1,307 @@
+#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
+#include "include/radosstriper/libradosstriper.h"
+#include "include/radosstriper/libradosstriper.hpp"
+#include "include/ceph_fs.h"
+#include "test/librados/test.h"
+#include "test/libradosstriper/TestCase.h"
+
+#include <string>
+#include <errno.h>
+using namespace librados;
+using namespace libradosstriper;
+
+class StriperTestRT : public StriperTestParam {
+public:
+  StriperTestRT() : StriperTestParam() {}
+protected:
+  char* getObjName(const std::string& soid, uint64_t nb)
+  {
+    char name[soid.size()+18];
+    sprintf(name, "%s.%016llx", soid.c_str(), (long long unsigned int)nb);
+    return strdup(name);
+  }
+  
+  void checkObjectFromRados(const std::string& soid, bufferlist &bl,
+                            uint64_t exp_stripe_unit, uint64_t exp_stripe_count,
+                            uint64_t exp_object_size, size_t size)
+  {
+    checkObjectFromRados(soid, bl, exp_stripe_unit, exp_stripe_count, exp_object_size, size, size);
+  }
+      
+  void checkObjectFromRados(const std::string& soid, bufferlist &bl,
+                            uint64_t exp_stripe_unit, uint64_t exp_stripe_count,
+                            uint64_t exp_object_size, size_t size,
+                            size_t actual_size_if_sparse)
+  {
+    // checking first object's rados xattrs
+    bufferlist xattrbl;
+    std::string firstOid = getObjName(soid, 0);
+    ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.stripe_unit", xattrbl));
+    std::string s_xattr(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
+    uint64_t stripe_unit = strtoll(s_xattr.c_str(), NULL, 10);
+    ASSERT_EQ(stripe_unit, exp_stripe_unit);
+    ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.stripe_count", xattrbl));
+    s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
+    uint64_t stripe_count = strtoll(s_xattr.c_str(), NULL, 10);
+    ASSERT_EQ(stripe_count, exp_stripe_count);
+    ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.layout.object_size", xattrbl));
+    s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
+    uint64_t object_size = strtoll(s_xattr.c_str(), NULL, 10);
+    ASSERT_EQ(object_size, exp_object_size);
+    ASSERT_LT(0, ioctx.getxattr(firstOid, "striper.size", xattrbl));
+    s_xattr = std::string(xattrbl.c_str(), xattrbl.length()); // adds 0 byte at the end
+    uint64_t xa_size = strtoll(s_xattr.c_str(), NULL, 10);
+    ASSERT_EQ(xa_size, size);
+    // checking object content from rados point of view
+    // we will go stripe by stripe, read the content of each of them and
+    // check with expectations
+    uint64_t stripe_per_object = object_size / stripe_unit;
+    uint64_t stripe_per_objectset = stripe_per_object * stripe_count;
+    uint64_t nb_stripes_in_object = (size+stripe_unit-1)/stripe_unit;
+    for (uint64_t stripe_nb = 0;
+         stripe_nb < nb_stripes_in_object;
+         stripe_nb++) {
+      // find out where this stripe is stored
+      uint64_t objectset = stripe_nb / stripe_per_objectset;
+      uint64_t stripe_in_object_set = stripe_nb % stripe_per_objectset;
+      uint64_t object_in_set = stripe_in_object_set % stripe_count;
+      uint64_t stripe_in_object = stripe_in_object_set / stripe_count;
+      uint64_t object_nb = objectset * stripe_count + object_in_set;
+      uint64_t start = stripe_in_object * stripe_unit;
+      uint64_t len = stripe_unit;
+      if (stripe_nb == nb_stripes_in_object-1 and size % stripe_unit != 0) {
+        len = size % stripe_unit;
+      }
+      // handle case of sparse object (can only be sparse at the end in our tests)
+      if (actual_size_if_sparse < size and
+          ((actual_size_if_sparse+stripe_unit-1)/stripe_unit)-1 == stripe_nb) {
+        len = actual_size_if_sparse % stripe_unit;
+        if (0 == len) len = stripe_unit;
+      }
+      bufferlist stripe_data;
+      // check object content
+      std::string oid = getObjName(soid, object_nb);
+      int rc = ioctx.read(oid, stripe_data, len, start);
+      if (actual_size_if_sparse < size and
+          (actual_size_if_sparse+stripe_unit-1)/stripe_unit <= stripe_nb) {
+        // sparse object case : the stripe does not exist, but the rados object may
+        uint64_t object_start = (object_in_set + objectset*stripe_per_objectset) * stripe_unit;
+        if (actual_size_if_sparse <= object_start) {
+          ASSERT_EQ(rc, -ENOENT);
+        } else {
+          ASSERT_EQ(rc, 0);
+        }
+      } else {
+        ASSERT_EQ((uint64_t)rc, len);
+        bufferlist original_data;
+        original_data.substr_of(bl, stripe_nb*stripe_unit, len);
+        ASSERT_EQ(0, memcmp(original_data.c_str(), stripe_data.c_str(), len));
+      }
+    }
+    // checking rados object sizes; we go object by object
+    uint64_t nb_full_object_sets = nb_stripes_in_object / stripe_per_objectset;
+    uint64_t nb_extra_objects = nb_stripes_in_object % stripe_per_objectset;
+    if (nb_extra_objects > stripe_count) nb_extra_objects = stripe_count;
+    uint64_t nb_objects = nb_full_object_sets * stripe_count + nb_extra_objects;
+    for (uint64_t object_nb = 0; object_nb < nb_objects; object_nb++) {
+      uint64_t rados_size;
+      time_t mtime;
+      std::string oid = getObjName(soid, object_nb);
+      uint64_t nb_full_object_set = object_nb / stripe_count;
+      uint64_t object_index_in_set = object_nb % stripe_count;
+      uint64_t object_start_stripe = nb_full_object_set * stripe_per_objectset + object_index_in_set;
+      uint64_t object_start_off = object_start_stripe * stripe_unit;
+       if (actual_size_if_sparse < size and actual_size_if_sparse <= object_start_off) {
+         ASSERT_EQ(-ENOENT, ioctx.stat(oid, &rados_size, &mtime));
+       } else {
+         ASSERT_EQ(0, ioctx.stat(oid, &rados_size, &mtime));
+         uint64_t offset = object_start_off;
+         uint64_t stripe_size = stripe_count * stripe_unit;
+         uint64_t set_size = stripe_count * object_size;
+         uint64_t len = 0;
+         for (offset = object_start_off;
+              (offset < (object_start_off) + set_size) && (offset < actual_size_if_sparse);
+              offset += stripe_size) {
+           if (offset + stripe_unit > actual_size_if_sparse) {
+             len += actual_size_if_sparse-offset;
+           } else {
+             len += stripe_unit;
+           }
+         }
+         ASSERT_EQ(len, rados_size);
+       }
+    }
+    // check we do not have an extra object behind
+    uint64_t rados_size;
+    time_t mtime;
+    ASSERT_EQ(-ENOENT, ioctx.stat(getObjName(soid, nb_objects), &rados_size, &mtime));
+  }
+};
+  
+TEST_P(StriperTestRT, StripedRoundtrip) {
+  // get striping parameters and apply them
+  TestData testData = GetParam();
+  ASSERT_EQ(0, striper.set_object_layout_stripe_unit(testData.stripe_unit));
+  ASSERT_EQ(0, striper.set_object_layout_stripe_count(testData.stripe_count));
+  ASSERT_EQ(0, striper.set_object_layout_object_size(testData.object_size));
+  std::ostringstream oss;
+  oss << "StripedRoundtrip_" << testData.stripe_unit << "_"
+      << testData.stripe_count << "_" << testData.object_size
+      << "_" << testData.size;
+  std::string soid = oss.str();
+  // writing striped data
+  bufferlist bl1;
+  {
+    SCOPED_TRACE("Writing initial object"); 
+    char buf[testData.size];
+    for (unsigned int i = 0; i < testData.size; i++) buf[i] = 13*((unsigned char)i);
+    bl1.append(buf, testData.size);
+    ASSERT_EQ(0, striper.write(soid, bl1, testData.size, 0));
+    // checking object state from Rados point of view
+    ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
+                                                 testData.stripe_count, testData.object_size,
+                                                 testData.size));
+  }
+  // adding more data to object and checking again
+  bufferlist bl2;
+  {
+    SCOPED_TRACE("Testing append");
+    char buf2[testData.size];
+    for (unsigned int i = 0; i < testData.size; i++) buf2[i] = 17*((unsigned char)i);
+    bl2.append(buf2, testData.size);
+    ASSERT_EQ(0, striper.append(soid, bl2, testData.size));
+    bl1.append(buf2, testData.size);
+    ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
+                                                 testData.stripe_count, testData.object_size,
+                                                 testData.size*2));
+  }
+  // truncating to half original size and checking again
+  {
+    SCOPED_TRACE("Testing trunc to truncate object");
+    ASSERT_EQ(0, striper.trunc(soid, testData.size/2));
+    ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl1, testData.stripe_unit,
+                                                 testData.stripe_count, testData.object_size,
+                                                 testData.size/2));
+  }
+  // truncating back to original size and checking again (especially for 0s)
+  {
+    SCOPED_TRACE("Testing trunc to extend object with 0s");
+    ASSERT_EQ(0, striper.trunc(soid, testData.size));
+    bufferlist bl3;
+    bl3.substr_of(bl1, 0, testData.size/2);
+    bl3.append_zero(testData.size - testData.size/2);
+    ASSERT_NO_FATAL_FAILURE(checkObjectFromRados(soid, bl3, testData.stripe_unit,
+                                                 testData.stripe_count, testData.object_size,
+                                                 testData.size, testData.size/2));
+  }
+  {
+    SCOPED_TRACE("Testing write_full");
+    // using write_full and checking again
+    ASSERT_EQ(0, striper.write_full(soid, bl2));
+    checkObjectFromRados(soid, bl2, testData.stripe_unit,
+                         testData.stripe_count, testData.object_size,
+                         testData.size);
+  }
+  {
+    SCOPED_TRACE("Testing standard remove");
+    // call remove
+    ASSERT_EQ(0, striper.remove(soid));
+    // check that the removal was successful
+    uint64_t size;
+    time_t mtime;   
+    for (uint64_t object_nb = 0;
+         object_nb < testData.size*2/testData.object_size + testData.stripe_count;
+         object_nb++) {
+      ASSERT_EQ(-ENOENT, ioctx.stat(getObjName(soid, object_nb), &size, &mtime));
+    }
+  }
+  {
+    SCOPED_TRACE("Testing remove when no object size");
+    // recreate object
+    ASSERT_EQ(0, striper.write(soid, bl1, testData.size*2, 0));
+    // remove the object size attribute from the striped object
+    std::string firstOid = getObjName(soid, 0);
+    ASSERT_EQ(0, ioctx.rmxattr(firstOid, "striper.size"));
+    // check that stat fails
+    uint64_t size;
+    time_t mtime;   
+    ASSERT_EQ(-ENODATA, striper.stat(soid, &size, &mtime));
+    // call remove
+    ASSERT_EQ(0, striper.remove(soid));
+    // check that the removal was successful
+    for (uint64_t object_nb = 0;
+         object_nb < testData.size*2/testData.object_size + testData.stripe_count;
+         object_nb++) {
+      ASSERT_EQ(-ENOENT, ioctx.stat(getObjName(soid, object_nb), &size, &mtime));
+    }
+  }
+}
+
+const TestData simple_stripe_schemes[] = {
+  // stripe_unit,        stripe_count, object_size,            size
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   2},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 5,            3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100},
+  {262144,               5,            262144,                 2},
+  {262144,               5,            262144,                 262144},
+  {262144,               5,            262144,                 262144-1},
+  {262144,               5,            262144,                 2*262144},
+  {262144,               5,            262144,                 12*262144},
+  {262144,               5,            262144,                 2*262144-1},
+  {262144,               5,            262144,                 12*262144-1},
+  {262144,               5,            262144,                 2*262144+100},
+  {262144,               5,            262144,                 12*262144+100},
+  {262144,               5,            3*262144,               2*262144+100},
+  {262144,               5,            3*262144,               8*262144+100},
+  {262144,               5,            3*262144,               12*262144+100},
+  {262144,               5,            3*262144,               15*262144+100},
+  {262144,               5,            3*262144,               25*262144+100},
+  {262144,               5,            3*262144,               45*262144+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   2},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 1,            3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   2},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT-1},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           CEPH_MIN_STRIPE_UNIT,   12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 2*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 8*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 12*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 15*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 25*CEPH_MIN_STRIPE_UNIT+100},
+  {CEPH_MIN_STRIPE_UNIT, 50,           3*CEPH_MIN_STRIPE_UNIT, 45*CEPH_MIN_STRIPE_UNIT+100}
+};
+
+INSTANTIATE_TEST_CASE_P(SimpleStriping,
+                        StriperTestRT,
+                        ::testing::ValuesIn(simple_stripe_schemes));