]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: convert C tests to gtest
authorSage Weil <sage@newdream.net>
Mon, 12 Sep 2011 04:35:21 +0000 (21:35 -0700)
committerSage Weil <sage@newdream.net>
Mon, 12 Sep 2011 04:35:21 +0000 (21:35 -0700)
Signed-off-by: Sage Weil <sage@newdream.net>
src/Makefile.am
src/test/test_librbd.cc [new file with mode: 0644]
src/testlibrbd.c [deleted file]

index cf561ddc2c819ae1e2c01940e6c6cd15e450076f..a89304964fd633fd2cf37ba430300d377a447a2d 100644 (file)
@@ -294,9 +294,6 @@ rbd_CXXFLAGS = ${AM_CXXFLAGS}
 rbd_LDADD = libglobal.la librbd.la librados.la -lpthread -lm -lkeyutils $(CRYPTO_LIBS) $(EXTRALIBS)
 bin_PROGRAMS += rbd
 
-testlibrbd_SOURCES = testlibrbd.c
-testlibrbd_LDADD = librbd.la librados.la -lpthread -lm \
-                  $(CRYPTO_LIBS) $(EXTRALIBS)
 testlibrbdpp_SOURCES = testlibrbdpp.cc
 testlibrbdpp_LDADD = librbd.la librados.la -lpthread -lm \
                     $(CRYPTO_LIBS) $(EXTRALIBS)
@@ -579,6 +576,11 @@ unittest_librgw_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 check_PROGRAMS += unittest_librgw
 endif
 
+test_librbd_SOURCES = test/test_librbd.cc
+test_librbd_LDADD =  librbd.la ${UNITTEST_STATIC_LDADD}
+test_librbd_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+bin_DEBUGPROGRAMS += test_librbd
+
 test_rados_api_io_SOURCES = test/rados-api/io.cc test/rados-api/test.cc
 test_rados_api_io_LDFLAGS = ${AM_LDFLAGS}
 test_rados_api_io_LDADD =  librados.la ${UNITTEST_STATIC_LDADD}
diff --git a/src/test/test_librbd.cc b/src/test/test_librbd.cc
new file mode 100644 (file)
index 0000000..43d7808
--- /dev/null
@@ -0,0 +1,484 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "include/rados/librados.h"
+#include "include/rbd/librbd.h"
+
+#include "gtest/gtest.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "rados-api/test.cc"
+
+TEST(LibRBD, CreateAndStat)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_info_t info;
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  uint64_t size = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+  ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
+  printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
+  ASSERT_EQ(info.size, size);
+  ASSERT_EQ(info.order, order);
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+TEST(LibRBD, ResizeAndStat)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_info_t info;
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  uint64_t size = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+
+  ASSERT_EQ(0, rbd_resize(image, size * 4));
+  ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
+  ASSERT_EQ(info.size, size * 4);
+
+  ASSERT_EQ(0, rbd_resize(image, size / 2));
+  ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
+  ASSERT_EQ(info.size, size / 2);
+  
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+
+int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
+{
+  int num_images, i, j;
+  char *expected, *names, *cur_name;
+  va_list ap;
+  size_t max_size = 1024;
+
+  names = (char *) malloc(sizeof(char *) * 1024);
+  int len = rbd_list(io_ctx, names, &max_size);
+
+  for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) {
+    printf("image: %s\n", cur_name);
+    cur_name += strlen(cur_name) + 1;
+    num_images++;
+  }
+
+  va_start(ap, num_expected);
+  for (i = num_expected; i > 0; i--) {
+    expected = va_arg(ap, char *);
+    printf("expected = %s\n", expected);
+    int found = 0;
+    for (j = 0, cur_name = names; j < num_images; j++) {
+      if (cur_name[0] == '_') {
+       cur_name += strlen(cur_name) + 1;
+       continue;
+      }
+      if (strcmp(cur_name, expected) == 0) {
+       printf("found %s\n", cur_name);
+       cur_name[0] = '_';
+       found = 1;
+       break;
+      }
+    }
+    assert(found);
+  }
+  va_end(ap);
+
+  for (i = 0, cur_name = names; cur_name < names + len; i++) {
+    assert(cur_name[0] == '_');
+    cur_name += strlen(cur_name) + 1;
+  }
+  free(names);
+
+  return num_images;
+}
+
+TEST(LibRBD, TestCreateLsDelete)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  int order = 0;
+  const char *name = "testimg";
+  const char *name2 = "testimg2";
+  uint64_t size = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(1, test_ls(ioctx, 1, name));
+  ASSERT_EQ(0, rbd_create(ioctx, name2, size, &order));
+  ASSERT_EQ(2, test_ls(ioctx, 2, name, name2));
+  ASSERT_EQ(0, rbd_remove(ioctx, name));
+  ASSERT_EQ(1, test_ls(ioctx, 1, name2));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+
+static int print_progress_percent(uint64_t offset, uint64_t src_size,
+                                    void *data)
+{
+  float percent = ((float)offset * 100) / src_size;
+  printf("%3.2f%% done\n", percent);
+  return 0; 
+}
+
+TEST(LibRBD, TestCopy)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  const char *name2 = "testimg2";
+  const char *name3 = "testimg3";
+
+  uint64_t size = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+  ASSERT_EQ(1, test_ls(ioctx, 1, name));
+  ASSERT_LT(0, rbd_copy(image, ioctx, name2));
+  ASSERT_EQ(2, test_ls(ioctx, 2, name, name2));
+  ASSERT_LT(0, rbd_copy_with_progress(image, ioctx, name3, print_progress_percent, NULL));
+  ASSERT_EQ(3, test_ls(ioctx, 3, name, name2, name3));
+
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+int test_ls_snaps(rbd_image_t image, int num_expected, ...)
+{
+  rbd_snap_info_t *snaps;
+  int num_snaps, i, j, expected_size, max_size = 10;
+  char *expected;
+  va_list ap;
+  snaps = (rbd_snap_info_t *) malloc(sizeof(rbd_snap_info_t *) * 10);
+  num_snaps = rbd_snap_list(image, snaps, &max_size);
+  printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
+
+  for (i = 0; i < num_snaps; i++) {
+    printf("snap: %s\n", snaps[i].name);
+  }
+
+  va_start(ap, num_expected);
+  for (i = num_expected; i > 0; i--) {
+    expected = va_arg(ap, char *);
+    expected_size = va_arg(ap, int);
+    int found = 0;
+    for (j = 0; j < num_snaps; j++) {
+      if (snaps[j].name == NULL)
+       continue;
+      if (strcmp(snaps[j].name, expected) == 0) {
+       printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
+       assert((int)snaps[j].size == expected_size);
+       free((void *) snaps[j].name);
+       snaps[j].name = NULL;
+       found = 1;
+       break;
+      }
+    }
+    assert(found);
+  }
+  va_end(ap);
+
+  for (i = 0; i < num_snaps; i++) {
+    assert(snaps[i].name == NULL);
+  }
+  free(snaps);
+
+  return num_snaps;
+}
+
+TEST(LibRBD, TestCreateLsDeleteSnap)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  uint64_t size = 2 << 20;
+  uint64_t size2 = 4 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+
+  ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
+  ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
+  ASSERT_EQ(0, rbd_resize(image, size2));
+  ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
+  ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
+  ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
+  ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
+  ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
+  ASSERT_EQ(0, test_ls_snaps(image, 0));
+  
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+
+#define TEST_IO_SIZE 512
+#define TEST_IO_TO_SNAP_SIZE 80
+
+void simple_write_cb(rbd_completion_t cb, void *arg)
+{
+  printf("write completion cb called!\n");
+}
+
+void simple_read_cb(rbd_completion_t cb, void *arg)
+{
+  printf("read completion cb called!\n");
+}
+
+void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
+{
+  rbd_completion_t comp;
+  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
+  printf("created completion\n");
+  rbd_aio_write(image, off, len, test_data, comp);
+  printf("started write\n");
+  rbd_aio_wait_for_complete(comp);
+  int r = rbd_aio_get_return_value(comp);
+  printf("return value is: %d\n", r);
+  assert(r == 0);
+  printf("finished write\n");
+  rbd_aio_release(comp);
+}
+
+void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
+{
+  ssize_t written;
+  written = rbd_write(image, off, len, test_data);
+  printf("wrote: %d\n", (int) written);
+  assert(written == (ssize_t)len);
+}
+
+void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
+{
+  rbd_completion_t comp;
+  char *result = (char *)malloc(len + 1);
+
+  assert(result);
+  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
+  printf("created completion\n");
+  rbd_aio_read(image, off, len, result, comp);
+  printf("started read\n");
+  rbd_aio_wait_for_complete(comp);
+  int r = rbd_aio_get_return_value(comp);
+  printf("return value is: %d\n", r);
+  assert(r == (ssize_t)len);
+  rbd_aio_release(comp);
+  printf("read: %s\nexpected: %s\n", result, expected);
+  assert(memcmp(result, expected, len) == 0);
+  free(result);
+}
+
+void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
+{
+  ssize_t read;
+  char *result = (char *)malloc(len + 1);
+
+  assert(result);
+  read = rbd_read(image, off, len, result);
+  printf("read: %d\n", (int) read);
+  assert(read == (ssize_t)len);
+  result[len] = '\0';
+  printf("read: %s\nexpected: %s\n", result, expected);
+  assert(memcmp(result, expected, len) == 0);
+  free(result);
+}
+
+TEST(LibRBD, TestIO)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  uint64_t size = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, size, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+
+  char test_data[TEST_IO_SIZE + 1];
+  int i;
+
+  for (i = 0; i < TEST_IO_SIZE; ++i) {
+    test_data[i] = (char) (rand() % (126 - 33) + 33);
+  }
+  test_data[TEST_IO_SIZE] = '\0';
+
+  for (i = 0; i < 5; ++i)
+    write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
+
+  for (i = 5; i < 10; ++i)
+    aio_write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
+
+  for (i = 0; i < 5; ++i)
+    read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
+
+  for (i = 5; i < 10; ++i)
+    aio_read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
+
+  rbd_image_info_t info;
+  rbd_completion_t comp;
+  ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
+  ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
+  ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
+  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
+  ASSERT_EQ(-EINVAL, rbd_aio_write(image, info.size, 1, test_data, comp));
+  ASSERT_EQ(-EINVAL, rbd_aio_read(image, info.size, 1, test_data, comp));
+
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+TEST(LibRBD, TestIOToSnapshot)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  std::string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  rbd_image_t image;
+  int order = 0;
+  const char *name = "testimg";
+  uint64_t isize = 2 << 20;
+  
+  ASSERT_EQ(0, rbd_create(ioctx, name, isize, &order));
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL));
+
+  int i, r;
+  rbd_image_t image_at_snap;
+  char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
+  char test_data[TEST_IO_TO_SNAP_SIZE + 1];
+
+  for (i = 0; i < TEST_IO_TO_SNAP_SIZE - 1; ++i)
+    test_data[i] = (char) (i + 48);
+  test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
+  orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
+
+  r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
+  ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
+
+  ASSERT_EQ(0, test_ls_snaps(image, 0));
+  ASSERT_EQ(0, rbd_snap_create(image, "orig"));
+  ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
+  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  printf("write test data!\n");
+  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
+  ASSERT_EQ(0, rbd_snap_create(image, "written"));
+  ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
+
+  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  rbd_snap_set(image, "orig");
+  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  rbd_snap_set(image, "written");
+  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  rbd_snap_set(image, "orig");
+
+  r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
+  printf("write to snapshot returned %d\n", r);
+  ASSERT_LT(r, 0);
+  printf("%s\n", strerror(-r));
+
+  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
+  rbd_snap_set(image, "written");
+  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  r = rbd_snap_rollback(image, "orig");
+  printf("rbd_snap_rollback returned %d\n", r);
+  ASSERT_GE(r, 0);
+
+  r = rbd_snap_set(image, NULL);
+  ASSERT_EQ(r, 0);
+  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
+
+  printf("opening testimg@orig\n");
+  ASSERT_EQ(0, rbd_open(ioctx, name, &image_at_snap, "orig"));
+  read_test_data(image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
+  r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
+  printf("write to snapshot returned %d\n", r);
+  ASSERT_LT(r, 0);
+  printf("%s\n", strerror(-r));
+  ASSERT_EQ(0, rbd_close(image_at_snap));
+
+  ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
+  ASSERT_EQ(0, rbd_snap_remove(image, "written"));
+  ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
+  ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
+  ASSERT_EQ(0, test_ls_snaps(image, 0));
+
+  ASSERT_EQ(0, rbd_close(image));
+
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}
+
+
diff --git a/src/testlibrbd.c b/src/testlibrbd.c
deleted file mode 100644 (file)
index 5624ebb..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2011 New Dream Network
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License version 2, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include "include/rados/librados.h"
-#include "include/rbd/librbd.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#define TEST_IMAGE "testimg"
-#define TEST_IMAGE2 "testimg2"
-#define TEST_POOL "librbdtest"
-#define TEST_SNAP "testsnap"
-#define TEST_IO_SIZE 512
-#define TEST_IO_TO_SNAP_SIZE 80
-#define MB_BYTES(mb) (mb << 20)
-
-void test_create_and_stat(rados_ioctx_t io_ctx, const char *name, size_t size)
-{
-  rbd_image_info_t info;
-  rbd_image_t image;
-  int order = 0;
-  assert(rbd_create(io_ctx, name, size, &order) == 0);
-  assert(rbd_open(io_ctx, name, &image, NULL) == 0);
-  assert(rbd_stat(image, &info, sizeof(info)) == 0);
-  printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
-  assert(info.size == size);
-  assert(info.order == order);
-  assert(rbd_close(image) == 0);
-}
-
-void test_resize_and_stat(rbd_image_t image, size_t size)
-{
-  rbd_image_info_t info;
-  assert(rbd_resize(image, size) == 0);
-  assert(rbd_stat(image, &info, sizeof(info)) == 0);
-  printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
-  assert(info.size == size);
-}
-
-void test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
-{
-  int num_images, i, j;
-  char *expected, *names, *cur_name;
-  va_list ap;
-  size_t max_size = 1024;
-  names = (char *) malloc(sizeof(char *) * 1024);
-  num_images = rbd_list(io_ctx, names, &max_size);
-  printf("num images is: %d\nexpected: %d\n", num_images, (int)num_expected);
-  assert(num_images >= 0);
-  assert(num_images == (int)num_expected);
-
-  for (i = 0, cur_name = names; i < num_images; i++) {
-    printf("image: %s\n", cur_name);
-    cur_name += strlen(cur_name) + 1;
-  }
-
-  va_start(ap, num_expected);
-  for (i = num_expected; i > 0; i--) {
-    expected = va_arg(ap, char *);
-    printf("expected = %s\n", expected);
-    int found = 0;
-    for (j = 0, cur_name = names; j < num_images; j++) {
-      if (cur_name[0] == '_') {
-       cur_name += strlen(cur_name) + 1;
-       continue;
-      }
-      if (strcmp(cur_name, expected) == 0) {
-       printf("found %s\n", cur_name);
-       cur_name[0] = '_';
-       found = 1;
-       break;
-      }
-    }
-    assert(found);
-  }
-  va_end(ap);
-
-  for (i = 0, cur_name = names; i < num_images; i++) {
-    assert(cur_name[0] == '_');
-    cur_name += strlen(cur_name) + 1;
-  }
-  free(names);
-}
-
-void test_delete(rados_ioctx_t io_ctx, const char *name)
-{
-  assert(rbd_remove(io_ctx, name) == 0);
-}
-
-void test_create_snap(rbd_image_t image, const char *name)
-{
-  assert(rbd_snap_create(image, name) == 0);
-}
-
-void test_ls_snaps(rbd_image_t image, int num_expected, ...)
-{
-  rbd_snap_info_t *snaps;
-  int num_snaps, i, j, expected_size, max_size = 10;
-  char *expected;
-  va_list ap;
-  snaps = (rbd_snap_info_t *) malloc(sizeof(rbd_snap_info_t *) * 10);
-  num_snaps = rbd_snap_list(image, snaps, &max_size);
-  printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
-  assert(num_snaps == num_expected);
-
-  for (i = 0; i < num_snaps; i++) {
-    printf("snap: %s\n", snaps[i].name);
-  }
-
-  va_start(ap, num_expected);
-  for (i = num_expected; i > 0; i--) {
-    expected = va_arg(ap, char *);
-    expected_size = va_arg(ap, int);
-    int found = 0;
-    for (j = 0; j < num_snaps; j++) {
-      if (snaps[j].name == NULL)
-       continue;
-      if (strcmp(snaps[j].name, expected) == 0) {
-       printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
-       assert((int)snaps[j].size == expected_size);
-       free((void *) snaps[j].name);
-       snaps[j].name = NULL;
-       found = 1;
-       break;
-      }
-    }
-    assert(found);
-  }
-  va_end(ap);
-
-  for (i = 0; i < num_snaps; i++) {
-    assert(snaps[i].name == NULL);
-  }
-  free(snaps);
-}
-
-void test_delete_snap(rbd_image_t image, const char *name)
-{
-  assert(rbd_snap_remove(image, name) == 0);
-}
-
-void simple_write_cb(rbd_completion_t cb, void *arg)
-{
-  printf("write completion cb called!\n");
-}
-
-void simple_read_cb(rbd_completion_t cb, void *arg)
-{
-  printf("read completion cb called!\n");
-}
-
-void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
-{
-  rbd_completion_t comp;
-  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
-  printf("created completion\n");
-  rbd_aio_write(image, off, len, test_data, comp);
-  printf("started write\n");
-  rbd_aio_wait_for_complete(comp);
-  int r = rbd_aio_get_return_value(comp);
-  printf("return value is: %d\n", r);
-  assert(r == 0);
-  printf("finished write\n");
-  rbd_aio_release(comp);
-}
-
-void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
-{
-  ssize_t written;
-  written = rbd_write(image, off, len, test_data);
-  printf("wrote: %d\n", (int) written);
-  assert(written == (ssize_t)len);
-}
-
-void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
-{
-  rbd_completion_t comp;
-  char *result = malloc(len + 1);
-
-  assert(result);
-  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
-  printf("created completion\n");
-  rbd_aio_read(image, off, len, result, comp);
-  printf("started read\n");
-  rbd_aio_wait_for_complete(comp);
-  int r = rbd_aio_get_return_value(comp);
-  printf("return value is: %d\n", r);
-  assert(r == (ssize_t)len);
-  rbd_aio_release(comp);
-  printf("read: %s\nexpected: %s\n", result, expected);
-  assert(memcmp(result, expected, len) == 0);
-  free(result);
-}
-
-void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
-{
-  ssize_t read;
-  char *result = malloc(len + 1);
-
-  assert(result);
-  read = rbd_read(image, off, len, result);
-  printf("read: %d\n", (int) read);
-  assert(read == (ssize_t)len);
-  result[len] = '\0';
-  printf("read: %s\nexpected: %s\n", result, expected);
-  assert(memcmp(result, expected, len) == 0);
-  free(result);
-}
-
-void test_io(rados_ioctx_t io, rbd_image_t image)
-{
-  char test_data[TEST_IO_SIZE + 1];
-  int i;
-
-  for (i = 0; i < TEST_IO_SIZE; ++i) {
-    test_data[i] = (char) (rand() % (126 - 33) + 33);
-  }
-  test_data[TEST_IO_SIZE] = '\0';
-
-  for (i = 0; i < 5; ++i)
-    write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
-
-  for (i = 5; i < 10; ++i)
-    aio_write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
-
-  for (i = 0; i < 5; ++i)
-    read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
-
-  for (i = 5; i < 10; ++i)
-    aio_read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
-
-  rbd_image_info_t info;
-  rbd_completion_t comp;
-  assert(rbd_stat(image, &info, sizeof(info)) == 0);
-  assert(rbd_write(image, info.size, 1, test_data) == -EINVAL);
-  assert(rbd_read(image, info.size, 1, test_data) == -EINVAL);
-  rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
-  assert(rbd_aio_write(image, info.size, 1, test_data, comp) == -EINVAL);
-  assert(rbd_aio_read(image, info.size, 1, test_data, comp) == -EINVAL);
-}
-
-void test_io_to_snapshot(rados_ioctx_t io_ctx, rbd_image_t image, size_t isize)
-{
-  int i, r;
-  rbd_image_t image_at_snap;
-  char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
-  char test_data[TEST_IO_TO_SNAP_SIZE + 1];
-
-  for (i = 0; i < TEST_IO_TO_SNAP_SIZE - 1; ++i)
-    test_data[i] = (char) (i + 48);
-  test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
-  orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
-
-  r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
-  assert(r == TEST_IO_TO_SNAP_SIZE);
-
-  test_ls_snaps(image, 0);
-  test_create_snap(image, "orig");
-  test_ls_snaps(image, 1, "orig", isize);
-  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  printf("write test data!\n");
-  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
-  test_create_snap(image, "written");
-  test_ls_snaps(image, 2, "orig", isize, "written", isize);
-
-  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  rbd_snap_set(image, "orig");
-  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  rbd_snap_set(image, "written");
-  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  rbd_snap_set(image, "orig");
-
-  r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
-  printf("write to snapshot returned %d\n", r);
-  assert(r < 0);
-  printf("%s\n", strerror(-r));
-
-  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
-  rbd_snap_set(image, "written");
-  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  r = rbd_snap_rollback(image, "orig");
-  printf("rbd_snap_rollback returned %d\n", r);
-  assert(r >= 0);
-
-  r = rbd_snap_set(image, NULL);
-  assert(r == 0);
-  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
-
-  printf("opening testimg@orig\n");
-  assert(rbd_open(io_ctx, TEST_IMAGE, &image_at_snap, "orig") >= 0);
-  read_test_data(image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
-  r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
-  printf("write to snapshot returned %d\n", r);
-  assert(r < 0);
-  printf("%s\n", strerror(-r));
-  assert(rbd_close(image_at_snap) == 0);
-
-  test_ls_snaps(image, 2, "orig", isize, "written", isize);
-  test_delete_snap(image, "written");
-  test_ls_snaps(image, 1, "orig", isize);
-  test_delete_snap(image, "orig");
-  test_ls_snaps(image, 0);
-}
-
-void test_rbd_copy(rados_ioctx_t io_ctx, rbd_image_t image)
-{
-  int ret;
-  ret = rbd_copy(image, io_ctx, TEST_IMAGE2);
-  if (ret < 0) {
-    fprintf(stderr, "rbd_copy returned %d!\n", ret);
-    abort();
-  }
-}
-
-static int print_progress_percent(uint64_t offset, uint64_t src_size,
-                                    void *data)
-{
-  float percent = ((float)offset * 100) / src_size;
-  printf("%3.2f%% done\n", percent);
-  return 0; 
-}
-
-void test_rbd_copy_with_progress(rados_ioctx_t io_ctx, rbd_image_t image)
-{
-  int ret;
-  ret = rbd_copy_with_progress(image, io_ctx, TEST_IMAGE2,
-                                print_progress_percent, NULL);
-  if (ret < 0) {
-    fprintf(stderr, "rbd_copy_with_progress returned %d!\n", ret);
-    abort();
-  }
-}
-
-int main(int argc, const char **argv) 
-{
-  rados_t cluster;
-  rados_ioctx_t io_ctx;
-  rbd_image_t image;
-
-  srand(time(0));
-
-  assert(rados_create(&cluster, NULL) == 0);
-  assert(rados_conf_parse_argv(cluster, argc, argv) == 0);
-  assert(rados_conf_read_file(cluster, NULL) == 0);
-  assert(rados_connect(cluster) == 0);
-
-  if (rados_pool_lookup(cluster, TEST_POOL) != -ENOENT) {
-    int r = rados_pool_delete(cluster, TEST_POOL);
-    printf("rados_pool_delete returned %d\n", r);
-  }
-  int r = rados_pool_create(cluster, TEST_POOL);
-  printf("rados_pool_create returned %d\n", r);
-
-  assert(rados_ioctx_create(cluster, TEST_POOL, &io_ctx) == 0);
-  test_ls(io_ctx, 0);
-
-  test_create_and_stat(io_ctx, TEST_IMAGE, MB_BYTES(1));
-  assert(rbd_open(io_ctx, TEST_IMAGE, &image, NULL) == 0);
-
-  test_ls(io_ctx, 1, TEST_IMAGE);
-  test_ls_snaps(image, 0);
-
-  test_create_snap(image, TEST_SNAP);
-  test_ls_snaps(image, 1, TEST_SNAP, MB_BYTES(1));
-  test_resize_and_stat(image, MB_BYTES(2));
-  test_io(io_ctx, image);
-
-  test_create_snap(image, TEST_SNAP "1");
-  test_ls_snaps(image, 2, TEST_SNAP, MB_BYTES(1), TEST_SNAP "1", MB_BYTES(2));
-
-  test_delete_snap(image, TEST_SNAP);
-  test_ls_snaps(image, 1, TEST_SNAP "1", MB_BYTES(2));
-
-  test_delete_snap(image, TEST_SNAP "1");
-  test_ls_snaps(image, 0);
-
-  test_io_to_snapshot(io_ctx, image, MB_BYTES(2));
-  assert(rbd_close(image) == 0);
-
-  test_create_and_stat(io_ctx, TEST_IMAGE "1", MB_BYTES(2));
-  test_ls(io_ctx, 2, TEST_IMAGE, TEST_IMAGE "1");
-
-  test_delete(io_ctx, TEST_IMAGE);
-  test_ls(io_ctx, 1, TEST_IMAGE "1");
-
-  test_delete(io_ctx, TEST_IMAGE "1");
-  test_ls(io_ctx, 0);
-
-  test_rbd_copy(io_ctx, image);
-  test_delete(io_ctx, TEST_IMAGE2);
-  test_rbd_copy_with_progress(io_ctx, image);
-
-  rados_ioctx_destroy(io_ctx);
-  rados_shutdown(cluster);
-
-  return 0;
-}