[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