You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2013/04/04 22:58:03 UTC

svn commit: r1464757 - in /incubator/mesos/trunk/third_party/libprocess: include/process/gmock.hpp src/tests/process_tests.cpp

Author: benh
Date: Thu Apr  4 20:58:03 2013
New Revision: 1464757

URL: http://svn.apache.org/r1464757
Log:
Redesigned and implemented mechanisms for filtering messages,
dispatches, etc, in tests. Deprecated EXPECT_MESSAGE/DISPATCH for
FUTURE_MESSAGE/DISPATCH.

Modified:
    incubator/mesos/trunk/third_party/libprocess/include/process/gmock.hpp
    incubator/mesos/trunk/third_party/libprocess/src/tests/process_tests.cpp

Modified: incubator/mesos/trunk/third_party/libprocess/include/process/gmock.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/include/process/gmock.hpp?rev=1464757&r1=1464756&r2=1464757&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/include/process/gmock.hpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/include/process/gmock.hpp Thu Apr  4 20:58:03 2013
@@ -1,6 +1,8 @@
 #ifndef __PROCESS_GMOCK_HPP__
 #define __PROCESS_GMOCK_HPP__
 
+#include <pthread.h>
+
 #include <gmock/gmock.h>
 
 #include <tr1/tuple>
@@ -14,18 +16,39 @@
 #include <stout/nothing.hpp>
 
 
+// THIS IS DEPRECATED AND BROKEN! REPLACE ALL USES!
 #define EXPECT_MESSAGE(name, from, to)                                  \
-  EXPECT_CALL(*process::FilterTestEventListener::instance()->install(), \
+  EXPECT_CALL(*new process::MockFilter(),                              \
               filter(testing::A<const process::MessageEvent&>()))       \
     .With(process::MessageMatcher(name, from, to))
 
 
+// THIS IS DEPRECATED AND BROKEN! REPLACE ALL USES!
 #define EXPECT_DISPATCH(pid, method)                                    \
-  EXPECT_CALL(*process::FilterTestEventListener::instance()->install(), \
+  EXPECT_CALL(*new process::MockFilter(),                              \
               filter(testing::A<const process::DispatchEvent&>()))      \
     .With(process::DispatchMatcher(pid, method))
 
 
+#define FUTURE_MESSAGE(name, from, to)          \
+  process::FutureMessage(name, from, to)
+
+#define DROP_MESSAGE(name, from, to)            \
+  process::FutureMessage(name, from, to, true)
+
+#define FUTURE_DISPATCH(pid, method)            \
+  process::FutureDispatch(pid, method)
+
+#define DROP_DISPATCH(pid, method)              \
+  process::FutureDispatch(pid, method, true)
+
+#define DROP_MESSAGES(name, from, to)           \
+  process::DropMessages(name, from, to)
+
+#define DROP_DISPATCHES(pid, method)            \
+  process::DropDispatches(pid, method)
+
+
 ACTION_TEMPLATE(PromiseArg,
                 HAS_1_TEMPLATE_PARAMS(int, k),
                 AND_1_VALUE_PARAMS(promise))
@@ -104,34 +127,10 @@ FutureSatisfy(process::Future<Nothing>* 
 
 namespace process {
 
-// Used by EXPECT_MESSAGE for matching a MessageEvent.
-MATCHER_P3(MessageMatcher, name, from, to, "")
-{
-  const MessageEvent& event = ::std::tr1::get<0>(arg);
-  return (testing::Matcher<std::string>(name).Matches(event.message->name) &&
-          testing::Matcher<UPID>(from).Matches(event.message->from) &&
-          testing::Matcher<UPID>(to).Matches(event.message->to));
-}
-
-
-// Used by EXPECT_DISPATCH for matching a DispatchEvent.
-MATCHER_P2(DispatchMatcher, pid, method, "")
-{
-  const DispatchEvent& event = ::std::tr1::get<0>(arg);
-  return (testing::Matcher<UPID>(pid).Matches(event.pid) &&
-          testing::Matcher<std::string>(internal::canonicalize(method))
-          .Matches(event.method));
-}
-
-
-// A definition of a libprocess filter to enable waiting for events
-// (such as messages or dispatches) via WAIT_UNTIL in tests (i.e.,
-// using triggers). This is not meant to be used directly by tests;
-// tests should use macros like EXPECT_MESSAGE.
-class TestsFilter : public Filter
+class MockFilter : public Filter
 {
 public:
-  TestsFilter()
+  MockFilter()
   {
     EXPECT_CALL(*this, filter(testing::A<const MessageEvent&>()))
       .WillRepeatedly(testing::Return(false));
@@ -150,6 +149,46 @@ public:
 };
 
 
+// A definition of a libprocess filter to enable waiting for events
+// (such as messages or dispatches) via in tests. This is not meant to
+// be used directly by tests; tests should use macros like
+// FUTURE_MESSAGE and FUTURE_DISPATCH instead.
+class TestsFilter : public Filter
+{
+public:
+  TestsFilter()
+  {
+    // We use a recursive mutex here in the event that satisfying the
+    // future created in FutureMessage or FutureDispatch via the
+    // FutureArgField or FutureSatisfy actions invokes callbacks (from
+    // Future::then or Future::onAny, etc) that themselves invoke
+    // FutureDispatch or FutureMessage.
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&mutex, &attr);
+    pthread_mutexattr_destroy(&attr);
+  }
+
+  virtual bool filter(const MessageEvent& event) { return handle(event); }
+  virtual bool filter(const DispatchEvent& event) { return handle(event); }
+  virtual bool filter(const HttpEvent& event) { return handle(event); }
+  virtual bool filter(const ExitedEvent& event) { return handle(event); }
+
+  template <typename T>
+  bool handle(const T& t)
+  {
+    pthread_mutex_lock(&mutex);
+    bool drop = mock.filter(t);
+    pthread_mutex_unlock(&mutex);
+    return drop;
+  }
+
+  MockFilter mock;
+  pthread_mutex_t mutex;;
+};
+
+
 class FilterTestEventListener : public ::testing::EmptyTestEventListener
 {
 public:
@@ -165,8 +204,8 @@ public:
   {
     if (!started) {
       EXIT(1)
-        << "To use EXPECT_MESSAGE you need to do the following before you "
-        << "invoke RUN_ALL_TESTS():\n\n"
+        << "To use FUTURE/DROP_MESSAGE/DISPATCH, etc. you need to do the "
+        << "following before you invoke RUN_ALL_TESTS():\n\n"
         << "\t::testing::TestEventListeners& listeners =\n"
         << "\t  ::testing::UnitTest::GetInstance()->listeners();\n"
         << "\tlisteners.Append(process::FilterTestEventListener::instance());";
@@ -209,6 +248,80 @@ private:
   bool started;
 };
 
+
+MATCHER_P3(MessageMatcher, name, from, to, "")
+{
+  const MessageEvent& event = ::std::tr1::get<0>(arg);
+  return (testing::Matcher<std::string>(name).Matches(event.message->name) &&
+          testing::Matcher<UPID>(from).Matches(event.message->from) &&
+          testing::Matcher<UPID>(to).Matches(event.message->to));
+}
+
+
+MATCHER_P2(DispatchMatcher, pid, method, "")
+{
+  const DispatchEvent& event = ::std::tr1::get<0>(arg);
+  return (testing::Matcher<UPID>(pid).Matches(event.pid) &&
+          testing::Matcher<std::string>(internal::canonicalize(method))
+          .Matches(event.method));
+}
+
+
+template <typename Name, typename From, typename To>
+Future<Message> FutureMessage(Name name, From from, To to, bool drop = false)
+{
+  TestsFilter* filter = FilterTestEventListener::instance()->install();
+  pthread_mutex_lock(&filter->mutex);
+  Future<Message> future;
+  EXPECT_CALL(filter->mock, filter(testing::A<const MessageEvent&>()))
+    .With(MessageMatcher(name, from, to))
+    .WillOnce(testing::DoAll(FutureArgField<0>(&MessageEvent::message, &future),
+                             testing::Return(drop)))
+    .RetiresOnSaturation(); // Don't impose any subsequent expectations.
+  pthread_mutex_unlock(&filter->mutex);
+  return future;
+}
+
+
+template <typename PID, typename Method>
+Future<Nothing> FutureDispatch(PID pid, Method method, bool drop = false)
+{
+  TestsFilter* filter = FilterTestEventListener::instance()->install();
+  pthread_mutex_lock(&filter->mutex);
+  Future<Nothing> future;
+  EXPECT_CALL(filter->mock, filter(testing::A<const DispatchEvent&>()))
+    .With(DispatchMatcher(pid, method))
+    .WillOnce(testing::DoAll(FutureSatisfy(&future),
+                             testing::Return(drop)))
+    .RetiresOnSaturation(); // Don't impose any subsequent expectations.
+  pthread_mutex_unlock(&filter->mutex);
+  return future;
+}
+
+
+template <typename Name, typename From, typename To>
+void DropMessages(Name name, From from, To to)
+{
+  TestsFilter* filter = FilterTestEventListener::instance()->install();
+  pthread_mutex_lock(&filter->mutex);
+  EXPECT_CALL(filter->mock, filter(testing::A<const MessageEvent&>()))
+    .With(MessageMatcher(name, from, to))
+    .WillRepeatedly(testing::Return(true));
+  pthread_mutex_unlock(&filter->mutex);
+}
+
+
+template <typename PID, typename Method>
+void DropDispatches(PID pid, Method method)
+{
+  TestsFilter* filter = FilterTestEventListener::instance()->install();
+  pthread_mutex_lock(&filter->mutex);
+  EXPECT_CALL(filter->mock, filter(testing::A<const DispatchEvent&>()))
+    .With(DispatchMatcher(pid, method))
+    .WillRepeatedly(testing::Return(true));
+  pthread_mutex_unlock(&filter->mutex);
+}
+
 } // namespace process {
 
 #endif // __PROCESS_GMOCK_HPP__

Modified: incubator/mesos/trunk/third_party/libprocess/src/tests/process_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/src/tests/process_tests.cpp?rev=1464757&r1=1464756&r2=1464757&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/src/tests/process_tests.cpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/src/tests/process_tests.cpp Thu Apr  4 20:58:03 2013
@@ -512,25 +512,17 @@ TEST(Process, expect)
 
   ASSERT_FALSE(!pid);
 
-  volatile bool func = false;
-
-  EXPECT_MESSAGE("func", _, _)
-    .WillOnce(DoAll(Assign(&func, true),
-                    Return(true)));
+  Future<Message> message = DROP_MESSAGE("func", _, _);
 
   post(pid, "func");
 
-  while (!func);
-
-  func = false;
+  EXPECT_FUTURE_WILL_SUCCEED(message);
 
-  EXPECT_DISPATCH(pid, &HandlersProcess::func)
-    .WillOnce(DoAll(Assign(&func, true),
-                    Return(true)));
+  Future<Nothing> func = DROP_DISPATCH(pid, &HandlersProcess::func);
 
   dispatch(pid, &HandlersProcess::func, pid, "");
 
-  while (!func);
+  EXPECT_FUTURE_WILL_SUCCEED(func);
 
   terminate(pid, false);
   wait(pid);