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);