initial code repo
[stor4nfv.git] / src / ceph / src / test / rgw / test_rgw_crypto.cc
diff --git a/src/ceph/src/test/rgw/test_rgw_crypto.cc b/src/ceph/src/test/rgw/test_rgw_crypto.cc
new file mode 100644 (file)
index 0000000..7739b4e
--- /dev/null
@@ -0,0 +1,660 @@
+// -*- 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) 2016 Mirantis <akupczyk@mirantis.com>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+#include <iostream>
+#include "global/global_init.h"
+#include "common/ceph_argparse.h"
+#include "rgw/rgw_common.h"
+#include "rgw/rgw_rados.h"
+#include "rgw/rgw_crypt.h"
+#include <gtest/gtest.h>
+#include "include/assert.h"
+#define dout_subsys ceph_subsys_rgw
+
+using namespace std;
+
+
+std::unique_ptr<BlockCrypt> AES_256_CBC_create(CephContext* cct, const uint8_t* key, size_t len);
+
+
+class ut_get_sink : public RGWGetDataCB {
+  std::stringstream sink;
+public:
+  ut_get_sink() {}
+  virtual ~ut_get_sink() {}
+
+  int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override
+  {
+    sink << boost::string_ref(bl.c_str()+bl_ofs, bl_len);
+    return 0;
+  }
+  std::string get_sink()
+  {
+    return sink.str();
+  }
+};
+
+class ut_put_sink: public RGWPutObjDataProcessor
+{
+  std::stringstream sink;
+public:
+  ut_put_sink(){}
+  virtual ~ut_put_sink(){}
+  int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again) override
+  {
+    sink << boost::string_ref(bl.c_str(),bl.length());
+    *again = false;
+    return 0;
+  }
+  int throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait) override
+  {
+    return 0;
+  }
+  std::string get_sink()
+  {
+    return sink.str();
+  }
+};
+
+
+class BlockCryptNone: public BlockCrypt {
+public:
+  BlockCryptNone(){};
+  virtual ~BlockCryptNone(){};
+  size_t get_block_size() override
+  {
+    return 256;
+  }
+  bool encrypt(bufferlist& input,
+                       off_t in_ofs,
+                       size_t size,
+                       bufferlist& output,
+                       off_t stream_offset) override
+  {
+    output.clear();
+    output.append(input.c_str(), input.length());
+    return true;
+  }
+  bool decrypt(bufferlist& input,
+                       off_t in_ofs,
+                       size_t size,
+                       bufferlist& output,
+                       off_t stream_offset) override
+  {
+    output.clear();
+    output.append(input.c_str(), input.length());
+    return true;
+  }
+};
+
+
+TEST(TestRGWCrypto, verify_AES_256_CBC_identity)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  buffer::ptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17})
+  {
+    //make some random key
+    uint8_t key[32];
+    for(size_t i=0;i<sizeof(key);i++)
+      key[i]=i*step;
+
+    auto aes(AES_256_CBC_create(g_ceph_context, &key[0], 32));
+    ASSERT_NE(aes.get(), nullptr);
+
+    size_t block_size = aes->get_block_size();
+    ASSERT_NE(block_size, 0u);
+
+    for (size_t r = 97; r < 123 ; r++)
+    {
+      off_t begin = (r*r*r*r*r % test_range);
+      begin = begin - begin % block_size;
+      off_t end = begin + r*r*r*r*r*r*r % (test_range - begin);
+      if (r % 3)
+        end = end - end % block_size;
+      off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000);
+      offset = offset - offset % block_size;
+
+      ASSERT_EQ(begin % block_size, 0u);
+      ASSERT_LE(end, test_range);
+      ASSERT_EQ(offset % block_size, 0u);
+
+      bufferlist encrypted;
+      ASSERT_TRUE(aes->encrypt(input, begin, end - begin, encrypted, offset));
+      bufferlist decrypted;
+      ASSERT_TRUE(aes->decrypt(encrypted, 0, end - begin, decrypted, offset));
+
+      ASSERT_EQ(decrypted.length(), end - begin);
+      ASSERT_EQ(boost::string_ref(input.c_str() + begin, end - begin),
+                boost::string_ref(decrypted.c_str(), end - begin) );
+    }
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_AES_256_CBC_identity_2)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  buffer::ptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17})
+  {
+    //make some random key
+    uint8_t key[32];
+    for(size_t i=0;i<sizeof(key);i++)
+      key[i]=i*step;
+
+    auto aes(AES_256_CBC_create(g_ceph_context, &key[0], 32));
+    ASSERT_NE(aes.get(), nullptr);
+
+    size_t block_size = aes->get_block_size();
+    ASSERT_NE(block_size, 0u);
+
+    for (off_t end = 1; end < 6096 ; end+=3)
+    {
+      off_t begin = 0;
+      off_t offset = end*end*end*end*end % (1000*1000*1000);
+      offset = offset - offset % block_size;
+
+      ASSERT_EQ(begin % block_size, 0u);
+      ASSERT_LE(end, test_range);
+      ASSERT_EQ(offset % block_size, 0u);
+
+      bufferlist encrypted;
+      ASSERT_TRUE(aes->encrypt(input, begin, end, encrypted, offset));
+      bufferlist decrypted;
+      ASSERT_TRUE(aes->decrypt(encrypted, 0, end, decrypted, offset));
+
+      ASSERT_EQ(decrypted.length(), end);
+      ASSERT_EQ(boost::string_ref(input.c_str(), end),
+                boost::string_ref(decrypted.c_str(), end) );
+    }
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_AES_256_CBC_identity_3)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  buffer::ptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17})
+  {
+    //make some random key
+    uint8_t key[32];
+    for(size_t i=0;i<sizeof(key);i++)
+      key[i]=i*step;
+
+    auto aes(AES_256_CBC_create(g_ceph_context, &key[0], 32));
+    ASSERT_NE(aes.get(), nullptr);
+
+    size_t block_size = aes->get_block_size();
+    ASSERT_NE(block_size, 0u);
+    size_t rr = 111;
+    for (size_t r = 97; r < 123 ; r++)
+    {
+      off_t begin = 0;
+      off_t end = begin + r*r*r*r*r*r*r % (test_range - begin);
+      //sometimes make aligned
+      if (r % 3)
+        end = end - end % block_size;
+      off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000);
+      offset = offset - offset % block_size;
+
+      ASSERT_EQ(begin % block_size, 0u);
+      ASSERT_LE(end, test_range);
+      ASSERT_EQ(offset % block_size, 0u);
+
+      bufferlist encrypted1;
+      bufferlist encrypted2;
+
+      off_t pos = begin;
+      off_t chunk;
+      while (pos < end) {
+        chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000;
+        chunk = chunk - chunk % block_size;
+        if (pos + chunk > end)
+          chunk = end - pos;
+        bufferlist tmp;
+        ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos));
+        encrypted1.append(tmp);
+        pos += chunk;
+        rr++;
+      }
+
+      pos = begin;
+      while (pos < end) {
+        chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000;
+        chunk = chunk - chunk % block_size;
+        if (pos + chunk > end)
+          chunk = end - pos;
+        bufferlist tmp;
+        ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos));
+        encrypted2.append(tmp);
+        pos += chunk;
+        rr++;
+      }
+      ASSERT_EQ(encrypted1.length(), end);
+      ASSERT_EQ(encrypted2.length(), end);
+      ASSERT_EQ(boost::string_ref(encrypted1.c_str(), end),
+                boost::string_ref(encrypted2.c_str(), end) );
+    }
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_AES_256_CBC_size_0_15)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  buffer::ptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17})
+  {
+    //make some random key
+    uint8_t key[32];
+    for(size_t i=0;i<sizeof(key);i++)
+      key[i]=i*step;
+
+    auto aes(AES_256_CBC_create(g_ceph_context, &key[0], 32));
+    ASSERT_NE(aes.get(), nullptr);
+
+    size_t block_size = aes->get_block_size();
+    ASSERT_NE(block_size, 0u);
+    for (size_t r = 97; r < 123 ; r++)
+    {
+      off_t begin = 0;
+      off_t end = begin + r*r*r*r*r*r*r % (16);
+
+      off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000);
+      offset = offset - offset % block_size;
+
+      ASSERT_EQ(begin % block_size, 0u);
+      ASSERT_LE(end, test_range);
+      ASSERT_EQ(offset % block_size, 0u);
+
+      bufferlist encrypted;
+      bufferlist decrypted;
+      ASSERT_TRUE(aes->encrypt(input, 0, end, encrypted, offset));
+      ASSERT_TRUE(aes->encrypt(encrypted, 0, end, decrypted, offset));
+      ASSERT_EQ(encrypted.length(), end);
+      ASSERT_EQ(decrypted.length(), end);
+      ASSERT_EQ(boost::string_ref(input.c_str(), end),
+                boost::string_ref(decrypted.c_str(), end) );
+    }
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_AES_256_CBC_identity_last_block)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  buffer::ptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17})
+  {
+    //make some random key
+    uint8_t key[32];
+    for(size_t i=0;i<sizeof(key);i++)
+      key[i]=i*step;
+
+    auto aes(AES_256_CBC_create(g_ceph_context, &key[0], 32));
+    ASSERT_NE(aes.get(), nullptr);
+
+    size_t block_size = aes->get_block_size();
+    ASSERT_NE(block_size, 0u);
+    size_t rr = 111;
+    for (size_t r = 97; r < 123 ; r++)
+    {
+      off_t begin = 0;
+      off_t end = r*r*r*r*r*r*r % (test_range - 16);
+      end = end - end % block_size;
+      end = end + (r+3)*(r+5)*(r+7) % 16;
+
+      off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000);
+      offset = offset - offset % block_size;
+
+      ASSERT_EQ(begin % block_size, 0u);
+      ASSERT_LE(end, test_range);
+      ASSERT_EQ(offset % block_size, 0u);
+
+      bufferlist encrypted1;
+      bufferlist encrypted2;
+
+      off_t pos = begin;
+      off_t chunk;
+      while (pos < end) {
+        chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000;
+        chunk = chunk - chunk % block_size;
+        if (pos + chunk > end)
+          chunk = end - pos;
+        bufferlist tmp;
+        ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos));
+        encrypted1.append(tmp);
+        pos += chunk;
+        rr++;
+      }
+      pos = begin;
+      while (pos < end) {
+        chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000;
+        chunk = chunk - chunk % block_size;
+        if (pos + chunk > end)
+          chunk = end - pos;
+        bufferlist tmp;
+        ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos));
+        encrypted2.append(tmp);
+        pos += chunk;
+        rr++;
+      }
+      ASSERT_EQ(encrypted1.length(), end);
+      ASSERT_EQ(encrypted2.length(), end);
+      ASSERT_EQ(boost::string_ref(encrypted1.c_str(), end),
+                boost::string_ref(encrypted2.c_str(), end) );
+    }
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_ranges)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  bufferptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  uint8_t key[32];
+  for(size_t i=0;i<sizeof(key);i++)
+    key[i] = i;
+
+  auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+  ASSERT_NE(cbc.get(), nullptr);
+  bufferlist encrypted;
+  ASSERT_TRUE(cbc->encrypt(input, 0, test_range, encrypted, 0));
+
+
+  for (off_t r = 93; r < 150; r++ )
+  {
+    ut_get_sink get_sink;
+    auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+    ASSERT_NE(cbc.get(), nullptr);
+    RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink, std::move(cbc) );
+
+    //random ranges
+    off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range;
+    off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1;
+
+    off_t f_begin = begin;
+    off_t f_end = end;
+    decrypt.fixup_range(f_begin, f_end);
+    decrypt.handle_data(encrypted, f_begin, f_end - f_begin + 1);
+    decrypt.flush();
+    const std::string& decrypted = get_sink.get_sink();
+    size_t expected_len = end - begin + 1;
+    ASSERT_EQ(decrypted.length(), expected_len);
+    ASSERT_EQ(decrypted, boost::string_ref(input.c_str()+begin, expected_len));
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_chunks)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  bufferptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  uint8_t key[32];
+  for(size_t i=0;i<sizeof(key);i++)
+    key[i] = i;
+
+  auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+  ASSERT_NE(cbc.get(), nullptr);
+  bufferlist encrypted;
+  ASSERT_TRUE(cbc->encrypt(input, 0, test_range, encrypted, 0));
+
+  for (off_t r = 93; r < 150; r++ )
+  {
+    ut_get_sink get_sink;
+    auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+    ASSERT_NE(cbc.get(), nullptr);
+    RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink, std::move(cbc) );
+
+    //random
+    off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range;
+    off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1;
+
+    off_t f_begin = begin;
+    off_t f_end = end;
+    decrypt.fixup_range(f_begin, f_end);
+    off_t pos = f_begin;
+    do
+    {
+      off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16);
+      size = (pos + 1117) * (pos + 2229) % size + 1;
+      if (pos + size > f_end + 1)
+        size = f_end + 1 - pos;
+
+      decrypt.handle_data(encrypted, pos, size);
+      pos = pos + size;
+    } while (pos < f_end + 1);
+    decrypt.flush();
+
+    const std::string& decrypted = get_sink.get_sink();
+    size_t expected_len = end - begin + 1;
+    ASSERT_EQ(decrypted.length(), expected_len);
+    ASSERT_EQ(decrypted, boost::string_ref(input.c_str()+begin, expected_len));
+  }
+}
+
+
+using range_t = std::pair<off_t, off_t>;
+
+// call filter->fixup_range() and return the range as a pair. this makes it easy
+// to fit on a single line for ASSERT_EQ()
+range_t fixup_range(RGWGetObj_BlockDecrypt *decrypt, off_t ofs, off_t end)
+{
+  decrypt->fixup_range(ofs, end);
+  return {ofs, end};
+}
+
+TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup)
+{
+  ut_get_sink get_sink;
+  auto nonecrypt = std::unique_ptr<BlockCrypt>(new BlockCryptNone);
+  RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink,
+                                 std::move(nonecrypt));
+  ASSERT_EQ(fixup_range(&decrypt,0,0),     range_t(0,255));
+  ASSERT_EQ(fixup_range(&decrypt,1,256),   range_t(0,511));
+  ASSERT_EQ(fixup_range(&decrypt,0,255),   range_t(0,255));
+  ASSERT_EQ(fixup_range(&decrypt,255,256), range_t(0,511));
+  ASSERT_EQ(fixup_range(&decrypt,511,1023), range_t(256,1023));
+  ASSERT_EQ(fixup_range(&decrypt,513,1024), range_t(512,1024+255));
+}
+
+
+TEST(TestRGWCrypto, verify_RGWPutObj_BlockEncrypt_chunks)
+{
+  //create some input for encryption
+  const off_t test_range = 1024*1024;
+  bufferptr buf(test_range);
+  char* p = buf.c_str();
+  for(size_t i = 0; i < buf.length(); i++)
+    p[i] = i + i*i + (i >> 2);
+
+  bufferlist input;
+  input.append(buf);
+
+  uint8_t key[32];
+  for(size_t i=0;i<sizeof(key);i++)
+    key[i] = i;
+
+  for (off_t r = 93; r < 150; r++ )
+  {
+    ut_put_sink put_sink;
+    auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+    ASSERT_NE(cbc.get(), nullptr);
+    RGWPutObj_BlockEncrypt encrypt(g_ceph_context, &put_sink,
+                                   std::move(cbc) );
+
+    off_t test_size = (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - 1) + 1;
+    off_t pos = 0;
+    do
+    {
+      off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16);
+      size = (pos + 1117) * (pos + 2229) % size + 1;
+      if (pos + size > test_size)
+        size = test_size - pos;
+
+      bufferlist bl;
+      bl.append(input.c_str()+pos, size);
+      void* handle;
+      bool again = false;
+      rgw_raw_obj ro;
+      encrypt.handle_data(bl, 0, &handle, nullptr, &again);
+      encrypt.throttle_data(handle, ro, size, false);
+
+      pos = pos + size;
+    } while (pos < test_size);
+    bufferlist bl;
+    void* handle;
+    bool again = false;
+    encrypt.handle_data(bl, 0, &handle, nullptr, &again);
+
+    ASSERT_EQ(put_sink.get_sink().length(), static_cast<size_t>(test_size));
+
+    cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32);
+    ASSERT_NE(cbc.get(), nullptr);
+
+    bufferlist encrypted;
+    bufferlist decrypted;
+    encrypted.append(put_sink.get_sink());
+    ASSERT_TRUE(cbc->decrypt(encrypted, 0, test_size, decrypted, 0));
+
+    ASSERT_EQ(decrypted.length(), test_size);
+    ASSERT_EQ(boost::string_ref(decrypted.c_str(), test_size),
+              boost::string_ref(input.c_str(), test_size));
+  }
+}
+
+
+TEST(TestRGWCrypto, verify_Encrypt_Decrypt)
+{
+  uint8_t key[32];
+  for(size_t i=0;i<sizeof(key);i++)
+    key[i]=i;
+
+  size_t fi_a = 0;
+  size_t fi_b = 1;
+  size_t test_size;
+  do
+  {
+    //fibonacci
+    size_t tmp = fi_b;
+    fi_b = fi_a + fi_b;
+    fi_a = tmp;
+
+    test_size = fi_b;
+
+    uint8_t* test_in = new uint8_t[test_size];
+    //fill with something
+    memset(test_in, test_size & 0xff, test_size);
+
+    ut_put_sink put_sink;
+    RGWPutObj_BlockEncrypt encrypt(g_ceph_context, &put_sink,
+                                  AES_256_CBC_create(g_ceph_context, &key[0], 32) );
+    bufferlist bl;
+    bl.append((char*)test_in, test_size);
+    void* handle;
+    bool again = false;
+    rgw_raw_obj ro;
+    encrypt.handle_data(bl, 0, &handle, nullptr, &again);
+    encrypt.throttle_data(handle, ro, test_size, false);
+    bl.clear();
+    encrypt.handle_data(bl, 0, &handle, nullptr, &again);
+    ASSERT_EQ(put_sink.get_sink().length(), test_size);
+
+    bl.append(put_sink.get_sink().data(), put_sink.get_sink().length());
+    ASSERT_EQ(bl.length(), test_size);
+
+    ut_get_sink get_sink;
+    RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink,
+                                   AES_256_CBC_create(g_ceph_context, &key[0], 32) );
+
+    off_t bl_ofs = 0;
+    off_t bl_end = test_size - 1;
+    decrypt.fixup_range(bl_ofs, bl_end);
+    decrypt.handle_data(bl, 0, bl.length());
+    decrypt.flush();
+    ASSERT_EQ(get_sink.get_sink().length(), test_size);
+    ASSERT_EQ(get_sink.get_sink(), boost::string_ref((char*)test_in,test_size));
+  }
+  while (test_size < 20000);
+}
+
+
+int main(int argc, char **argv) {
+  vector<const char*> args;
+  argv_to_vec(argc, (const char **)argv, args);
+
+  auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0);
+  common_init_finish(g_ceph_context);
+
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+