summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Makefile.am24
-rw-r--r--cpp/src/cluster.mk11
-rw-r--r--cpp/src/qpid/cluster/Cpg.cpp62
-rw-r--r--cpp/src/qpid/cluster/Cpg.h122
-rw-r--r--cpp/src/tests/Makefile.am14
-rw-r--r--cpp/src/tests/README2
-rwxr-xr-xcpp/src/tests/ais_unit_tests2
-rw-r--r--cpp/src/tests/cluster.mk23
-rwxr-xr-xcpp/src/tests/run-python-tests0
-rw-r--r--cpp/src/tests/unit/Cpg.cpp97
-rw-r--r--cpp/src/tests/unit/logging.cpp1
-rw-r--r--cpp/src/tests/unit/test_tools.h2
12 files changed, 344 insertions, 16 deletions
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index abc081a6a5..02044be01b 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -103,6 +103,10 @@ endif
lib_LTLIBRARIES = libqpidcommon.la libqpidbroker.la libqpidclient.la
+if CLUSTER
+include cluster.mk
+endif
+
# The logger library uses boost::date_time to format time.
# We have to disable the unused parameters warning to get around
# unused parameters in boost::date_time headers. So we build it
@@ -209,16 +213,16 @@ libqpidbroker_la_SOURCES = \
libqpidclient_la_LIBADD = libqpidcommon.la
libqpidclient_la_SOURCES = \
- qpid/client/ClientConnection.cpp \
- qpid/client/ClientChannel.cpp \
- qpid/client/ClientExchange.cpp \
- qpid/client/ClientQueue.cpp \
- qpid/client/BasicMessageChannel.cpp \
- qpid/client/MessageMessageChannel.cpp \
- qpid/client/Connector.cpp \
- qpid/client/IncomingMessage.cpp \
- qpid/client/MessageListener.cpp \
- qpid/client/ResponseHandler.cpp \
+ qpid/client/ClientConnection.cpp \
+ qpid/client/ClientChannel.cpp \
+ qpid/client/ClientExchange.cpp \
+ qpid/client/ClientQueue.cpp \
+ qpid/client/BasicMessageChannel.cpp \
+ qpid/client/MessageMessageChannel.cpp \
+ qpid/client/Connector.cpp \
+ qpid/client/IncomingMessage.cpp \
+ qpid/client/MessageListener.cpp \
+ qpid/client/ResponseHandler.cpp \
qpid/client/ReturnedMessageHandler.cpp
nobase_include_HEADERS = \
diff --git a/cpp/src/cluster.mk b/cpp/src/cluster.mk
new file mode 100644
index 0000000000..3658ee91b5
--- /dev/null
+++ b/cpp/src/cluster.mk
@@ -0,0 +1,11 @@
+#-*-Makefile-*-
+# Cluster library makefile fragment, to be included in Makefile.am
+#
+
+lib_LTLIBRARIES += libqpidcluster.la
+
+libqpidcluster_la_SOURCES = \
+ qpid/cluster/Cpg.cpp \
+ qpid/cluster/Cpg.h
+
+libqpidcluster_la_LIBADD= -lcpg
diff --git a/cpp/src/qpid/cluster/Cpg.cpp b/cpp/src/qpid/cluster/Cpg.cpp
new file mode 100644
index 0000000000..858d25f37c
--- /dev/null
+++ b/cpp/src/qpid/cluster/Cpg.cpp
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Cpg.h"
+
+namespace qpid {
+namespace cluster {
+
+using namespace std;
+
+string Cpg::errorStr(cpg_error_t err, const std::string& msg) {
+ switch (err) {
+ case CPG_OK: return msg+": ok";
+ case CPG_ERR_LIBRARY: return msg+": library";
+ case CPG_ERR_TIMEOUT: return msg+": timeout";
+ case CPG_ERR_TRY_AGAIN: return msg+": try again";
+ case CPG_ERR_INVALID_PARAM: return msg+": invalid param";
+ case CPG_ERR_NO_MEMORY: return msg+": no memory";
+ case CPG_ERR_BAD_HANDLE: return msg+": bad handle";
+ case CPG_ERR_ACCESS: return msg+": access";
+ case CPG_ERR_NOT_EXIST: return msg+": not exist";
+ case CPG_ERR_EXIST: return msg+": exist";
+ case CPG_ERR_NOT_SUPPORTED: return msg+": not supported";
+ case CPG_ERR_SECURITY: return msg+": security";
+ case CPG_ERR_TOO_MANY_GROUPS: return msg+": too many groups";
+ default:
+ assert(0);
+ return ": unknown";
+ };
+}
+
+std::string Cpg::cantJoinMsg(const Name& group) {
+ return "Cannot join CPG group "+group.str();
+}
+
+std::string Cpg::cantLeaveMsg(const Name& group) {
+ return "Cannot leave CPG group "+group.str();
+}
+
+std::string Cpg::cantMcastMsg(const Name& group) {
+ return "Cannot mcast to CPG group "+group.str();
+}
+
+}} // namespace qpid::cpg
+
+
+
diff --git a/cpp/src/qpid/cluster/Cpg.h b/cpp/src/qpid/cluster/Cpg.h
new file mode 100644
index 0000000000..6e61fa8a6e
--- /dev/null
+++ b/cpp/src/qpid/cluster/Cpg.h
@@ -0,0 +1,122 @@
+#ifndef CPG_H
+#define CPG_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdexcept>
+#include <cassert>
+#ifdef CLUSTER
+extern "C" {
+#include <openais/cpg.h>
+}
+#endif
+namespace qpid {
+namespace cluster {
+
+/**
+ * Lightweight C++ interface to cpg.h operations.
+ * Manages a single CPG handle, initialized in ctor, finialzed in destructor.
+ * On error all functions throw Cpg::Exception
+ */
+class Cpg {
+ public:
+ // FIXME aconway 2007-06-01: qpid::Exception
+ struct Exception : public std::runtime_error {
+ Exception(const std::string& msg) : runtime_error(msg) {}
+ };
+
+ struct Name : public cpg_name {
+ Name(const char* s) { copy(s, strlen(s)); }
+ Name(const char* s, size_t n) { copy(s,n); }
+ Name(const std::string& s) { copy(s.data(), s.size()); }
+ void copy(const char* s, size_t n) {
+ assert(n < CPG_MAX_NAME_LENGTH);
+ memcpy(value, s, n);
+ length=n;
+ }
+
+ std::string str() const { return std::string(value, length); }
+ };
+
+ static inline std::string str(const cpg_name& n) {
+ return std::string(n.value, n.length);
+ }
+
+ // TODO aconway 2007-06-01: when cpg handle supports a context pointer
+ // use callback objects (boost::function) instead of free functions.
+ //
+ /** Open a CPG handle.
+ *@param deliver - free function called when a message is delivered.
+ *@param reconfig - free function called when CPG configuration changes.
+ */
+ Cpg(cpg_deliver_fn_t deliver, cpg_confchg_fn_t reconfig) {
+ cpg_callbacks_t callbacks = { deliver, reconfig };
+ check(cpg_initialize(&handle, &callbacks), "Cannot initialize CPG");
+ }
+
+ /** Disconnect */
+ ~Cpg() {
+ check(cpg_finalize(handle), "Cannot finalize CPG");
+ }
+
+ /** Dispatch CPG events.
+ *@param type one of
+ * - CPG_DISPATCH_ONE - dispatch exactly one event.
+ * - CPG_DISPATCH_ALL - dispatch all available events, don't wait.
+ * - CPG_DISPATCH_BLOCKING - blocking dispatch loop.
+ */
+ void dispatch(cpg_dispatch_t type) {
+ check(cpg_dispatch(handle,type), "Error in CPG dispatch");
+ }
+
+ void join(const Name& group) {
+ check(cpg_join(handle, const_cast<Name*>(&group)),cantJoinMsg(group));
+ };
+
+ void leave(const Name& group) {
+ check(cpg_leave(handle,const_cast<Name*>(&group)),cantLeaveMsg(group));
+ }
+
+ void mcast(const Name& group, const iovec* iov, int iovLen) {
+ check(cpg_mcast_joined(
+ handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen),
+ cantMcastMsg(group));
+ }
+
+ private:
+ static std::string errorStr(cpg_error_t err, const std::string& msg);
+ static std::string cantJoinMsg(const Name&);
+ static std::string cantLeaveMsg(const Name&);
+ static std::string cantMcastMsg(const Name&);
+
+ static void check(cpg_error_t result, const std::string& msg) {
+ // TODO aconway 2007-06-01: Logging and exceptions.
+ if (result != CPG_OK)
+ throw Exception(errorStr(result, msg));
+ }
+ cpg_handle_t handle;
+};
+
+
+
+}} // namespace qpid::cluster
+
+
+
+#endif /*!CPG_H*/
diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am
index c351408988..9649ce354f 100644
--- a/cpp/src/tests/Makefile.am
+++ b/cpp/src/tests/Makefile.am
@@ -1,14 +1,19 @@
AM_CXXFLAGS = $(WARNING_CFLAGS) $(CPPUNIT_CXXFLAGS) $(APR_CXXFLAGS)
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
-
-# Unit test programs
+#
+# Unit test programs.
+#
UNIT_TESTS=
UNIT_TESTS+=logging
logging_SOURCES=unit/logging.cpp unit/test_tools.h
logging_LDADD=-lboost_unit_test_framework -lboost_regex $(lib_common)
+if CLUSTER
+include cluster.mk
+endif
+
# NB: CppUnit test libraries below will be migrated to boost test programs.
# UNIT_TESTS+= ...
@@ -63,7 +68,8 @@ testprogs = \
topic_listener \
topic_publisher
-check_PROGRAMS = $(UNIT_TESTS) $(testprogs) interop_runner
+
+check_PROGRAMS = $(UNIT_TESTS) $(AIS_UNIT_TESTS) $(testprogs) interop_runner
# FIXME aconway 2007-05-30: TESTS_ENVIRONMENT should have ./run_test
# as below to run valgrind on all test programs.
@@ -73,7 +79,7 @@ check_PROGRAMS = $(UNIT_TESTS) $(testprogs) interop_runner
TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir)
SYSTEM_TESTS = client_test quick_topictest
-TESTS = $(UNIT_TESTS) run-unit-tests start_broker $(SYSTEM_TESTS) python_tests kill_broker daemon_test
+TESTS = $(UNIT_TESTS) run-unit-tests $(RUN_AIS_TESTS) start_broker $(SYSTEM_TESTS) python_tests kill_broker daemon_test
EXTRA_DIST = \
test_env \
diff --git a/cpp/src/tests/README b/cpp/src/tests/README
index d0552a2ddd..2501ba1f21 100644
--- a/cpp/src/tests/README
+++ b/cpp/src/tests/README
@@ -57,7 +57,7 @@ They are listed in the TESTS make variable, which can be over-ridden.
The ./start_broker "test" launches the broker, ./kill_broker" kills it.
Tests in between assume the broker is running.
-./run-python-tests: runs ../python/run_tests. This is the main set of
+./python_tests: runs ../python/run_tests. This is the main set of
system testss for the broker.
Other C++ client test executables and scripts under client/test are
diff --git a/cpp/src/tests/ais_unit_tests b/cpp/src/tests/ais_unit_tests
new file mode 100755
index 0000000000..9758891891
--- /dev/null
+++ b/cpp/src/tests/ais_unit_tests
@@ -0,0 +1,2 @@
+#!/bin/sh
+make check-ais
diff --git a/cpp/src/tests/cluster.mk b/cpp/src/tests/cluster.mk
new file mode 100644
index 0000000000..489eec748e
--- /dev/null
+++ b/cpp/src/tests/cluster.mk
@@ -0,0 +1,23 @@
+#-*-Makefile-*-
+# Cluster tests makefile fragment, to be included in Makefile.am
+#
+
+lib_cluster = $(abs_builddir)/../libqpidcluster.la
+#
+# AIS_UNIT_TESTS must be called with gid=ais. They are run
+# separately under sudo -u ais.
+#
+AIS_UNIT_TESTS=
+
+AIS_UNIT_TESTS+=Cpg
+Cpg_SOURCES=unit/Cpg.cpp
+Cpg_LDADD=-lboost_unit_test_framework $(lib_cluster)
+
+RUN_AIS_TESTS=ais_unit_tests # Run ais unit tests via check-ais.
+
+# The chmod is a horrible hack to allow libtools annoying wrapers to
+# relink the executable when run as user ais.
+check-ais: $(AIS_UNIT_TESTS)
+ chmod a+rwx . .libs
+ sudo -u ais $(MAKE) check TESTS=$(AIS_UNIT_TESTS)
+
diff --git a/cpp/src/tests/run-python-tests b/cpp/src/tests/run-python-tests
deleted file mode 100755
index e69de29bb2..0000000000
--- a/cpp/src/tests/run-python-tests
+++ /dev/null
diff --git a/cpp/src/tests/unit/Cpg.cpp b/cpp/src/tests/unit/Cpg.cpp
new file mode 100644
index 0000000000..74c6532338
--- /dev/null
+++ b/cpp/src/tests/unit/Cpg.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define BOOST_AUTO_TEST_MAIN // Must come before #include<boost/test/*>
+#include "test_tools.h"
+#include "qpid/cluster/Cpg.h"
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <algorithm>
+
+using namespace std;
+using namespace qpid::cluster;
+
+// For debugging: op << for CPG types.
+
+ostream& operator<<(ostream& o, const cpg_name* n) {
+ return o << qpid::cluster::Cpg::str(*n);
+}
+
+ostream& operator<<(ostream& o, const cpg_address& a) {
+ return o << "(" << a.nodeid <<","<<a.pid<<","<<a.reason<<")";
+}
+
+template <class T>
+ostream& operator<<(ostream& o, const pair<T*, int>& array) {
+ o << "{ ";
+ ostream_iterator<cpg_address> i(o, " ");
+ copy(array.first, array.first+array.second, i);
+ cout << "}";
+ return o;
+}
+
+const string testGroup("foo");
+vector<string> delivered;
+vector<int> configChanges;
+
+void testDeliver (
+ cpg_handle_t /*handle*/,
+ struct cpg_name *group,
+ uint32_t /*nodeid*/,
+ uint32_t /*pid*/,
+ void* msg,
+ int msg_len)
+{
+ BOOST_CHECK_EQUAL(testGroup, Cpg::str(*group));
+ delivered.push_back(string((char*)msg,msg_len));
+}
+
+void testConfigChange(
+ cpg_handle_t /*handle*/,
+ struct cpg_name *group,
+ struct cpg_address */*members*/, int nMembers,
+ struct cpg_address */*left*/, int /*nLeft*/,
+ struct cpg_address */*joined*/, int /*nJoined*/
+)
+{
+ BOOST_CHECK_EQUAL(testGroup, Cpg::str(*group));
+ configChanges.push_back(nMembers);
+}
+
+BOOST_AUTO_TEST_CASE(basic) {
+ // Verify basic functionality of cpg. This will catch any
+ // openais configuration or permission errors.
+ //
+ Cpg cpg(&testDeliver, &testConfigChange);
+ Cpg::Name group("foo");
+
+ cpg.join(group);
+ iovec iov = { (void*)"Hello!", 6 };
+ cpg.mcast(group, &iov, 1);
+ cpg.leave(group);
+
+ cpg.dispatch(CPG_DISPATCH_ONE); // Wait for at least one.
+ cpg.dispatch(CPG_DISPATCH_ALL);
+ BOOST_REQUIRE_EQUAL(1u, delivered.size());
+ BOOST_CHECK_EQUAL("Hello!", delivered.front());
+ BOOST_REQUIRE_EQUAL(2u, configChanges.size());
+ BOOST_CHECK_EQUAL(1, configChanges[0]);
+ BOOST_CHECK_EQUAL(0, configChanges[1]);
+}
diff --git a/cpp/src/tests/unit/logging.cpp b/cpp/src/tests/unit/logging.cpp
index 3dbe68ad2b..c80bf7b337 100644
--- a/cpp/src/tests/unit/logging.cpp
+++ b/cpp/src/tests/unit/logging.cpp
@@ -16,6 +16,7 @@
*
*/
+#define BOOST_AUTO_TEST_MAIN // Must come before #include<boost/test/*>
#include "test_tools.h"
#include "qpid/log/Logger.h"
#include "qpid/log/Options.h"
diff --git a/cpp/src/tests/unit/test_tools.h b/cpp/src/tests/unit/test_tools.h
index a941cf40eb..faa198af9a 100644
--- a/cpp/src/tests/unit/test_tools.h
+++ b/cpp/src/tests/unit/test_tools.h
@@ -19,7 +19,6 @@
*
*/
-#define BOOST_AUTO_TEST_MAIN // Must come before #include<boost/test/*>
#include <boost/test/auto_unit_test.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/regex.hpp>
@@ -51,3 +50,4 @@ inline bool regexPredicate(const std::string& re, const std::string& text) {
BOOST_CHECK_PREDICATE(regexPredicate, (re)(text))
#endif /*!TEST_TOOLS_H*/
+