[asterisk-scf-commits] asterisk-scf/integration/ice-util-c++.git branch "master" created.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Thu Oct 14 17:24:04 CDT 2010
branch "master" has been created
at 1316c30cb230c1a54c08e5cc76290359d73bef89 (commit)
- Log -----------------------------------------------------------------
commit 1316c30cb230c1a54c08e5cc76290359d73bef89
Author: Mark Michelson <mmichelson at digium.com>
Date: Thu Oct 14 17:18:06 2010 -0500
Adding ProxyWrapper and StateReplicator initial code for this repo.
diff --git a/ProxyWrapper/CMakeLists.txt b/ProxyWrapper/CMakeLists.txt
new file mode 100644
index 0000000..cdfa251
--- /dev/null
+++ b/ProxyWrapper/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# Asterisk Scalable Communications Framework
+#
+# Copyright (C) 2010 -- Digium, Inc.
+#
+# All rights reserved.
+#
+
+# State Replicator build system
+
+if(NOT integrated_build STREQUAL "true")
+
+ # Minimum we require is 2.6
+ cmake_minimum_required(VERSION 2.6)
+
+ # Include common Hydra build infrastructure. Make sure your submodules are pulled.
+ include(cmake/AsteriskSCF.cmake)
+
+ # This project is C++ based and requires a minimum of 3.4 of Ice.
+ hydra_project(SipChannelService 3.4 CXX)
+
+ # Pull in the slice definitions
+ #add_subdirectory(slice)
+
+endif()
+
+add_subdirectory(src)
diff --git a/ProxyWrapper/src/CMakeLists.txt b/ProxyWrapper/src/CMakeLists.txt
new file mode 100644
index 0000000..039fdfd
--- /dev/null
+++ b/ProxyWrapper/src/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Define the SIP Channel Service component
+
+hydra_component_init(ProxyWrapper CXX)
+
+hydra_component_add_file(ProxyWrapper ProxyWrapper.h)
+hydra_component_add_file(ProxyWrapper ProxyWrapper.cpp)
+
+hydra_component_build_library(ProxyWrapper)
+
+# MACH-O requires libraries for linking libraries
+if(APPLE)
+ target_link_libraries(ProxyWrapper ${ICE_CXX_LIB_IceUtil})
+ target_link_libraries(ProxyWrapper ${ICE_CXX_LIB_ZeroCIce})
+endif()
+
+hydra_component_install(ProxyWrapper LIBRARY lib "Proxy Wrapper" ProxyWrapper ARCHIVE DESTINATION lib)
+
diff --git a/ProxyWrapper/src/ProxyWrapper.cpp b/ProxyWrapper/src/ProxyWrapper.cpp
new file mode 100644
index 0000000..df206ad
--- /dev/null
+++ b/ProxyWrapper/src/ProxyWrapper.cpp
@@ -0,0 +1,20 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+#include "ProxyWrapper.h"
+
+namespace AsteriskSCF
+{
+namespace SipChannelService
+{
+ /*
+ * This .cpp is a temporary solution to get a CMakeProject that consists only of header files.
+ */
+
+};
+};
diff --git a/ProxyWrapper/src/ProxyWrapper.h b/ProxyWrapper/src/ProxyWrapper.h
new file mode 100644
index 0000000..6bc7e0c
--- /dev/null
+++ b/ProxyWrapper/src/ProxyWrapper.h
@@ -0,0 +1,154 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#pragma once
+
+#include <Ice/Ice.h>
+#include <boost/shared_ptr.hpp>
+
+#include "Core/Discovery/ServiceLocatorIf.h"
+
+namespace AsteriskSCF
+{
+namespace SipChannelService
+{
+
+/**
+ * A wrapper for an Ice Proxy.
+ * The Template parameter P is the proxy we're wrapping
+ *
+ * The main feature of using a proxy wrapper at this stage is that
+ * it provides the ability to detect if we could find a given proxy
+ * at initialization. If we did not, then the first time we try to
+ * invoke a proxy operation, then we will attempt to acquire a proxy
+ * a second time via the service locator.
+ *
+ * An improvement that would be nice would be to make the recovery
+ * more general purpose. There are a couple of ways to try this.
+ *
+ * 1. Always ice_ping as the first operation of the -> operator
+ * overload. This way we can be sure that the servant we are trying
+ * to talk to is still reachable. If it's not, then we may be able to
+ * ask the service locator for a new proxy and proceed. The advantage
+ * to this method is that we only ping proxies when we need them. The
+ * disadvantage is that we add an extra RPC for each proxy operation.
+ *
+ * 2. Have a background thread that periodically ice_pings all wrapped
+ * proxies. This thread can be responsible for alerting a proxy wrapper
+ * to try to get a new proxy if one is unreachable. The advantage here is
+ * that for RPC-heavy operations, we're not doubling the amount of RPCs
+ * by pinging every time. The disadvantage is that we could be needlessly
+ * pinging servants for essentially dormant services.
+ */
+template <class P>
+class ProxyWrapper
+{
+public:
+ ProxyWrapper() : mServiceLocator(0), mLocatorParams(0), mInitialized(false) {}
+
+ ProxyWrapper(const ProxyWrapper &pw)
+ {
+ copy(pw);
+ }
+
+ ProxyWrapper(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
+ AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params)
+ : mServiceLocator(locator), mLocatorParams(params), mInitialized(false)
+ {
+ initialize();
+ }
+
+ P& operator->()
+ {
+ assert(mServiceLocator && mLocatorParams);
+
+ if (!verifyInitialized())
+ {
+ throw "No access to Proxy";
+ }
+
+ return mProxy;
+ }
+
+ ProxyWrapper operator=(const ProxyWrapper &pw)
+ {
+ // Boo to self-assignment
+ if (this == &pw)
+ {
+ return *this;
+ }
+ copy(pw);
+ return *this;
+ }
+
+ operator void*() const
+ {
+ return mProxy ? (void *)1 : 0;
+ }
+
+ bool isInitialized()
+ {
+ return mInitialized;
+ }
+
+private:
+ /**
+ * Initialization. Primarily involves acquring access to specific IceStorm topic.
+ */
+ void initialize()
+ {
+ try
+ {
+ // Use the locator to find the Proxy
+ Ice::ObjectPrx bridgeManagerObject = mServiceLocator->locate(mLocatorParams);
+ mProxy = P::checkedCast(bridgeManagerObject);
+ }
+ catch (const Ice::Exception &e)
+ {
+ std::cout << "Exception locating " << mLocatorParams->category << ": " << e.what() << std::endl;
+ return;
+ }
+
+ if (mProxy == 0)
+ {
+ std::cout << "Unable to locate " << mLocatorParams->category << std::endl;
+ }
+
+ mInitialized = true;
+ }
+
+ /**
+ * Utiltity to check for initialization state.
+ */
+ bool verifyInitialized()
+ {
+ if (mInitialized)
+ {
+ return true;
+ }
+
+ // Try again to initialize.
+ initialize();
+ return mInitialized;
+ }
+
+ void copy(const ProxyWrapper &pw)
+ {
+ mServiceLocator = pw.mServiceLocator;
+ mLocatorParams = pw.mLocatorParams;
+ mProxy = pw.mProxy;
+ mInitialized = pw.mInitialized;
+ }
+
+ P mProxy;
+ AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
+ AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr mLocatorParams;
+ bool mInitialized;
+};
+
+}; // end SipChannelService
+}; // end AsteriskSCF
diff --git a/StateReplicator/CMakeLists.txt b/StateReplicator/CMakeLists.txt
new file mode 100644
index 0000000..69bf862
--- /dev/null
+++ b/StateReplicator/CMakeLists.txt
@@ -0,0 +1,30 @@
+#
+# Asterisk Scalable Communications Framework
+#
+# Copyright (C) 2010 -- Digium, Inc.
+#
+# All rights reserved.
+#
+
+# State Replicator build system
+
+if(NOT integrated_build STREQUAL "true")
+
+ # Minimum we require is 2.6
+ cmake_minimum_required(VERSION 2.6)
+
+ # Include common Hydra build infrastructure. Make sure your submodules are pulled.
+ include(cmake/AsteriskSCF.cmake)
+
+ # This project is C++ based and requires a minimum of 3.4 of Ice.
+ hydra_project(SipChannelService 3.4 CXX)
+
+ # Pull in the slice definitions
+ #add_subdirectory(slice)
+
+endif()
+
+add_subdirectory(src)
+add_subdirectory(testslice)
+add_subdirectory(test)
+
diff --git a/StateReplicator/src/CMakeLists.txt b/StateReplicator/src/CMakeLists.txt
new file mode 100644
index 0000000..725040f
--- /dev/null
+++ b/StateReplicator/src/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Define the SIP Channel Service component
+
+hydra_component_init(StateReplicator CXX)
+
+hydra_component_add_file(StateReplicator StateReplicator.h)
+hydra_component_add_file(StateReplicator StateReplicator.cpp)
+
+hydra_component_build_library(StateReplicator)
+
+# MACH-O requires libraries for linking libraries
+if(APPLE)
+ target_link_libraries(StateReplicator ${ICE_CXX_LIB_IceUtil})
+ target_link_libraries(StateReplicator ${ICE_CXX_LIB_ZeroCIce})
+endif()
+
+hydra_component_install(StateReplicator LIBRARY lib "State Replicator" statereplicator ARCHIVE DESTINATION lib)
+
diff --git a/StateReplicator/src/StateReplicator.cpp b/StateReplicator/src/StateReplicator.cpp
new file mode 100644
index 0000000..fc7f541
--- /dev/null
+++ b/StateReplicator/src/StateReplicator.cpp
@@ -0,0 +1,22 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+#include <IceUtil/UUID.h>
+
+#include "StateReplicator.h"
+
+namespace AsteriskSCF
+{
+namespace StateReplication
+{
+ /*
+ * This .cpp is a temporary solution to get a CMakeProject that consists only of header files.
+ */
+
+};
+};
diff --git a/StateReplicator/src/StateReplicator.h b/StateReplicator/src/StateReplicator.h
new file mode 100644
index 0000000..fc0233b
--- /dev/null
+++ b/StateReplicator/src/StateReplicator.h
@@ -0,0 +1,239 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#pragma once
+
+#include <Ice/Ice.h>
+
+namespace AsteriskSCF
+{
+namespace StateReplication
+{
+
+/**
+ * Templatization of a state replicator. This particular implementation preserves the order
+ * of the fields from the order in which they were added to the collection. If an item is removed and
+ * re-added later, it goes to the back of the list.
+ * - The state item type is assumed to have a public field named "key" which is of type "K".
+
+ The Replicator should implement (at a minimum) these operations:
+ interface FooStateReplicator
+ {
+ void addListener(TestStateReplicatorListener *listener);
+ void removeListener(TestStateReplicatorListener *listener);
+ void setState (FooStateItemSeq items);
+ void removeState(FooKeySeq items);
+ idempotent TestStateItemSeq getState(FooKeySeq itemKeys);
+ idempotent TestStateItemSeq getAllState();
+ };
+
+ The Listener should implement (at a minimum) these operations:
+ interface FooStateReplicatorListener
+ {
+ void stateRemoved(FooKeySeq itemKeys);
+ void stateSet(FooStateItemSeq items);
+ };
+
+ * NOTE: - The process should be made asynchronous.
+ * NOTE: - Should probably use IceStorm for forwarding to all listeners.
+ */
+template<typename R, typename S, typename K, typename L>
+class StateReplicator : public R
+{
+// Template Types: R - Replicator, S - State item, K - Key element, L - Listener
+public:
+ /**
+ * Functor for forwarding setState() notices.
+ */
+ template<typename T, typename U> class SetStateNotice
+ {
+ // Types: T - Listener type, U - State Item seq.
+ public:
+ SetStateNotice(const U& stateSeq) : mStateSeq(stateSeq) {}
+ ~SetStateNotice() {}
+ void operator() (T x) {x->stateSet(mStateSeq);}
+ U mStateSeq;
+ };
+
+ /**
+ * Functor for forwarding removeState() notices.
+ */
+ template<typename T, typename V> class RemoveStateNotice
+ {
+ // Types: T - Listener type, V - Key Item seq.
+ public:
+ RemoveStateNotice(const V& keys) : mKeys(keys) {}
+ ~RemoveStateNotice() {}
+ void operator() (T x) {x->stateRemoved(mKeys);}
+ V mKeys;
+ };
+
+ /**
+ * Functor to use as find_if predicate.
+ */
+ template<typename T> class IdentifyListener
+ {
+ public:
+ IdentifyListener(const T& listener) : mListener(listener) {}
+ ~IdentifyListener() {}
+ bool operator() (T x) {return (x->ice_getIdentity() == mListener->ice_getIdentity());}
+ T mListener;
+ };
+
+ template<typename T, typename D> class MatchItem
+ {
+ public:
+ MatchItem(const D& key) : mKey(key) {}
+ ~MatchItem() {}
+ bool operator() (T x) {return (x->key == mKey); }
+ D mKey;
+ };
+
+public:
+ StateReplicator() {};
+ virtual ~StateReplicator() {};
+
+ /**
+ * Adds a listener of state update notices.
+ * @Override
+ */
+ void addListener(const L& listener, const Ice::Current& = ::Ice::Current())
+ {
+ mListeners.push_back(listener);
+
+ // Give this listener the current state.
+ listener->stateSet(mStateItems);
+ }
+
+ /**
+ * Removes a listener of state update notices.
+ * @Override
+ */
+ void removeListener(const L& listener, const Ice::Current& = ::Ice::Current())
+ {
+ typename std::vector<L>::iterator it = std::find_if(mListeners.begin(), mListeners.end(), IdentifyListener<L>(listener));
+
+ if (it != mListeners.end())
+ {
+ mListeners.erase(it);
+ }
+ }
+
+ /**
+ * Drops all listeners of state update notices.
+ */
+ void clearListeners()
+ {
+ mListeners.clear();
+ }
+
+ /**
+ * Drops all state that has previously been set. Notifies listeners.
+ */
+ void clearState()
+ {
+ std::vector<K> allIds;
+
+ for(typename std::vector<S>::const_iterator it = mStateItems.begin(); it != mStateItems.end(); ++it)
+ {
+ allIds.push_back((*it)->key);
+ }
+
+ mStateItems.clear();
+
+ for_each(mListeners.begin(), mListeners.end(), RemoveStateNotice<L,std::vector<K> >(allIds));
+ }
+
+ /**
+ * Add or update the specified state variables, and notify listeners.
+ * @Override
+ */
+ void setState(const std::vector<S>& items, const Ice::Current& = ::Ice::Current())
+ {
+ for (typename std::vector<S>::const_iterator iter = items.begin();
+ iter != items.end(); ++iter)
+ {
+ typename std::vector<S>::iterator it = std::find_if(mStateItems.begin(), mStateItems.end(), MatchItem<S,K >((*iter)->key));
+
+ if (it != mStateItems.end())
+ {
+ (*it) = (*iter);
+ }
+ else
+ {
+ mStateItems.push_back(*iter);
+ }
+ }
+
+ for_each( mListeners.begin(), mListeners.end(), SetStateNotice<L,std::vector<S> >(items) );
+ }
+
+ /**
+ * Remove the specified state variables, and notify listeners.
+ * @Override
+ */
+ void removeState(const std::vector<K>& ids, const Ice::Current& = ::Ice::Current())
+ {
+ for (typename std::vector<K>::const_iterator keyIter = ids.begin(); keyIter != ids.end(); ++keyIter)
+ {
+ typename std::vector<S>::iterator locateIt = std::find_if(mStateItems.begin(), mStateItems.end(), MatchItem<S,K >(*keyIter));
+
+ if (locateIt != mStateItems.end())
+ {
+ mStateItems.erase(locateIt);
+ }
+ }
+
+ for_each(mListeners.begin(), mListeners.end(), RemoveStateNotice<L,std::vector<K> >(ids));
+ }
+
+ /**
+ * Retrieve the state variables identifed by the key collection.
+ * @Override
+ */
+ std::vector<S> getState(const std::vector<K>& itemKeys, const Ice::Current& = ::Ice::Current())
+ {
+ std::vector<S> results;
+
+ for(typename std::vector<K>::const_iterator keyIt = itemKeys.begin(); keyIt != itemKeys.end(); ++keyIt)
+ {
+ typename std::vector<S>::iterator locateIt = std::find_if(mStateItems.begin(), mStateItems.end(), MatchItem<S,K >(*keyIt));
+
+ if (locateIt != mStateItems.end())
+ {
+ results.push_back(*locateIt);
+ }
+
+ }
+ return results;
+ }
+
+ /**
+ * Retrieve all the state variables currently known to this replicator.
+ * @Override
+ */
+ std::vector<S> getAllState(const Ice::Current& = ::Ice::Current())
+ {
+ return mStateItems;
+ }
+
+ /**
+ * Returns the number of listeners currently registered with this replicator.
+ */
+ int getListenerCount()
+ {
+ return mListeners.size();
+ }
+
+private:
+ std::vector<L> mListeners;
+ std::vector<S> mStateItems;
+
+};
+
+} // end namespace StateReplication
+} // end namespace AsteriskSCF
diff --git a/StateReplicator/test/CMakeLists.txt b/StateReplicator/test/CMakeLists.txt
new file mode 100644
index 0000000..5c7b3bc
--- /dev/null
+++ b/StateReplicator/test/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Create State Replicator Test project.
+
+hydra_component_init(StateReplicatorTest CXX)
+include_directories("../src")
+hydra_component_add_slice(StateReplicatorTest StateReplicatorTestIf)
+hydra_component_add_file(StateReplicatorTest TestStateReplicator.cpp)
+hydra_component_add_file(StateReplicatorTest SharedTestData.h)
+hydra_component_add_file(StateReplicatorTest MockStateReplicatorListener.h)
+
+hydra_component_add_boost_libraries(StateReplicatorTest unit_test_framework)
+
+hydra_component_build_standalone(StateReplicatorTest)
+hydra_component_install(StateReplicatorTest RUNTIME bin "StateReplicatorTest Component Test Driver." Test)
+
+boost_add_test(StateReplicatorTest)
diff --git a/StateReplicator/test/MockStateReplicatorListener.h b/StateReplicator/test/MockStateReplicatorListener.h
new file mode 100644
index 0000000..581d066
--- /dev/null
+++ b/StateReplicator/test/MockStateReplicatorListener.h
@@ -0,0 +1,55 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#pragma once
+
+#include <Ice/Ice.h>
+#include "StateReplicatorTestIf.h"
+
+namespace AsteriskSCF
+{
+namespace StateReplicatorTest
+{
+
+class MockStateReplicatorListenerImpl : public AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListener
+{
+public:
+ MockStateReplicatorListenerImpl() : mRemoveStateCalled(false), mSetStateCalled(true)
+ {
+ }
+
+ void stateRemoved(const ::Ice::StringSeq& itemKeys, const ::Ice::Current& )
+ {
+ mItemKeys = itemKeys;
+ mRemoveStateCalled = true;
+ }
+
+ void stateSet(const ::AsteriskSCF::StateReplicatorTest::V1::TestStateItemSeq& items, const ::Ice::Current& )
+ {
+ mStateItems = items;
+ mSetStateCalled = true;
+ }
+
+ void reset()
+ {
+ mRemoveStateCalled = false;
+ mSetStateCalled = false;
+ mStateItems.clear();
+ mItemKeys.clear();
+ }
+
+public:
+ bool mRemoveStateCalled;
+ bool mSetStateCalled;
+ AsteriskSCF::StateReplicatorTest::V1::TestStateItemSeq mStateItems;
+ Ice::StringSeq mItemKeys;
+};
+typedef ::IceInternal::ProxyHandle<MockStateReplicatorListenerImpl> MockStateReplicatorListenerImplPrx;
+typedef ::IceInternal::Handle<MockStateReplicatorListenerImpl> MockStateReplicatorListenerImplPtr;
+
+} // StateReplicatorTest
+} // AsteriskSCF
diff --git a/StateReplicator/test/SharedTestData.h b/StateReplicator/test/SharedTestData.h
new file mode 100644
index 0000000..8a93591
--- /dev/null
+++ b/StateReplicator/test/SharedTestData.h
@@ -0,0 +1,52 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#pragma once
+
+#include <Ice/Ice.h>
+#include "StateReplicatorTestIf.h"
+#include "MockStateReplicatorListener.h"
+
+namespace AsteriskSCF
+{
+namespace StateReplicatorTest
+{
+ // typedef AsteriskSCF::StateReplication::StateReplicator<AsteriskSCF::StateReplicatorTest::V1::TestStateReplicator, AsteriskSCF::StateReplicatorTest::V1::TestStateItemSeq, AsteriskSCF::StateReplicatorTest::V1::TestStateItemPtr, Ice::StringSeq, std::string, AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListenerPrx> TestReplicatorImpl;
+ typedef AsteriskSCF::StateReplication::StateReplicator<AsteriskSCF::StateReplicatorTest::V1::TestStateReplicator, AsteriskSCF::StateReplicatorTest::V1::TestStateItemPtr, std::string, AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListenerPrx> TestReplicatorImpl;
+ typedef IceUtil::Handle<TestReplicatorImpl> TestReplicatorImplPtr;
+
+/**
+ * Pseudo singleton for sharing data among test artifacts.
+ */
+class SharedTestData
+{
+public:
+ static SharedTestData instance;
+
+ // Communicator for outgoing stuff.
+ Ice::CommunicatorPtr communicator_out;
+
+ // Communicator for incoming stuff. This is where we add the test servants.
+ Ice::CommunicatorPtr communicator_in;
+
+ Ice::ObjectAdapterPtr adapter_in;
+ Ice::ObjectAdapterPtr adapter_out;
+
+ TestReplicatorImplPtr mTestReplicatorImplPtr;
+ AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorPrx mTestStateReplicatorPrx;
+
+ MockStateReplicatorListenerImplPtr mMockStateListener1Ptr;
+ MockStateReplicatorListenerImplPtr mMockStateListener2Ptr;
+ MockStateReplicatorListenerImplPtr mMockStateListener3Ptr;
+
+ AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListenerPrx mTestStateListener1Prx;
+ AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListenerPrx mTestStateListener2Prx;
+ AsteriskSCF::StateReplicatorTest::V1::TestStateReplicatorListenerPrx mTestStateListener3Prx;
+};
+
+}; // StateReplicatorTest
+}; // AsteriskSCF
diff --git a/StateReplicator/test/TestStateReplicator.cpp b/StateReplicator/test/TestStateReplicator.cpp
new file mode 100644
index 0000000..d121ca2
--- /dev/null
+++ b/StateReplicator/test/TestStateReplicator.cpp
@@ -0,0 +1,477 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE StateReplicatorComponentTestSuite
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/debug.hpp>
+
+#include <Ice/Ice.h>
+
+#include "StateReplicatorTestIf.h"
+#include "StateReplicator.h"
+#include "SharedTestData.h"
+
+using namespace std;
+using namespace AsteriskSCF::StateReplicatorTest::V1;
+using namespace AsteriskSCF::StateReplicatorTest;
+using namespace AsteriskSCF::StateReplication;
+
+/**
+ * Instantiate our shared data.
+ */
+SharedTestData SharedTestData::instance;
+
+/* Cache the command line arguments so that Ice can be initialized within the global fixture. */
+struct ArgCacheType
+{
+public:
+ int argc;
+ char **argv;
+};
+static ArgCacheType mCachedArgs;
+
+/**
+ * A global fixture for Ice initialization.
+ * Provides setup/teardown for the entire set of tests.
+ */
+struct GlobalIceFixture
+{
+ GlobalIceFixture()
+ {
+ BOOST_TEST_MESSAGE("Setting up State Replicator test fixture");
+
+ ::boost::debug::detect_memory_leaks(false);
+ ::boost::unit_test::unit_test_log.set_stream( std::cout );
+
+ int status = 0;
+ try
+ {
+ Ice::PropertiesPtr props = Ice::createProperties(mCachedArgs.argc, mCachedArgs.argv);
+ Ice::InitializationData initData;
+ initData.properties = props;
+
+ // NOTE: See the typedef at top of ShareTestData.h to see how the StateReplicator template is invoked.
+
+ // Set up incoming adapter. This is where we'll publish our proxies.
+ SharedTestData::instance.communicator_in = Ice::initialize(initData);
+
+ SharedTestData::instance.adapter_in = SharedTestData::instance.communicator_in->createObjectAdapterWithEndpoints("TestReplicatorAdapterIn", "default -p 10070");
+
+ string replicatorId("TestReplicator");
+ SharedTestData::instance.mTestReplicatorImplPtr = new TestReplicatorImpl();
+ SharedTestData::instance.adapter_in->add(SharedTestData::instance.mTestReplicatorImplPtr, SharedTestData::instance.communicator_in->stringToIdentity(replicatorId));
+
+ string listenerId1("Listener1");
+ SharedTestData::instance.mMockStateListener1Ptr = new MockStateReplicatorListenerImpl();
+ SharedTestData::instance.adapter_in->add(SharedTestData::instance.mMockStateListener1Ptr, SharedTestData::instance.communicator_in->stringToIdentity(listenerId1));
+
+ string listenerId2("Listener2");
+ SharedTestData::instance.mMockStateListener2Ptr = new MockStateReplicatorListenerImpl();
+ SharedTestData::instance.adapter_in->add(SharedTestData::instance.mMockStateListener2Ptr, SharedTestData::instance.communicator_in->stringToIdentity(listenerId2));
+
+ string listenerId3("Listener3");
+ SharedTestData::instance.mMockStateListener3Ptr = new MockStateReplicatorListenerImpl();
+ SharedTestData::instance.adapter_in->add(SharedTestData::instance.mMockStateListener3Ptr, SharedTestData::instance.communicator_in->stringToIdentity(listenerId3));
+
+ SharedTestData::instance.adapter_in->activate();
+
+ // Now that the adapter has been activated, get a local proxy to the replicator.
+ Ice::ObjectPrx replicatorObjectPrx = SharedTestData::instance.adapter_in->createDirectProxy(SharedTestData::instance.communicator_in->stringToIdentity(replicatorId));
+ SharedTestData::instance.mTestStateReplicatorPrx = TestStateReplicatorPrx::checkedCast(replicatorObjectPrx);
+
+ Ice::ObjectPrx listener1ObjectPrx = SharedTestData::instance.adapter_in->createDirectProxy(SharedTestData::instance.communicator_in->stringToIdentity(listenerId1));
+ SharedTestData::instance.mTestStateListener1Prx = TestStateReplicatorListenerPrx::checkedCast(listener1ObjectPrx);
+
+ Ice::ObjectPrx listener2ObjectPrx = SharedTestData::instance.adapter_in->createDirectProxy(SharedTestData::instance.communicator_in->stringToIdentity(listenerId2));
+ SharedTestData::instance.mTestStateListener2Prx = TestStateReplicatorListenerPrx::checkedCast(listener2ObjectPrx);
+
+ Ice::ObjectPrx listener3ObjectPrx = SharedTestData::instance.adapter_in->createDirectProxy(SharedTestData::instance.communicator_in->stringToIdentity(listenerId3));
+ SharedTestData::instance.mTestStateListener3Prx = TestStateReplicatorListenerPrx::checkedCast(listener3ObjectPrx);
+
+ }
+ catch (const Ice::Exception& ex)
+ {
+ cerr << ex << endl;
+ status = 1;
+ }
+ catch (const char* msg)
+ {
+ cerr << msg << endl;
+ status = 1;
+ }
+ } // end Fixture() constructor
+
+
+ ~GlobalIceFixture()
+ {
+ BOOST_TEST_MESSAGE("Tearing down service discovery test fixture");
+
+
+ if (SharedTestData::instance.communicator_in)
+ {
+ SharedTestData::instance.communicator_in->shutdown();
+ SharedTestData::instance.communicator_in = 0;
+ }
+ if (SharedTestData::instance.communicator_out)
+ {
+ SharedTestData::instance.communicator_out->shutdown();
+ SharedTestData::instance.communicator_out = 0;
+ }
+ }
+private:
+ int mGlob;
+};
+
+BOOST_GLOBAL_FIXTURE(GlobalIceFixture);
+
+/**
+ * Implement our own main to intercept the command line args.
+ * (A default main() is provided if we hadn't set BOOST_TEST_NO_MAIN at the top of file.)
+ * NOTE: Pass in --log_level=message to see the debug print statements.
+ */
+int BOOST_TEST_CALL_DECL main( int argc, char* argv[] )
+{
+ mCachedArgs.argc = argc;
+ mCachedArgs.argv = argv;
+ return ::boost::unit_test::unit_test_main( &init_unit_test, argc, argv );
+}
+
+struct PerTestFixture
+{
+public:
+ PerTestFixture()
+ {
+ try
+ {
+ SharedTestData::instance.mMockStateListener1Ptr->reset();
+ SharedTestData::instance.mMockStateListener2Ptr->reset();
+
+ SharedTestData::instance.mTestStateReplicatorPrx->addListener(SharedTestData::instance.mTestStateListener1Prx);
+ SharedTestData::instance.mTestStateReplicatorPrx->addListener(SharedTestData::instance.mTestStateListener2Prx);
+
+ mTestValues.clear();
+
+ TestStateItemFooPtr item1 = new TestStateItemFoo();
+ item1->key = "FooBabar";
+ item1->mFooCount = 12;
+ item1->mFooString = "Baileys";
+ mTestValues.push_back(item1);
+
+ TestStateItemBarPtr item2 = new TestStateItemBar();
+ item2->key = "BarMouse";
+ item2->mBarString = "Ringling";
+ mTestValues.push_back(item2);
+
+ TestStateItemFooPtr item3 = new TestStateItemFoo();
+ item3->key = "FooDumbo";
+ item3->mFooCount = 7;
+ item3->mFooString = "Barnum";
+ mTestValues.push_back(item3);
+
+ }
+ catch (...)
+ {
+ BOOST_TEST_MESSAGE("PerTestFixture failed to initialize.");
+
+ SharedTestData::instance.mTestReplicatorImplPtr->clearListeners();
+ SharedTestData::instance.mTestReplicatorImplPtr->clearState();
+ }
+ }
+
+ ~PerTestFixture()
+ {
+ try
+ {
+ SharedTestData::instance.mTestReplicatorImplPtr->clearListeners();
+ SharedTestData::instance.mTestReplicatorImplPtr->clearState();
+ }
+ catch (...)
+ {
+ BOOST_TEST_MESSAGE("PerTestFixture failed in shutdown.");
+ }
+ }
+
+public:
+ TestStateItemSeq mTestValues;
+};
+
+/**
+ * Test adding and removing a listener with the StateReplicator.
+ */
+BOOST_AUTO_TEST_CASE(AddRemoveListeners)
+{
+ bool addListenerSucceeded(true);
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->addListener(SharedTestData::instance.mTestStateListener1Prx);
+ SharedTestData::instance.mTestStateReplicatorPrx->addListener(SharedTestData::instance.mTestStateListener2Prx);
+ }
+ catch (...)
+ {
+ addListenerSucceeded = false;
+ BOOST_TEST_MESSAGE("Exception adding Listeners.");
+ }
+
+ BOOST_CHECK(addListenerSucceeded);
+ BOOST_CHECK(SharedTestData::instance.mTestReplicatorImplPtr->getListenerCount() == 2);
+
+ bool removeListenerSucceeded(true);
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->removeListener(SharedTestData::instance.mTestStateListener1Prx);
+ SharedTestData::instance.mTestStateReplicatorPrx->removeListener(SharedTestData::instance.mTestStateListener2Prx);
+ }
+ catch (...)
+ {
+ removeListenerSucceeded = false;
+ BOOST_TEST_MESSAGE("Exception removing Listener.");
+ }
+ BOOST_CHECK(removeListenerSucceeded);
+ BOOST_CHECK(SharedTestData::instance.mTestReplicatorImplPtr->getListenerCount() == 0);
+
+
+ BOOST_TEST_MESSAGE("Completed AddRemoveListeners test.");
+}
+
+/**
+ * Test forwarding the setState operation of the StateReplicator interface to listeners.
+ */
+BOOST_FIXTURE_TEST_CASE(PushData, PerTestFixture)
+{
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(mTestValues);
+
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception pushing state data.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+ catch (...)
+ {
+ bool unknownException(false);
+ BOOST_CHECK(unknownException);
+ }
+
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener1Ptr->mStateItems.size() == 3);
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener2Ptr->mStateItems.size() == 3);
+
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener1Ptr->mStateItems.front()->key == "FooBabar");
+
+ BOOST_TEST_MESSAGE("Completed PushData test.");
+
+}
+
+/**
+ * Test forwarding the removeState message to listeners.
+ */
+BOOST_FIXTURE_TEST_CASE(ForwardRemoveState, PerTestFixture)
+{
+ TestStateItemSeq retrievedValues;
+
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(mTestValues);
+ // {FooBabar, BarMouse, FooDumbo}
+
+ Ice::StringSeq keys;
+ keys.push_back("FooBabar");
+ keys.push_back("FooDumbo");
+
+ SharedTestData::instance.mTestStateReplicatorPrx->removeState(keys);
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception removing state data.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+ catch (...)
+ {
+ bool unknownException(false);
+ BOOST_CHECK(unknownException);
+ }
+
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener1Ptr->mItemKeys.size() == 2);
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener2Ptr->mItemKeys.size() == 2);
+
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener1Ptr->mItemKeys.front() == "FooBabar");
+
+ BOOST_TEST_MESSAGE("Completed ForwardRemoveState test.");
+
+}
+
+/**
+ * Test removing state. Also tests retrieving all the state.
+ */
+BOOST_FIXTURE_TEST_CASE(RemoveState, PerTestFixture)
+{
+ TestStateItemSeq retrievedValues;
+
+ try
+ {
+ // Set the basic 3 items of state.
+ // {FooBabar, BarMouse, FooDumbo}
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(mTestValues);
+
+ // Try removing two of them.
+ Ice::StringSeq keys;
+ keys.push_back("FooBabar");
+ keys.push_back("FooDumbo");
+
+ SharedTestData::instance.mTestStateReplicatorPrx->removeState(keys);
+
+ retrievedValues = SharedTestData::instance.mTestStateReplicatorPrx->getAllState();
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception removing state data.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+ catch (...)
+ {
+ bool unknownException(false);
+ BOOST_CHECK(unknownException);
+ }
+
+ BOOST_CHECK(retrievedValues.size() == 1);
+
+ BOOST_CHECK(retrievedValues.front()->key == "BarMouse");
+
+ BOOST_TEST_MESSAGE("Completed RemoveState test.");
+}
+
+/**
+ * Test getting partial state based on keyed subset.
+ */
+BOOST_FIXTURE_TEST_CASE(GetSomeState, PerTestFixture)
+{
+ TestStateItemSeq retrievedValues;
+
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(mTestValues);
+ // {FooBabar, BarMouse, FooDumbo}
+
+ Ice::StringSeq keys;
+ keys.push_back("FooBabar");
+ keys.push_back("FooDumbo");
+
+ retrievedValues = SharedTestData::instance.mTestStateReplicatorPrx->getState(keys);
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception getting partial state data.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+ catch (...)
+ {
+ bool unknownException(false);
+ BOOST_CHECK(unknownException);
+ }
+
+ BOOST_CHECK(retrievedValues.size() == 2);
+
+ BOOST_CHECK(retrievedValues.front()->key == "FooBabar");
+
+ BOOST_TEST_MESSAGE("Completed GetSomeState test.");
+}
+
+/**
+ * Test order of data sent to listeners.
+ */
+BOOST_FIXTURE_TEST_CASE(PreserveOrder, PerTestFixture)
+{
+ TestStateItemSeq retrievedValues;
+
+ try
+ {
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(mTestValues);
+
+ // {FooBabar, BarMouse, FooDumbo}
+ Ice::StringSeq keys;
+ keys.push_back("BarMouse");
+ SharedTestData::instance.mTestStateReplicatorPrx->removeState(keys);
+ // {FooBabar, FooDumbo}
+
+ TestStateItemSeq moreItems;
+ TestStateItemBarPtr item1 = new TestStateItemBar();
+ item1->key = "Extra";
+ moreItems.push_back(item1);
+
+ // Re-add BarMouse
+ TestStateItemBarPtr item2 = new TestStateItemBar();
+ item2->key = "BarMouse";
+ moreItems.push_back(item2);
+
+ SharedTestData::instance.mTestStateReplicatorPrx->setState(moreItems);
+ // {FooBabar, FooDumbo, Extra, BarMouse}
+
+ retrievedValues = SharedTestData::instance.mTestStateReplicatorPrx->getAllState();
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception altering state data.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+ catch (...)
+ {
+ bool unknownException(false);
+ BOOST_CHECK(unknownException);
+ }
+
+ BOOST_CHECK(retrievedValues.size() == 4);
+
+ BOOST_CHECK(retrievedValues[0]->key == "FooBabar");
+ BOOST_CHECK(retrievedValues[1]->key == "FooDumbo");
+ BOOST_CHECK(retrievedValues[2]->key == "Extra");
+ BOOST_CHECK(retrievedValues[3]->key == "BarMouse");
+
+ try
+ {
+ //Insure that a late joiner is pushed the correct current state, in correct order.
+ SharedTestData::instance.mTestStateReplicatorPrx->addListener(SharedTestData::instance.mTestStateListener3Prx);
+
+ // NOTE: This test currently is reliable only because we are NOT doing asynchronous sends to the listeners.
+ // Will need a delay when asynch.
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener3Ptr->mStateItems.size() == 4);
+
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener3Ptr->mStateItems[0]->key == "FooBabar");
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener3Ptr->mStateItems[1]->key == "FooDumbo");
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener3Ptr->mStateItems[2]->key == "Extra");
+ BOOST_CHECK(SharedTestData::instance.mMockStateListener3Ptr->mStateItems[3]->key == "BarMouse");
+ }
+ catch(const IceUtil::Exception &ie)
+ {
+ bool IceException(false);
+ string msg = "Exception adding a late listener.";
+ msg += ie.what();
+ BOOST_TEST_MESSAGE(msg);
+ BOOST_CHECK(IceException);
+ }
+
+ BOOST_TEST_MESSAGE("Completed PreserveOrder test.");
+
+}
\ No newline at end of file
diff --git a/StateReplicator/testslice/CMakeLists.txt b/StateReplicator/testslice/CMakeLists.txt
new file mode 100644
index 0000000..ec356d7
--- /dev/null
+++ b/StateReplicator/testslice/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Compile State Replicator Test Component's slice
+
+hydra_slice_include_directories("${CMAKE_SOURCE_DIR}/slice")
+hydra_compile_slice(StateReplicatorTestIf.ice lib "State Replicator Test Slice Types" Test)
+
diff --git a/StateReplicator/testslice/StateReplicatorTestIf.ice b/StateReplicator/testslice/StateReplicatorTestIf.ice
new file mode 100644
index 0000000..f70a92c
--- /dev/null
+++ b/StateReplicator/testslice/StateReplicatorTestIf.ice
@@ -0,0 +1,48 @@
+#pragma once
+#include <Ice/BuiltinSequences.ice>
+
+module AsteriskSCF
+{
+module StateReplicatorTest
+{
+["suppress"]
+module V1
+{
+ class TestStateItem
+ {
+ string key;
+ };
+
+ sequence<TestStateItem> TestStateItemSeq;
+
+ interface TestStateReplicatorListener
+ {
+ void stateRemoved(Ice::StringSeq itemKeys);
+ void stateSet(TestStateItemSeq items);
+ };
+
+ interface TestStateReplicator
+ {
+ void addListener(TestStateReplicatorListener *listener);
+ void removeListener(TestStateReplicatorListener *listener);
+ void setState (TestStateItemSeq items);
+ void removeState(Ice::StringSeq items);
+ idempotent TestStateItemSeq getState(Ice::StringSeq itemKeys);
+ idempotent TestStateItemSeq getAllState();
+ };
+
+ class TestStateItemFoo extends TestStateItem
+ {
+ string mFooString;
+ bool mIsFoo;
+ int mFooCount;
+ };
+
+ class TestStateItemBar extends TestStateItem
+ {
+ string mBarString;
+ };
+
+}; //module V1
+}; //module SIP
+}; //module Asterisk SCF
-----------------------------------------------------------------------
--
asterisk-scf/integration/ice-util-c++.git
More information about the asterisk-scf-commits
mailing list