summaryrefslogtreecommitdiffstats
path: root/src/test/librados_test_stub/TestRadosClient.cc
diff options
context:
space:
mode:
authorJason Dillaman <dillaman@redhat.com>2014-12-02 23:40:34 +0100
committerJason Dillaman <dillaman@redhat.com>2015-01-13 10:49:32 +0100
commitc105003bd62d191f37e2738517e290008b94cda1 (patch)
tree08e2abe8121eaaa96a4f01df199d580a02cb3edd /src/test/librados_test_stub/TestRadosClient.cc
parentinclude: moved RBD's generic FunctionContext wrapper (diff)
downloadceph-c105003bd62d191f37e2738517e290008b94cda1.tar.xz
ceph-c105003bd62d191f37e2738517e290008b94cda1.zip
tests: add mock librados API for supporting unit tests
The new librados_test_stub library can be used by unit tests as a replacement for the librados shared library. The library currently provides an in-memory RADOS simulator and will allow future unit tests to be developed using mocking. Signed-off-by: Jason Dillaman <dillaman@redhat.com>
Diffstat (limited to 'src/test/librados_test_stub/TestRadosClient.cc')
-rw-r--r--src/test/librados_test_stub/TestRadosClient.cc205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/test/librados_test_stub/TestRadosClient.cc b/src/test/librados_test_stub/TestRadosClient.cc
new file mode 100644
index 00000000000..91734f21a11
--- /dev/null
+++ b/src/test/librados_test_stub/TestRadosClient.cc
@@ -0,0 +1,205 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librados_test_stub/TestRadosClient.h"
+#include "test/librados_test_stub/TestIoCtxImpl.h"
+#include "librados/AioCompletionImpl.h"
+#include "include/assert.h"
+#include "common/ceph_json.h"
+#include "common/Finisher.h"
+#include <boost/bind.hpp>
+#include <boost/thread.hpp>
+#include <errno.h>
+
+static int get_concurrency() {
+ int concurrency = 0;
+ char *env = getenv("LIBRADOS_CONCURRENCY");
+ if (env != NULL) {
+ concurrency = atoi(env);
+ }
+ if (concurrency == 0) {
+ concurrency = boost::thread::thread::hardware_concurrency();
+ }
+ if (concurrency == 0) {
+ concurrency = 1;
+ }
+ return concurrency;
+}
+
+namespace librados {
+
+static void finish_aio_completion(AioCompletionImpl *c, int r) {
+ c->lock.Lock();
+ c->ack = true;
+ c->safe = true;
+ c->rval = r;
+ c->lock.Unlock();
+
+ rados_callback_t cb_complete = c->callback_complete;
+ void *cb_complete_arg = c->callback_complete_arg;
+ if (cb_complete) {
+ cb_complete(c, cb_complete_arg);
+ }
+
+ rados_callback_t cb_safe = c->callback_safe;
+ void *cb_safe_arg = c->callback_safe_arg;
+ if (cb_safe) {
+ cb_safe(c, cb_safe_arg);
+ }
+
+ c->lock.Lock();
+ c->callback_complete = NULL;
+ c->callback_safe = NULL;
+ c->cond.Signal();
+ c->put_unlock();
+}
+
+class AioFunctionContext : public Context {
+public:
+ AioFunctionContext(const TestRadosClient::AioFunction &callback,
+ AioCompletionImpl *c)
+ : m_callback(callback), m_comp(c)
+ {
+ if (m_comp != NULL) {
+ m_comp->get();
+ }
+ }
+
+ virtual void finish(int r) {
+ int ret = m_callback();
+ if (m_comp != NULL) {
+ finish_aio_completion(m_comp, ret);
+ }
+ }
+private:
+ TestRadosClient::AioFunction m_callback;
+ AioCompletionImpl *m_comp;
+};
+
+TestRadosClient::TestRadosClient(CephContext *cct)
+ : m_cct(cct->get()),
+ m_watch_notify(m_cct)
+{
+ get();
+
+ int concurrency = get_concurrency();
+ for (int i = 0; i < concurrency; ++i) {
+ m_finishers.push_back(new Finisher(m_cct));
+ m_finishers.back()->start();
+ }
+}
+
+TestRadosClient::~TestRadosClient() {
+ flush_aio_operations();
+
+ for (size_t i = 0; i < m_finishers.size(); ++i) {
+ m_finishers[i]->stop();
+ delete m_finishers[i];
+ }
+
+ m_cct->put();
+ m_cct = NULL;
+}
+
+void TestRadosClient::get() {
+ m_refcount.inc();
+}
+
+void TestRadosClient::put() {
+ if (m_refcount.dec() == 0) {
+ shutdown();
+ delete this;
+ }
+}
+
+CephContext *TestRadosClient::cct() {
+ return m_cct;
+}
+
+uint64_t TestRadosClient::get_instance_id() {
+ return 0;
+}
+
+int TestRadosClient::connect() {
+ return 0;
+}
+
+void TestRadosClient::shutdown() {
+}
+
+int TestRadosClient::wait_for_latest_osdmap() {
+ return 0;
+}
+
+int TestRadosClient::mon_command(const std::vector<std::string>& cmd,
+ const bufferlist &inbl,
+ bufferlist *outbl, std::string *outs) {
+ for (std::vector<std::string>::const_iterator it = cmd.begin();
+ it != cmd.end(); ++it) {
+ JSONParser parser;
+ if (!parser.parse(it->c_str(), it->length())) {
+ return -EINVAL;
+ }
+
+ JSONObjIter j_it = parser.find("prefix");
+ if (j_it.end()) {
+ return -EINVAL;
+ }
+
+ if ((*j_it)->get_data() == "osd tier add") {
+ return 0;
+ } else if ((*j_it)->get_data() == "osd tier cache-mode") {
+ return 0;
+ } else if ((*j_it)->get_data() == "osd tier set-overlay") {
+ return 0;
+ } else if ((*j_it)->get_data() == "osd tier remove-overlay") {
+ return 0;
+ } else if ((*j_it)->get_data() == "osd tier remove") {
+ return 0;
+ }
+ }
+ return -ENOSYS;
+}
+
+void TestRadosClient::add_aio_operation(const std::string& oid,
+ const AioFunction &aio_function,
+ AioCompletionImpl *c) {
+ AioFunctionContext *ctx = new AioFunctionContext(aio_function, c);
+ get_finisher(oid)->queue(ctx);
+}
+
+struct WaitForFlush {
+ int flushed() {
+ if (count.dec() == 0) {
+ if (c != NULL) {
+ finish_aio_completion(c, 0);
+ }
+ delete this;
+ }
+ return 0;
+ }
+
+ atomic_t count;
+ AioCompletionImpl *c;
+};
+
+void TestRadosClient::flush_aio_operations() {
+ AioCompletionImpl *comp = new AioCompletionImpl();
+ flush_aio_operations(comp);
+ comp->wait_for_safe();
+ comp->put();
+}
+
+void TestRadosClient::flush_aio_operations(AioCompletionImpl *c) {
+ WaitForFlush *wait_for_flush = new WaitForFlush();
+ wait_for_flush->count.set(m_finishers.size());
+ wait_for_flush->c = c;
+ add_aio_operation("", boost::bind(&WaitForFlush::flushed, wait_for_flush), NULL);
+}
+
+Finisher *TestRadosClient::get_finisher(const std::string &oid) {
+ std::size_t h = m_hash(oid);
+ return m_finishers[h % m_finishers.size()];
+}
+
+} // namespace librados