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 2011/06/05 10:45:35 UTC
svn commit: r1132109 [3/26] - in /incubator/mesos/trunk: ./ src/common/
src/configurator/ src/master/ src/sched/ src/slave/ src/tests/
third_party/gmock-1.5.0/ third_party/gmock-1.5.0/build-aux/
third_party/gmock-1.5.0/fused-src/ third_party/gmock-1.5....
Modified: incubator/mesos/trunk/configure.ac
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/configure.ac?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/configure.ac (original)
+++ incubator/mesos/trunk/configure.ac Sun Jun 5 08:45:22 2011
@@ -24,8 +24,8 @@ ac_configure_args="$ac_configure_args --
AC_CONFIG_FILES([Makefile src/Makefile src/examples/Makefile src/tests/Makefile src/config/config.hpp])
AC_CONFIG_SUBDIRS([third_party/libprocess])
-AC_CONFIG_SUBDIRS([third_party/gtest-1.5.0])
AC_CONFIG_SUBDIRS([third_party/glog-0.3.1])
+AC_CONFIG_SUBDIRS([third_party/gmock-1.5.0])
AC_CONFIG_SUBDIRS([third_party/zookeeper-3.3.1/src/c])
AC_CANONICAL_SYSTEM
Modified: incubator/mesos/trunk/src/common/foreach.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/common/foreach.hpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/common/foreach.hpp (original)
+++ incubator/mesos/trunk/src/common/foreach.hpp Sun Jun 5 08:45:22 2011
@@ -25,6 +25,10 @@
#include <boost/tuple/tuple.hpp>
+namespace foreach {
+
const boost::tuples::detail::swallow_assign _ = boost::tuples::ignore;
+}
+
#endif /* FOREACH_HPP */
Modified: incubator/mesos/trunk/src/configurator/configurator.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/configurator/configurator.cpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/configurator/configurator.cpp (original)
+++ incubator/mesos/trunk/src/configurator/configurator.cpp Sun Jun 5 08:45:22 2011
@@ -14,6 +14,8 @@
using namespace mesos::internal;
+using foreach::_;
+
const char* Configurator::DEFAULT_CONFIG_DIR = "conf";
const char* Configurator::CONFIG_FILE_NAME = "mesos.conf";
Modified: incubator/mesos/trunk/src/master/master.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/master/master.hpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/master/master.hpp (original)
+++ incubator/mesos/trunk/src/master/master.hpp Sun Jun 5 08:45:22 2011
@@ -38,6 +38,9 @@
namespace mesos { namespace internal { namespace master {
+using namespace mesos;
+using namespace mesos::internal;
+
using std::make_pair;
using std::map;
using std::pair;
@@ -48,8 +51,7 @@ using std::vector;
using boost::unordered_map;
using boost::unordered_set;
-using namespace mesos;
-using namespace mesos::internal;
+using foreach::_;
// Maximum number of slot offers to have outstanding for each framework.
Modified: incubator/mesos/trunk/src/sched/sched.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/sched/sched.cpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/sched/sched.cpp (original)
+++ incubator/mesos/trunk/src/sched/sched.cpp Sun Jun 5 08:45:22 2011
@@ -493,6 +493,8 @@ void MesosSchedulerDriver::init(Schedule
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
pthread_cond_init(&cond, 0);
+
+ // TODO(benh): Initialize glog.
}
Modified: incubator/mesos/trunk/src/slave/slave.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/slave/slave.hpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/slave/slave.hpp (original)
+++ incubator/mesos/trunk/src/slave/slave.hpp Sun Jun 5 08:45:22 2011
@@ -60,6 +60,8 @@ using boost::lexical_cast;
using boost::unordered_map;
using boost::unordered_set;
+using foreach::_;
+
// A description of a task that is yet to be launched
struct TaskDescription
Modified: incubator/mesos/trunk/src/tests/Makefile.in
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/Makefile.in?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/Makefile.in (original)
+++ incubator/mesos/trunk/src/tests/Makefile.in Sun Jun 5 08:45:22 2011
@@ -22,7 +22,7 @@ LIBPROCESS = third_party/libprocess
LIBEV = $(LIBPROCESS)/third_party/libev-3.8
GLOG = third_party/glog-0.3.1
-GTEST = third_party/gtest-1.5.0
+GMOCK = third_party/gmock-1.5.0
ZOOKEEPER = third_party/zookeeper-3.3.1/src/c
@@ -50,9 +50,9 @@ LDFLAGS += -L@top_builddir@/$(LIBPROCESS
# Add libev to LDFLAGS.
LDFLAGS += -L@top_builddir@/$(LIBEV)/.libs
-# Add glog and gtest to include paths.
-CXXFLAGS += -I@top_srcdir@/$(GLOG)/src -I@top_builddir@/$(GLOG)/src -I@top_srcdir@/$(GTEST)/include
-LDFLAGS += -L@top_builddir@/$(GLOG)/.libs -L@top_builddir@/$(GTEST)/lib/.libs
+# Add glog, and gmock/gtest to include paths and library paths.
+CXXFLAGS += -I@top_srcdir@/$(GLOG)/src -I@top_builddir@/$(GLOG)/src -I@top_srcdir@/$(GMOCK)/include -I@top_srcdir@/$(GMOCK)/gtest/include
+LDFLAGS += -L@top_builddir@/$(GLOG)/.libs -L@top_builddir@/$(GMOCK)/lib/.libs -L@top_builddir@/$(GMOCK)/gtest/lib/.libs
# Add included ZooKeeper to include and lib paths if necessary.
ifeq ($(WITH_INCLUDED_ZOOKEEPER),1)
@@ -72,8 +72,8 @@ CXXFLAGS += -DBUILD_DATE="\"$$(date '+%Y
CFLAGS += -DBUILD_USER="\"$$USER\""
CXXFLAGS += -DBUILD_USER="\"$$USER\""
-# Add glog, gtest, libev, libprocess, pthread, and dl to LIBS.
-LIBS += -lglog -lgtest -lprocess -lev -lpthread -ldl
+# Add glog, gmock, gtest, libev, libprocess, pthread, and dl to LIBS.
+LIBS += -lglog -lgmock -lgtest -lprocess -lev -lpthread -ldl
# Add ZooKeeper if necessary.
ifeq ($(WITH_ZOOKEEPER),1)
Modified: incubator/mesos/trunk/src/tests/test_master.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/test_master.cpp?rev=1132109&r1=1132108&r2=1132109&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/test_master.cpp (original)
+++ incubator/mesos/trunk/src/tests/test_master.cpp Sun Jun 5 08:45:22 2011
@@ -1,7 +1,7 @@
-#include <gtest/gtest.h>
-
#include <boost/lexical_cast.hpp>
+#include <gmock/gmock.h>
+
#include <mesos_exec.hpp>
#include <mesos_sched.hpp>
@@ -13,261 +13,405 @@
#include "slave/process_based_isolation_module.hpp"
#include "slave/slave.hpp"
-using std::string;
-using std::vector;
-
-using boost::lexical_cast;
-
using namespace mesos;
using namespace mesos::internal;
+using boost::lexical_cast;
+
using mesos::internal::master::Master;
using mesos::internal::slave::Slave;
using mesos::internal::slave::Framework;
using mesos::internal::slave::IsolationModule;
using mesos::internal::slave::ProcessBasedIsolationModule;
+using std::string;
+using std::vector;
+
+using testing::_;
+using testing::A;
+using testing::An;
+using testing::AtMost;
+using testing::DoAll;
+using testing::Eq;
+using testing::ElementsAre;
+using testing::Ne;
+using testing::Return;
+using testing::SaveArg;
+using testing::Sequence;
+using testing::StrEq;
-class NoopScheduler : public Scheduler
+
+class MockScheduler : public Scheduler
{
public:
- bool registeredCalled;
- int offersGotten;
- int slavesExpected;
+ MOCK_METHOD1(getFrameworkName, std::string(SchedulerDriver*));
+ MOCK_METHOD1(getExecutorInfo, ExecutorInfo(SchedulerDriver*));
+ MOCK_METHOD2(registered, void(SchedulerDriver*, FrameworkID));
+ MOCK_METHOD3(resourceOffer, void(SchedulerDriver*, OfferID,
+ const std::vector<SlaveOffer>&));
+ MOCK_METHOD2(offerRescinded, void(SchedulerDriver*, OfferID));
+ MOCK_METHOD2(statusUpdate, void(SchedulerDriver*, const TaskStatus&));
+ MOCK_METHOD2(frameworkMessage, void(SchedulerDriver*,
+ const FrameworkMessage&));
+ MOCK_METHOD2(slaveLost, void(SchedulerDriver*, SlaveID));
+ MOCK_METHOD3(error, void(SchedulerDriver*, int, const std::string&));
+};
+
+class MockExecutor : public Executor
+{
public:
- NoopScheduler(int _slavesExpected)
- : slavesExpected(_slavesExpected),
- registeredCalled(false),
- offersGotten(0)
- {}
+ MOCK_METHOD2(init, void(ExecutorDriver*, const ExecutorArgs&));
+ MOCK_METHOD2(launchTask, void(ExecutorDriver*, const TaskDescription&));
+ MOCK_METHOD2(killTask, void(ExecutorDriver*, TaskID));
+ MOCK_METHOD2(frameworkMessage, void(ExecutorDriver*, const FrameworkMessage&));
+ MOCK_METHOD1(shutdown, void(ExecutorDriver*));
+ MOCK_METHOD3(error, void(ExecutorDriver*, int, const std::string&));
+};
- virtual ~NoopScheduler() {}
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+class MockFilter : public MessageFilter
+{
+ public:
+ MOCK_METHOD1(filter, bool(struct msg *));
+};
- virtual void registered(SchedulerDriver*, FrameworkID fid) {
- LOG(INFO) << "NoopScheduler registered with id " << fid;
- registeredCalled = true;
- }
- virtual void resourceOffer(SchedulerDriver *d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "NoopScheduler got a slot offer";
- offersGotten++;
- EXPECT_EQ(slavesExpected, offers.size());
- foreach (const SlaveOffer& offer, offers) {
- string cpus = offer.params.find("cpus")->second;
- string mem = offer.params.find("mem")->second;
- EXPECT_EQ("2", cpus);
- EXPECT_EQ(lexical_cast<string>(1 * Gigabyte), mem);
- }
- vector<TaskDescription> tasks;
- d->replyToOffer(id, tasks, map<string, string>());
- d->stop();
- }
-};
+struct trigger
+{
+ trigger() : value(false) {}
+ bool value;
+};
-TEST(MasterTest, NoopFrameworkWithOneSlave)
+MATCHER_P3(MsgMatcher, id, from, to, "")
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 2, 1 * Gigabyte, false, false);
- NoopScheduler sched(1);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_TRUE(sched.registeredCalled);
- EXPECT_EQ(1, sched.offersGotten);
- local::shutdown();
+ return (testing::Matcher<MSGID>(id).Matches(arg->id) &&
+ testing::Matcher<PID>(from).Matches(arg->from) &&
+ testing::Matcher<PID>(to).Matches(arg->to));
}
-TEST(MasterTest, NoopFrameworkWithMultipleSlaves)
+ACTION_P(Trigger, trigger) { trigger->value = true; }
+
+
+#define EXPECT_MSG(filter, id, from, to) \
+ EXPECT_CALL(filter, filter(MsgMatcher(id, from, to)))
+
+
+#define WAIT_UNTIL(trigger) \
+ do { \
+ int sleeps = 0; \
+ do { \
+ __sync_synchronize(); \
+ if (trigger.value) \
+ break; \
+ usleep(10); \
+ if (sleeps++ >= 100000) { \
+ ADD_FAILURE(); \
+ break; \
+ } \
+ } while (true); \
+ } while (false)
+
+
+class LocalIsolationModule : public IsolationModule
+{
+public:
+ Executor *executor;
+ MesosExecutorDriver *driver;
+ string pid;
+
+ LocalIsolationModule(Executor *_executor)
+ : executor(_executor), driver(NULL) {}
+
+ virtual ~LocalIsolationModule() {}
+
+ virtual void initialize(Slave *slave) {
+ pid = slave->self();
+ }
+
+ virtual void startExecutor(Framework *framework) {
+ // TODO(benh): Cleanup the way we launch local drivers!
+ setenv("MESOS_LOCAL", "1", 1);
+ setenv("MESOS_SLAVE_PID", pid.c_str(), 1);
+ setenv("MESOS_FRAMEWORK_ID", framework->id.c_str(), 1);
+
+ driver = new MesosExecutorDriver(executor);
+ driver->start();
+ }
+
+ virtual void killExecutor(Framework* framework) {
+ driver->stop();
+ driver->join();
+ delete driver;
+
+ // TODO(benh): Cleanup the way we launch local drivers!
+ unsetenv("MESOS_LOCAL");
+ unsetenv("MESOS_SLAVE_PID");
+ unsetenv("MESOS_FRAMEWORK_ID");
+ }
+};
+
+
+TEST(MasterTest, ResourceOfferForMultipleSlaves)
{
ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
PID master = local::launch(10, 2, 1 * Gigabyte, false, false);
- NoopScheduler sched(10);
+
+ MockScheduler sched;
MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_TRUE(sched.registeredCalled);
- EXPECT_EQ(1, sched.offersGotten);
+
+ vector<SlaveOffer> offers;
+
+ trigger resourceOfferCall;
+
+ EXPECT_CALL(sched, getFrameworkName(&driver))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched, getExecutorInfo(&driver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched, registered(&driver, _))
+ .Times(1);
+
+ EXPECT_CALL(sched, resourceOffer(&driver, _, _))
+ .WillOnce(DoAll(SaveArg<2>(&offers), Trigger(&resourceOfferCall)));
+
+ EXPECT_CALL(sched, offerRescinded(&driver, _))
+ .Times(AtMost(1));
+
+ driver.start();
+
+ WAIT_UNTIL(resourceOfferCall);
+
+ ASSERT_GE(10, offers.size());
+ EXPECT_EQ("2", offers[0].params["cpus"]);
+ EXPECT_EQ("1024", offers[0].params["mem"]);
+
+ driver.stop();
+ driver.join();
+
local::shutdown();
}
-class FixedResponseScheduler : public Scheduler
+class ReplyToOfferErrorTest : public testing::Test
{
-public:
- vector<TaskDescription> response;
- string errorMessage;
-
- FixedResponseScheduler(vector<TaskDescription> _response)
- : response(_response) {}
-
- virtual ~FixedResponseScheduler() {}
+protected:
+ ReplyToOfferErrorTest() : driver(NULL)
+ {
+ PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
+ driver = new MesosSchedulerDriver(&sched, master);
+ }
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
+ virtual ~ReplyToOfferErrorTest()
+ {
+ delete driver;
}
- virtual void resourceOffer(SchedulerDriver* d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "FixedResponseScheduler got a slot offer";
- d->replyToOffer(id, response, map<string, string>());
+ virtual void SetUp()
+ {
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+ trigger resourceOfferCall;
+
+ EXPECT_CALL(sched, getFrameworkName(driver))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched, getExecutorInfo(driver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched, registered(driver, _))
+ .Times(1);
+
+ EXPECT_CALL(sched, resourceOffer(driver, _, ElementsAre(_)))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&resourceOfferCall)));
+
+ driver->start();
+
+ WAIT_UNTIL(resourceOfferCall);
+
+ ASSERT_GE(1, offers.size());
+ EXPECT_EQ("3", offers[0].params["cpus"]);
+ EXPECT_EQ("3072", offers[0].params["mem"]);
}
-
- virtual void error(SchedulerDriver* d,
- int code,
- const std::string& message) {
- errorMessage = message;
- d->stop();
+
+ virtual void TearDown()
+ {
+ ASSERT_NE("", message);
+
+ trigger errorCall;
+
+ EXPECT_CALL(sched, error(driver, _, message))
+ .WillOnce(Trigger(&errorCall));
+
+ EXPECT_CALL(sched, offerRescinded(driver, offerId))
+ .Times(AtMost(1));
+
+ driver->replyToOffer(offerId, tasks, map<string, string>());
+
+ WAIT_UNTIL(errorCall);
+
+ driver->stop();
+ driver->join();
+
+ local::shutdown();
}
+
+ MockScheduler sched;
+ MesosSchedulerDriver *driver;
+
+ OfferID offerId;
+ vector<SlaveOffer> offers;
+
+ map<string, string> params;
+ vector<TaskDescription> tasks;
+ string message;
};
-TEST(MasterTest, DuplicateTaskIdsInResponse)
+TEST_F(ReplyToOfferErrorTest, DuplicateTaskIdsInResponse)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "1";
params["mem"] = lexical_cast<string>(1 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- tasks.push_back(TaskDescription(2, "0-0", "", params, ""));
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Duplicate task ID: 1", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+ tasks.push_back(TaskDescription(2, offers[0].slaveId, "", params, bytes()));
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+
+ message = "Duplicate task ID: 1";
}
-TEST(MasterTest, TooMuchMemoryInTask)
+TEST_F(ReplyToOfferErrorTest, TooMuchMemoryInTask)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "1";
params["mem"] = lexical_cast<string>(4 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Too many resources accepted", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+
+ message = "Too many resources accepted";
}
-TEST(MasterTest, TooMuchCpuInTask)
+TEST_F(ReplyToOfferErrorTest, TooMuchCpuInTask)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "4";
params["mem"] = lexical_cast<string>(1 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Too many resources accepted", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+ message = "Too many resources accepted";
}
-TEST(MasterTest, TooLittleCpuInTask)
+TEST_F(ReplyToOfferErrorTest, TooLittleCpuInTask)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "0";
params["mem"] = lexical_cast<string>(1 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Invalid task size: <0 CPUs, 1024 MEM>", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+ message = "Invalid task size: <0 CPUs, 1024 MEM>";
}
-TEST(MasterTest, TooLittleMemoryInTask)
+TEST_F(ReplyToOfferErrorTest, TooLittleMemoryInTask)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "1";
params["mem"] = "1";
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Invalid task size: <1 CPUs, 1 MEM>", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+
+ message = "Invalid task size: <1 CPUs, 1 MEM>";
}
-TEST(MasterTest, TooMuchMemoryAcrossTasks)
+TEST_F(ReplyToOfferErrorTest, TooMuchMemoryAcrossTasks)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "1";
params["mem"] = lexical_cast<string>(2 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- tasks.push_back(TaskDescription(2, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Too many resources accepted", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+ tasks.push_back(TaskDescription(2, offers[0].slaveId, "", params, bytes()));
+
+ message = "Too many resources accepted";
}
-TEST(MasterTest, TooMuchCpuAcrossTasks)
+TEST_F(ReplyToOfferErrorTest, TooMuchCpuAcrossTasks)
{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
- PID master = local::launch(1, 3, 3 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
- map<string, string> params;
params["cpus"] = "2";
params["mem"] = lexical_cast<string>(1 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- tasks.push_back(TaskDescription(2, "0-0", "", params, ""));
- FixedResponseScheduler sched(tasks);
- MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_EQ("Too many resources accepted", sched.errorMessage);
- local::shutdown();
+
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+ tasks.push_back(TaskDescription(2, offers[0].slaveId, "", params, bytes()));
+
+ message = "Too many resources accepted";
}
TEST(MasterTest, ResourcesReofferedAfterReject)
{
ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
PID master = local::launch(10, 2, 1 * Gigabyte, false, false);
- NoopScheduler sched1(10);
+ MockScheduler sched1;
MesosSchedulerDriver driver1(&sched1, master);
- driver1.run();
- EXPECT_TRUE(sched1.registeredCalled);
- EXPECT_EQ(1, sched1.offersGotten);
- NoopScheduler sched2(10);
+ OfferID offerId;
+
+ trigger sched1ResourceOfferCall;
+
+ EXPECT_CALL(sched1, getFrameworkName(&driver1))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched1, getExecutorInfo(&driver1))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched1, registered(&driver1, _))
+ .Times(1);
+
+ EXPECT_CALL(sched1, resourceOffer(&driver1, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), Trigger(&sched1ResourceOfferCall)));
+
+ driver1.start();
+
+ WAIT_UNTIL(sched1ResourceOfferCall);
+
+ driver1.replyToOffer(offerId, vector<TaskDescription>(), map<string, string>());
+
+ driver1.stop();
+ driver1.join();
+
+ MockScheduler sched2;
MesosSchedulerDriver driver2(&sched2, master);
- driver2.run();
- EXPECT_TRUE(sched2.registeredCalled);
- EXPECT_EQ(1, sched2.offersGotten);
+
+ trigger sched2ResourceOfferCall;
+
+ EXPECT_CALL(sched2, getFrameworkName(&driver2))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched2, getExecutorInfo(&driver2))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched2, registered(&driver2, _))
+ .Times(1);
+
+ EXPECT_CALL(sched2, resourceOffer(&driver2, _, _))
+ .WillOnce(Trigger(&sched2ResourceOfferCall));
+
+ EXPECT_CALL(sched2, offerRescinded(&driver2, _))
+ .Times(AtMost(1));
+
+ driver2.start();
+
+ WAIT_UNTIL(sched2ResourceOfferCall);
+
+ driver2.stop();
+ driver2.join();
local::shutdown();
}
@@ -276,55 +420,87 @@ TEST(MasterTest, ResourcesReofferedAfter
TEST(MasterTest, ResourcesReofferedAfterBadResponse)
{
ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
PID master = local::launch(1, 2, 1 * Gigabyte, false, false);
- vector<TaskDescription> tasks;
+ MockScheduler sched1;
+ MesosSchedulerDriver driver1(&sched1, master);
+
+ OfferID offerId;
+ vector<SlaveOffer> offers;
+
+ trigger sched1ResourceOfferCall;
+
+ EXPECT_CALL(sched1, getFrameworkName(&driver1))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched1, getExecutorInfo(&driver1))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched1, registered(&driver1, _))
+ .Times(1);
+
+ EXPECT_CALL(sched1, resourceOffer(&driver1, _, ElementsAre(_)))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&sched1ResourceOfferCall)));
+
+ driver1.start();
+
+ WAIT_UNTIL(sched1ResourceOfferCall);
+
+ ASSERT_GE(1, offers.size());
+
map<string, string> params;
params["cpus"] = "0";
params["mem"] = lexical_cast<string>(1 * Gigabyte);
- tasks.push_back(TaskDescription(1, "0-0", "", params, ""));
- FixedResponseScheduler sched1(tasks);
- MesosSchedulerDriver driver1(&sched1, master);
- driver1.run();
- EXPECT_EQ("Invalid task size: <0 CPUs, 1024 MEM>", sched1.errorMessage);
- NoopScheduler sched2(1);
+ vector<TaskDescription> tasks;
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", params, bytes()));
+
+ trigger errorCall;
+
+ EXPECT_CALL(sched1, error(&driver1, _, "Invalid task size: <0 CPUs, 1024 MEM>"))
+ .WillOnce(Trigger(&errorCall));
+
+ EXPECT_CALL(sched1, offerRescinded(&driver1, offerId))
+ .Times(AtMost(1));
+
+ driver1.replyToOffer(offerId, tasks, map<string, string>());
+
+ WAIT_UNTIL(errorCall);
+
+ driver1.stop();
+ driver1.join();
+
+ MockScheduler sched2;
MesosSchedulerDriver driver2(&sched2, master);
- driver2.run();
- EXPECT_TRUE(sched2.registeredCalled);
- EXPECT_EQ(1, sched2.offersGotten);
- local::shutdown();
-}
+ trigger sched2ResourceOfferCall;
+ EXPECT_CALL(sched2, getFrameworkName(&driver2))
+ .WillOnce(Return(""));
-class SlaveLostScheduler : public Scheduler
-{
-public:
- PID slave;
- bool slaveLostCalled;
-
- SlaveLostScheduler(const PID &_slave)
- : slave(_slave), slaveLostCalled(false) {}
+ EXPECT_CALL(sched2, getExecutorInfo(&driver2))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- virtual ~SlaveLostScheduler() {}
+ EXPECT_CALL(sched2, registered(&driver2, _))
+ .Times(1);
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ EXPECT_CALL(sched2, resourceOffer(&driver2, _, _))
+ .WillOnce(Trigger(&sched2ResourceOfferCall));
- virtual void resourceOffer(SchedulerDriver* d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "SlaveLostScheduler got a slot offer";
- MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
- }
-
- virtual void slaveLost(SchedulerDriver* d, SlaveID slaveId) {
- slaveLostCalled = true;
- d->stop();
- }
-};
+ EXPECT_CALL(sched2, offerRescinded(&driver2, _))
+ .Times(AtMost(1));
+
+ driver2.start();
+
+ WAIT_UNTIL(sched2ResourceOfferCall);
+
+ driver2.stop();
+ driver2.join();
+
+ local::shutdown();
+}
TEST(MasterTest, SlaveLost)
@@ -340,74 +516,54 @@ TEST(MasterTest, SlaveLost)
BasicMasterDetector detector(master, slave, true);
- SlaveLostScheduler sched(slave);
-
+ MockScheduler sched;
MesosSchedulerDriver driver(&sched, master);
- driver.run();
- EXPECT_TRUE(sched.slaveLostCalled);
+ OfferID offerId;
+ vector<SlaveOffer> offers;
- Process::wait(slave);
+ trigger resourceOfferCall;
- MesosProcess::post(master, pack<M2M_SHUTDOWN>());
- Process::wait(master);
-}
+ EXPECT_CALL(sched, getFrameworkName(&driver))
+ .WillOnce(Return(""));
+ EXPECT_CALL(sched, getExecutorInfo(&driver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+ EXPECT_CALL(sched, registered(&driver, _))
+ .Times(1);
-class FailoverScheduler : public Scheduler
-{
-public:
- bool registeredCalled;
-
- FailoverScheduler() : registeredCalled(false) {}
+ EXPECT_CALL(sched, resourceOffer(&driver, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&resourceOfferCall)));
- virtual ~FailoverScheduler() {}
+ driver.start();
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ WAIT_UNTIL(resourceOfferCall);
- virtual void registered(SchedulerDriver *d, FrameworkID fid) {
- LOG(INFO) << "FailoverScheduler registered";
- registeredCalled = true;
- d->stop();
- }
-};
+ ASSERT_GE(1, offers.size());
+ trigger offerRescindedCall, slaveLostCall;
-class FailingScheduler : public Scheduler
-{
-public:
- Scheduler *failover;
- PID master;
- MesosSchedulerDriver *driver;
- string errorMessage;
+ EXPECT_CALL(sched, offerRescinded(&driver, offerId))
+ .WillOnce(Trigger(&offerRescindedCall));
- FailingScheduler(Scheduler *_failover, const PID &_master)
- : failover(_failover), master(_master) {}
+ EXPECT_CALL(sched, slaveLost(&driver, offers[0].slaveId))
+ .WillOnce(Trigger(&slaveLostCall));
- virtual ~FailingScheduler() {
- delete driver;
- }
+ MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ WAIT_UNTIL(offerRescindedCall);
+ WAIT_UNTIL(slaveLostCall);
- virtual void registered(SchedulerDriver*, FrameworkID fid) {
- LOG(INFO) << "FailingScheduler registered";
- driver = new MesosSchedulerDriver(failover, master, fid);
- driver->start();
- }
+ driver.stop();
+ driver.join();
- virtual void error(SchedulerDriver* d,
- int code,
- const std::string& message) {
- errorMessage = message;
- d->stop();
- }
-};
+ Process::wait(slave);
+
+ MesosProcess::post(master, pack<M2M_SHUTDOWN>());
+ Process::wait(master);
+}
TEST(MasterTest, SchedulerFailover)
@@ -416,271 +572,201 @@ TEST(MasterTest, SchedulerFailover)
PID master = local::launch(1, 2, 1 * Gigabyte, false, false);
- FailoverScheduler failoverSched;
- FailingScheduler failingSched(&failoverSched, master);
+ // Launch the first (i.e., failing) scheduler and wait until
+ // registered gets called to launch the second (i.e., failover)
+ // scheduler.
- MesosSchedulerDriver driver(&failingSched, master);
- driver.run();
+ MockScheduler failingSched;
+ MesosSchedulerDriver failingDriver(&failingSched, master);
- EXPECT_EQ("Framework failover", failingSched.errorMessage);
+ FrameworkID frameworkId;
- failingSched.driver->join();
+ trigger failingRegisteredCall;
- EXPECT_TRUE(failoverSched.registeredCalled);
+ EXPECT_CALL(failingSched, getFrameworkName(&failingDriver))
+ .WillOnce(Return(""));
- local::shutdown();
-}
+ EXPECT_CALL(failingSched, getExecutorInfo(&failingDriver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+ EXPECT_CALL(failingSched, registered(&failingDriver, _))
+ .WillOnce(DoAll(SaveArg<1>(&frameworkId), Trigger(&failingRegisteredCall)));
-class OfferRescindedScheduler : public Scheduler
-{
-public:
- const PID slave;
- bool offerRescindedCalled;
-
- OfferRescindedScheduler(const PID &_slave)
- : slave(_slave), offerRescindedCalled(false) {}
-
- virtual ~OfferRescindedScheduler() {}
+ EXPECT_CALL(failingSched, resourceOffer(&failingDriver, _, _))
+ .Times(AtMost(1));
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ EXPECT_CALL(failingSched, offerRescinded(&failingDriver, _))
+ .Times(AtMost(1));
- virtual void resourceOffer(SchedulerDriver* d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "OfferRescindedScheduler got a slot offer";
- vector<TaskDescription> tasks;
- ASSERT_TRUE(offers.size() == 1);
- const SlaveOffer &offer = offers[0];
- TaskDescription desc(0, offer.slaveId, "", offer.params, "");
- tasks.push_back(desc);
- d->replyToOffer(id, tasks, map<string, string>());
- MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
- }
+ EXPECT_CALL(failingSched, error(&failingDriver, _, "Framework failover"))
+ .Times(1);
- virtual void offerRescinded(SchedulerDriver* d, OfferID)
- {
- offerRescindedCalled = true;
- d->stop();
- }
-};
+ failingDriver.start();
+ WAIT_UNTIL(failingRegisteredCall);
-class OfferReplyMessageFilter : public MessageFilter
-{
-public:
- virtual bool filter(struct msg *msg) {
- return msg->id == F2M_SLOT_OFFER_REPLY;
- }
-};
+ // Now launch the second (i.e., failover) scheduler using the
+ // framework id recorded from the first scheduler and wait until it
+ // gets a registered callback..
+ MockScheduler failoverSched;
+ MesosSchedulerDriver failoverDriver(&failoverSched, master, frameworkId);
-TEST(MasterTest, OfferRescinded)
-{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
+ trigger failoverRegisteredCall;
- OfferReplyMessageFilter filter;
- Process::filter(&filter);
+ EXPECT_CALL(failoverSched, getFrameworkName(&failoverDriver))
+ .WillOnce(Return(""));
- Master m;
- PID master = Process::spawn(&m);
+ EXPECT_CALL(failoverSched, getExecutorInfo(&failoverDriver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- ProcessBasedIsolationModule isolationModule;
- Slave s(Resources(2, 1 * Gigabyte), true, &isolationModule);
- PID slave = Process::spawn(&s);
+ EXPECT_CALL(failoverSched, registered(&failoverDriver, frameworkId))
+ .WillOnce(Trigger(&failoverRegisteredCall));
- BasicMasterDetector detector(master, slave, true);
+ EXPECT_CALL(failoverSched, resourceOffer(&failoverDriver, _, _))
+ .Times(AtMost(1));
- OfferRescindedScheduler sched(slave);
- MesosSchedulerDriver driver(&sched, master);
+ EXPECT_CALL(failoverSched, offerRescinded(&failoverDriver, _))
+ .Times(AtMost(1));
- driver.run();
+ failoverDriver.start();
- EXPECT_TRUE(sched.offerRescindedCalled);
+ WAIT_UNTIL(failoverRegisteredCall);
- Process::wait(slave);
+ failingDriver.stop();
+ failoverDriver.stop();
- MesosProcess::post(master, pack<M2M_SHUTDOWN>());
- Process::wait(master);
+ failingDriver.join();
+ failoverDriver.join();
- Process::filter(NULL);
+ local::shutdown();
}
-class SlavePartitionedScheduler : public Scheduler
+TEST(MasterTest, SlavePartitioned)
{
-public:
- bool slaveLostCalled;
-
- SlavePartitionedScheduler()
- : slaveLostCalled(false) {}
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
- virtual ~SlavePartitionedScheduler() {}
+ ProcessClock::pause();
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ MockFilter filter;
+ Process::filter(&filter);
- virtual void slaveLost(SchedulerDriver* d, SlaveID slaveId) {
- slaveLostCalled = true;
- d->stop();
- }
-};
+ EXPECT_MSG(filter, _, _, _)
+ .WillRepeatedly(Return(false));
+ PID master = local::launch(1, 2, 1 * Gigabyte, false, false);
-class HeartbeatMessageFilter : public MessageFilter
-{
-public:
- virtual bool filter(struct msg *msg) {
- return msg->id == SH2M_HEARTBEAT;
- }
-};
+ MockScheduler sched;
+ MesosSchedulerDriver driver(&sched, master);
+ trigger slaveLostCall;
-TEST(MasterTest, SlavePartitioned)
-{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
+ EXPECT_CALL(sched, getFrameworkName(&driver))
+ .WillOnce(Return(""));
- HeartbeatMessageFilter filter;
- Process::filter(&filter);
+ EXPECT_CALL(sched, getExecutorInfo(&driver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- ProcessClock::pause();
+ EXPECT_CALL(sched, registered(&driver, _))
+ .Times(1);
- PID master = local::launch(1, 2, 1 * Gigabyte, false, false);
+ EXPECT_CALL(sched, resourceOffer(&driver, _, _))
+ .Times(AtMost(1));
- SlavePartitionedScheduler sched;
- MesosSchedulerDriver driver(&sched, master);
+ EXPECT_CALL(sched, offerRescinded(&driver, _))
+ .Times(AtMost(1));
+
+ EXPECT_CALL(sched, slaveLost(&driver, _))
+ .WillOnce(Trigger(&slaveLostCall));
+
+ EXPECT_MSG(filter, Eq(SH2M_HEARTBEAT), _, _)
+ .WillRepeatedly(Return(true));
driver.start();
ProcessClock::advance(master::HEARTBEAT_TIMEOUT);
- driver.join();
+ WAIT_UNTIL(slaveLostCall);
- EXPECT_TRUE(sched.slaveLostCalled);
+ driver.stop();
+ driver.join();
local::shutdown();
- ProcessClock::resume();
-
Process::filter(NULL);
+
+ ProcessClock::resume();
}
-class TaskRunningScheduler : public Scheduler
+TEST(MasterTest, TaskRunning)
{
-public:
- FrameworkID fid;
- bool statusUpdateCalled;
- string errorMessage;
-
- TaskRunningScheduler()
- : statusUpdateCalled(false) {}
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
- virtual ~TaskRunningScheduler() {}
+ Master m;
+ PID master = Process::spawn(&m);
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ MockExecutor exec;
- virtual void registered(SchedulerDriver*, FrameworkID fid) {
- LOG(INFO) << "TaskRunningScheduler registered";
- this->fid = fid;
- }
+ EXPECT_CALL(exec, init(_, _))
+ .Times(1);
- virtual void resourceOffer(SchedulerDriver* d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "TaskRunningScheduler got a slot offer";
- vector<TaskDescription> tasks;
- ASSERT_TRUE(offers.size() == 1);
- const SlaveOffer &offer = offers[0];
- TaskDescription desc(0, offer.slaveId, "", offer.params, "");
- tasks.push_back(desc);
- d->replyToOffer(id, tasks, map<string, string>());
- }
+ EXPECT_CALL(exec, launchTask(_, _))
+ .Times(1);
- virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
- EXPECT_EQ(TASK_RUNNING, status.state);
- statusUpdateCalled = true;
- d->stop();
- }
+ EXPECT_CALL(exec, shutdown(_))
+ .Times(1);
- virtual void error(SchedulerDriver* d,
- int code,
- const std::string& message) {
- errorMessage = message;
- d->stop();
- }
-};
+ LocalIsolationModule isolationModule(&exec);
+ Slave s(Resources(2, 1 * Gigabyte), true, &isolationModule);
+ PID slave = Process::spawn(&s);
-class TaskRunningExecutor : public Executor {};
+ BasicMasterDetector detector(master, slave, true);
+ MockScheduler sched;
+ MesosSchedulerDriver driver(&sched, master);
-class LocalIsolationModule : public IsolationModule
-{
-public:
- Executor *executor;
- MesosExecutorDriver *driver;
- string pid;
+ OfferID offerId;
+ vector<SlaveOffer> offers;
+ TaskStatus status;
- LocalIsolationModule(Executor *_executor)
- : executor(_executor), driver(NULL) {}
+ trigger resourceOfferCall, statusUpdateCall;
- virtual ~LocalIsolationModule() {}
+ EXPECT_CALL(sched, getFrameworkName(&driver))
+ .WillOnce(Return(""));
- virtual void initialize(Slave *slave) {
- pid = slave->self();
- }
+ EXPECT_CALL(sched, getExecutorInfo(&driver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- virtual void startExecutor(Framework *framework) {
- // TODO(benh): Cleanup the way we launch local drivers!
- setenv("MESOS_LOCAL", "1", 1);
- setenv("MESOS_SLAVE_PID", pid.c_str(), 1);
- setenv("MESOS_FRAMEWORK_ID", framework->id.c_str(), 1);
+ EXPECT_CALL(sched, registered(&driver, _))
+ .Times(1);
- driver = new MesosExecutorDriver(executor);
- driver->start();
- }
+ EXPECT_CALL(sched, resourceOffer(&driver, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&resourceOfferCall)));
- virtual void killExecutor(Framework* framework) {
- driver->stop();
- driver->join();
- delete driver;
+ EXPECT_CALL(sched, statusUpdate(&driver, _))
+ .WillOnce(DoAll(SaveArg<1>(&status), Trigger(&statusUpdateCall)));
- // TODO(benh): Cleanup the way we launch local drivers!
- unsetenv("MESOS_LOCAL");
- unsetenv("MESOS_SLAVE_PID");
- unsetenv("MESOS_FRAMEWORK_ID");
- }
-};
-
-
-TEST(MasterTest, TaskRunning)
-{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
+ driver.start();
- Master m;
- PID master = Process::spawn(&m);
+ WAIT_UNTIL(resourceOfferCall);
- TaskRunningExecutor exec;
- LocalIsolationModule isolationModule(&exec);
+ ASSERT_GE(1, offers.size());
- Slave s(Resources(2, 1 * Gigabyte), true, &isolationModule);
- PID slave = Process::spawn(&s);
+ vector<TaskDescription> tasks;
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", offers[0].params, ""));
- BasicMasterDetector detector(master, slave, true);
+ driver.replyToOffer(offerId, tasks, map<string, string>());
- TaskRunningScheduler sched;
- MesosSchedulerDriver driver(&sched, master);
+ WAIT_UNTIL(statusUpdateCall);
- driver.run();
+ EXPECT_EQ(TASK_RUNNING, status.state);
- EXPECT_TRUE(sched.statusUpdateCalled);
- EXPECT_EQ("", sched.errorMessage);
+ driver.stop();
+ driver.join();
MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
Process::wait(slave);
@@ -690,220 +776,247 @@ TEST(MasterTest, TaskRunning)
}
-class SchedulerFailoverStatusUpdateScheduler : public TaskRunningScheduler
+TEST(MasterTest, SchedulerFailoverStatusUpdate)
{
- public:
- virtual void registered(SchedulerDriver*, FrameworkID fid) {
- Process::filter(NULL);
- ProcessClock::advance(RELIABLE_TIMEOUT);
- }
-};
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
+ ProcessClock::pause();
-class StatusUpdateFilter : public MessageFilter
-{
-public:
- TaskRunningScheduler *failover;
- TaskRunningScheduler *failing;
- const PID master;
- MesosSchedulerDriver *driver;
+ MockFilter filter;
+ Process::filter(&filter);
- StatusUpdateFilter(TaskRunningScheduler *_failover,
- TaskRunningScheduler *_failing,
- const PID &_master)
- : failover(_failover), failing(_failing), master(_master),
- driver(NULL) {}
-
- ~StatusUpdateFilter() {
- if (driver != NULL) {
- driver->join();
- delete driver;
- driver = NULL;
- }
- }
+ EXPECT_MSG(filter, _, _, _)
+ .WillRepeatedly(Return(false));
- virtual bool filter(struct msg *msg) {
- // TODO(benh): Fix the brokenness of this test due to blocking
- // S2M_FT_STATUS_UPDATE!
- if (driver == NULL &&
- msg->id == S2M_FT_STATUS_UPDATE &&
- !(msg->to == master)) {
- driver = new MesosSchedulerDriver(failover, master, failing->fid);
- driver->start();
- return true;
- }
+ MockExecutor exec;
- return false;
- }
-};
+ EXPECT_CALL(exec, init(_, _))
+ .Times(1);
+ EXPECT_CALL(exec, launchTask(_, _))
+ .Times(1);
-TEST(MasterTest, SchedulerFailoverStatusUpdate)
-{
- ASSERT_TRUE(GTEST_IS_THREADSAFE);
+ EXPECT_CALL(exec, shutdown(_))
+ .Times(1);
- ProcessClock::pause();
+ LocalIsolationModule isolationModule(&exec);
+// <<<<<<<<<<<<<<
+// PID master;
+// vector<PID> slaves;
+
+// tie(master, slaves) =
+// local::launch(1, 2, 1 * Gigabyte, false, false, isolationModule);
+// >>>>>>>>>>>>>>
Master m;
PID master = Process::spawn(&m);
- TaskRunningExecutor exec;
- LocalIsolationModule isolationModule(&exec);
-
Slave s(Resources(2, 1 * Gigabyte), true, &isolationModule);
PID slave = Process::spawn(&s);
BasicMasterDetector detector(master, slave, true);
+// >>>>>>>>>>>>>>
- SchedulerFailoverStatusUpdateScheduler failoverSched;
- TaskRunningScheduler failingSched;
+ // Launch the first (i.e., failing) scheduler and wait until the
+ // first status update message is sent to it (drop the message).
- StatusUpdateFilter filter(&failoverSched, &failingSched, master);
- Process::filter(&filter);
+ MockScheduler failingSched;
+ MesosSchedulerDriver failingDriver(&failingSched, master);
- MesosSchedulerDriver driver(&failingSched, master);
+ FrameworkID frameworkId;
+ OfferID offerId;
+ vector<SlaveOffer> offers;
- driver.run();
+ trigger resourceOfferCall;
- EXPECT_FALSE(failingSched.statusUpdateCalled);
- EXPECT_EQ("Framework failover", failingSched.errorMessage);
+ EXPECT_CALL(failingSched, getFrameworkName(&failingDriver))
+ .WillOnce(Return(""));
- filter.driver->join();
+ EXPECT_CALL(failingSched, getExecutorInfo(&failingDriver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- EXPECT_TRUE(failoverSched.statusUpdateCalled);
- EXPECT_EQ("", failoverSched.errorMessage);
+ EXPECT_CALL(failingSched, registered(&failingDriver, _))
+ .WillOnce(SaveArg<1>(&frameworkId));
- Process::filter(NULL);
+ EXPECT_CALL(failingSched, resourceOffer(&failingDriver, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&resourceOfferCall)));
- MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
- Process::wait(slave);
+ EXPECT_CALL(failingSched, error(&failingDriver, _, "Framework failover"))
+ .Times(1);
- MesosProcess::post(master, pack<M2M_SHUTDOWN>());
- Process::wait(master);
+ EXPECT_CALL(failingSched, statusUpdate(&failingDriver, _))
+ .Times(0);
- ProcessClock::resume();
-}
+ trigger statusUpdateMsg;
+ EXPECT_MSG(filter, Eq(S2M_FT_STATUS_UPDATE), _, Ne(master))
+ .WillOnce(DoAll(Trigger(&statusUpdateMsg), Return(true)))
+ .RetiresOnSaturation();
-// An executor used in the framework message test that just sends a reply
-// to each message received and logs the last message.
-class FrameworkMessageExecutor : public Executor
-{
-public:
- bool messageReceived;
- string messageData;
- SlaveID mySlaveId;
+ failingDriver.start();
- FrameworkMessageExecutor(): messageReceived(false) {}
+ WAIT_UNTIL(resourceOfferCall);
- virtual ~FrameworkMessageExecutor() {}
+ ASSERT_GE(1, offers.size());
- virtual void init(ExecutorDriver* d, const ExecutorArgs& args) {
- mySlaveId = args.slaveId;
- }
+ vector<TaskDescription> tasks;
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", offers[0].params, ""));
- virtual void frameworkMessage(ExecutorDriver* d, const FrameworkMessage& m) {
- LOG(INFO) << "FrameworkMessageExecutor got a message";
- messageReceived = true;
- messageData = m.data;
- // Send a message back to the scheduler, which will cause it to exit
- FrameworkMessage reply(mySlaveId, 0, "reply");
- d->sendFrameworkMessage(reply);
- LOG(INFO) << "Sent the reply back";
- }
-};
+ failingDriver.replyToOffer(offerId, tasks, map<string, string>());
+ WAIT_UNTIL(statusUpdateMsg);
-// A scheduler used in the framework message test that launches a task, waits
-// for it to start, sends it a framework message, and waits for a reply.
-class FrameworkMessageScheduler : public Scheduler
-{
-public:
- FrameworkID fid;
- string errorMessage;
- bool messageReceived;
- string messageData;
- SlaveID slaveIdOfTask;
+ // Now launch the second (i.e., failover) scheduler using the
+ // framework id recorded from the first scheduler and wait until it
+ // registers, at which point advance time enough for the reliable
+ // timeout to kick in and another status update message is sent.
- FrameworkMessageScheduler() {}
+ MockScheduler failoverSched;
+ MesosSchedulerDriver failoverDriver(&failoverSched, master, frameworkId);
- virtual ~FrameworkMessageScheduler() {}
+ trigger registeredCall, statusUpdateCall;
- virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
- return ExecutorInfo("noexecutor", "");
- }
+ EXPECT_CALL(failoverSched, getFrameworkName(&failoverDriver))
+ .WillOnce(Return(""));
- virtual void registered(SchedulerDriver*, FrameworkID fid) {
- LOG(INFO) << "FrameworkMessageScheduler registered";
- this->fid = fid;
- }
+ EXPECT_CALL(failoverSched, getExecutorInfo(&failoverDriver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
- virtual void resourceOffer(SchedulerDriver* d,
- OfferID id,
- const vector<SlaveOffer>& offers) {
- LOG(INFO) << "FrameworkMessageScheduler got a slot offer";
- vector<TaskDescription> tasks;
- ASSERT_TRUE(offers.size() == 1);
- const SlaveOffer &offer = offers[0];
- TaskDescription desc(0, offer.slaveId, "", offer.params, "");
- tasks.push_back(desc);
- slaveIdOfTask = offer.slaveId;
- d->replyToOffer(id, tasks, map<string, string>());
- }
+ EXPECT_CALL(failoverSched, registered(&failoverDriver, frameworkId))
+ .WillOnce(Trigger(®isteredCall));
+ EXPECT_CALL(failoverSched, statusUpdate(&failoverDriver, _))
+ .WillOnce(Trigger(&statusUpdateCall));
- virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
- EXPECT_EQ(TASK_RUNNING, status.state);
- LOG(INFO) << "Task is running; sending it a framework message";
- FrameworkMessage message(slaveIdOfTask, 0, "hello");
- d->sendFrameworkMessage(message);
- }
+ failoverDriver.start();
+ WAIT_UNTIL(registeredCall);
- virtual void frameworkMessage(SchedulerDriver* d, const FrameworkMessage& m) {
- LOG(INFO) << "FrameworkMessageScheduler got a message";
- messageReceived = true;
- messageData = m.data;
- // Stop our driver because the test is complete
- d->stop();
- }
+ ProcessClock::advance(RELIABLE_TIMEOUT);
- virtual void error(SchedulerDriver* d,
- int code,
- const std::string& message) {
- errorMessage = message;
- d->stop();
- }
-};
+ WAIT_UNTIL(statusUpdateCall);
+
+ failingDriver.stop();
+ failoverDriver.stop();
+
+ failingDriver.join();
+ failoverDriver.join();
+
+// <<<<<<<<<<<<<<
+// local::shutdown();
+// >>>>>>>>>>>>>>
+ MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
+ Process::wait(slave);
+
+ MesosProcess::post(master, pack<M2M_SHUTDOWN>());
+ Process::wait(master);
+// >>>>>>>>>>>>>>
+ Process::filter(NULL);
+
+ ProcessClock::resume();
+}
-// Tests that framework messages are sent correctly both in both the
-// scheduler->executor direction and the executor->scheduler direction.
TEST(MasterTest, FrameworkMessages)
{
ASSERT_TRUE(GTEST_IS_THREADSAFE);
- Master m;
- PID master = Process::spawn(&m);
+ MockExecutor exec;
+
+ ExecutorDriver *execDriver;
+ ExecutorArgs args;
+ FrameworkMessage execMessage;
+
+ trigger execFrameworkMessageCall;
+
+ EXPECT_CALL(exec, init(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&execDriver), SaveArg<1>(&args)));
+
+ EXPECT_CALL(exec, launchTask(_, _))
+ .Times(1);
+
+ EXPECT_CALL(exec, frameworkMessage(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&execMessage),
+ Trigger(&execFrameworkMessageCall)));
+
+ EXPECT_CALL(exec, shutdown(_))
+ .Times(1);
- FrameworkMessageExecutor exec;
LocalIsolationModule isolationModule(&exec);
+ Master m;
+ PID master = Process::spawn(&m);
+
Slave s(Resources(2, 1 * Gigabyte), true, &isolationModule);
PID slave = Process::spawn(&s);
BasicMasterDetector detector(master, slave, true);
- FrameworkMessageScheduler sched;
- MesosSchedulerDriver driver(&sched, master);
+ // Launch the first (i.e., failing) scheduler and wait until the
+ // first status update message is sent to it (drop the message).
+
+ MockScheduler sched;
+ MesosSchedulerDriver schedDriver(&sched, master);
+
+ OfferID offerId;
+ vector<SlaveOffer> offers;
+ TaskStatus status;
+ FrameworkMessage schedMessage;
+
+ trigger resourceOfferCall, statusUpdateCall, schedFrameworkMessageCall;
+
+ EXPECT_CALL(sched, getFrameworkName(&schedDriver))
+ .WillOnce(Return(""));
+
+ EXPECT_CALL(sched, getExecutorInfo(&schedDriver))
+ .WillOnce(Return(ExecutorInfo("noexecutor", "")));
+
+ EXPECT_CALL(sched, registered(&schedDriver, _))
+ .Times(1);
+
+ EXPECT_CALL(sched, resourceOffer(&schedDriver, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&offerId), SaveArg<2>(&offers),
+ Trigger(&resourceOfferCall)));
+
+ EXPECT_CALL(sched, statusUpdate(&schedDriver, _))
+ .WillOnce(DoAll(SaveArg<1>(&status), Trigger(&statusUpdateCall)));
+
+ EXPECT_CALL(sched, frameworkMessage(&schedDriver, _))
+ .WillOnce(DoAll(SaveArg<1>(&schedMessage),
+ Trigger(&schedFrameworkMessageCall)));
+
+ schedDriver.start();
+
+ WAIT_UNTIL(resourceOfferCall);
+
+ ASSERT_GE(1, offers.size());
+
+ vector<TaskDescription> tasks;
+ tasks.push_back(TaskDescription(1, offers[0].slaveId, "", offers[0].params, ""));
+
+ schedDriver.replyToOffer(offerId, tasks, map<string, string>());
+
+ WAIT_UNTIL(statusUpdateCall);
+
+ EXPECT_EQ(TASK_RUNNING, status.state);
+
+ FrameworkMessage hello(offers[0].slaveId, 1, "hello");
+ schedDriver.sendFrameworkMessage(hello);
+
+ WAIT_UNTIL(execFrameworkMessageCall);
+
+ EXPECT_EQ("hello", execMessage.data);
+
+ FrameworkMessage reply(args.slaveId, 1, "reply");
+ execDriver->sendFrameworkMessage(reply);
+
+ WAIT_UNTIL(schedFrameworkMessageCall);
- driver.run();
+ EXPECT_EQ("reply", schedMessage.data);
- EXPECT_EQ("", sched.errorMessage);
- EXPECT_TRUE(exec.messageReceived);
- EXPECT_EQ("hello", exec.messageData);
- EXPECT_TRUE(sched.messageReceived);
- EXPECT_EQ("reply", sched.messageData);
+ schedDriver.stop();
+ schedDriver.join();
MesosProcess::post(slave, pack<S2S_SHUTDOWN>());
Process::wait(slave);
Added: incubator/mesos/trunk/third_party/gmock-1.5.0/CHANGES
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/gmock-1.5.0/CHANGES?rev=1132109&view=auto
==============================================================================
--- incubator/mesos/trunk/third_party/gmock-1.5.0/CHANGES (added)
+++ incubator/mesos/trunk/third_party/gmock-1.5.0/CHANGES Sun Jun 5 08:45:22 2011
@@ -0,0 +1,66 @@
+Changes for 1.5.0:
+
+ * New feature: Google Mock can be safely used in multi-threaded tests
+ on platforms having pthreads.
+ * New feature: function for printing a value of arbitrary type.
+ * New feature: function ExplainMatchResult() for easy definition of
+ composite matchers.
+ * The new matcher API lets user-defined matchers generate custom
+ explanations more directly and efficiently.
+ * Better failure messages all around.
+ * NotNull() and IsNull() now work with smart pointers.
+ * Field() and Property() now work when the matcher argument is a pointer
+ passed by reference.
+ * Regular expression matchers on all platforms.
+ * Added GCC 4.0 support for Google Mock Doctor.
+ * Added gmock_all_test.cc for compiling most Google Mock tests
+ in a single file.
+ * Significantly cleaned up compiler warnings.
+ * Bug fixes, better test coverage, and implementation clean-ups.
+
+ Potentially breaking changes:
+
+ * Custom matchers defined using MatcherInterface or MakePolymorphicMatcher()
+ need to be updated after upgrading to Google Mock 1.5.0; matchers defined
+ using MATCHER or MATCHER_P* aren't affected.
+ * Dropped support for 'make install'.
+
+Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of
+Google Test):
+
+ * Works in more environments: Symbian and minGW, Visual C++ 7.1.
+ * Lighter weight: comes with our own implementation of TR1 tuple (no
+ more dependency on Boost!).
+ * New feature: --gmock_catch_leaked_mocks for detecting leaked mocks.
+ * New feature: ACTION_TEMPLATE for defining templatized actions.
+ * New feature: the .After() clause for specifying expectation order.
+ * New feature: the .With() clause for for specifying inter-argument
+ constraints.
+ * New feature: actions ReturnArg<k>(), ReturnNew<T>(...), and
+ DeleteArg<k>().
+ * New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(),
+ and Contains().
+ * New feature: utility class MockFunction<F>, useful for checkpoints, etc.
+ * New feature: functions Value(x, m) and SafeMatcherCast<T>(m).
+ * New feature: copying a mock object is rejected at compile time.
+ * New feature: a script for fusing all Google Mock and Google Test
+ source files for easy deployment.
+ * Improved the Google Mock doctor to diagnose more diseases.
+ * Improved the Google Mock generator script.
+ * Compatibility fixes for Mac OS X and gcc.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.1.0:
+
+ * New feature: ability to use Google Mock with any testing framework.
+ * New feature: macros for easily defining new matchers
+ * New feature: macros for easily defining new actions.
+ * New feature: more container matchers.
+ * New feature: actions for accessing function arguments and throwing
+ exceptions.
+ * Improved the Google Mock doctor script for diagnosing compiler errors.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Mock
Added: incubator/mesos/trunk/third_party/gmock-1.5.0/CONTRIBUTORS
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/gmock-1.5.0/CONTRIBUTORS?rev=1132109&view=auto
==============================================================================
--- incubator/mesos/trunk/third_party/gmock-1.5.0/CONTRIBUTORS (added)
+++ incubator/mesos/trunk/third_party/gmock-1.5.0/CONTRIBUTORS Sun Jun 5 08:45:22 2011
@@ -0,0 +1,40 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Mocking Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Benoit Sigoure <ts...@google.com>
+Bogdan Piloca <bo...@google.com>
+Chandler Carruth <ch...@google.com>
+Dave MacLachlan <dm...@gmail.com>
+David Anderson <da...@google.com>
+Dean Sturtevant
+Gene Volovich <gv...@cite.com>
+Hal Burch <gm...@hburch.com>
+Jeffrey Yasskin <jy...@google.com>
+Jim Keller <ji...@google.com>
+Joe Walnes <jo...@truemesh.com>
+Jon Wray <jw...@google.com>
+Keir Mierle <mi...@gmail.com>
+Keith Ray <ke...@gmail.com>
+Kostya Serebryany <kc...@google.com>
+Lev Makhlis
+Manuel Klimek <kl...@google.com>
+Mario Tanev <ra...@google.com>
+Mark Paskin
+Markus Heule <ma...@gmail.com>
+Matthew Simmons <si...@acm.org>
+Mike Bland <mb...@google.com>
+Neal Norwitz <nn...@gmail.com>
+Nermin Ozkiranartli <ne...@google.com>
+Owen Carlsen <oc...@google.com>
+Paneendra Ba <pa...@google.com>
+Paul Menage <me...@google.com>
+Piotr Kaminski <pi...@google.com>
+Russ Rufer <ru...@pentad.com>
+Sverre Sundsdal <su...@gmail.com>
+Takeshi Yoshino <ty...@google.com>
+Vadim Berman <va...@google.com>
+Vlad Losev <vl...@google.com>
+Wolfgang Klier <wk...@google.com>
+Zhanyong Wan <wa...@google.com>
Copied: incubator/mesos/trunk/third_party/gmock-1.5.0/COPYING (from r1132108, incubator/mesos/trunk/third_party/gtest-1.5.0/COPYING)
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/gmock-1.5.0/COPYING?p2=incubator/mesos/trunk/third_party/gmock-1.5.0/COPYING&p1=incubator/mesos/trunk/third_party/gtest-1.5.0/COPYING&r1=1132108&r2=1132109&rev=1132109&view=diff
==============================================================================
(empty)
Added: incubator/mesos/trunk/third_party/gmock-1.5.0/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/gmock-1.5.0/Makefile.am?rev=1132109&view=auto
==============================================================================
--- incubator/mesos/trunk/third_party/gmock-1.5.0/Makefile.am (added)
+++ incubator/mesos/trunk/third_party/gmock-1.5.0/Makefile.am Sun Jun 5 08:45:22 2011
@@ -0,0 +1,192 @@
+# Automake file
+
+# Nonstandard package files for distribution.
+EXTRA_DIST =
+
+# We may need to build our internally packaged gtest. If so, it will be
+# included in the 'subdirs' variable.
+SUBDIRS = $(subdirs)
+
+# Scripts and utilities to be installed by 'make install'.
+dist_bin_SCRIPTS = scripts/gmock_doctor.py
+bin_SCRIPTS = scripts/gmock-config
+
+# This is generated by the configure script, so clean it for distribution.
+DISTCLEANFILES = scripts/gmock-config
+
+# We define the global AM_CPPFLAGS as everything we compile includes from these
+# directories.
+AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include
+
+# Modifies compiler and linker flags for pthreads compatibility.
+if HAVE_PTHREADS
+ AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
+ AM_LIBS = @PTHREAD_LIBS@
+endif
+
+# Build rules for libraries.
+lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la
+
+lib_libgmock_la_SOURCES = src/gmock-all.cc
+
+pkginclude_HEADERS = include/gmock/gmock.h \
+ include/gmock/gmock-actions.h \
+ include/gmock/gmock-cardinalities.h \
+ include/gmock/gmock-generated-actions.h \
+ include/gmock/gmock-generated-function-mockers.h \
+ include/gmock/gmock-generated-matchers.h \
+ include/gmock/gmock-generated-nice-strict.h \
+ include/gmock/gmock-matchers.h \
+ include/gmock/gmock-more-actions.h \
+ include/gmock/gmock-printers.h \
+ include/gmock/gmock-spec-builders.h
+
+pkginclude_internaldir = $(pkgincludedir)/internal
+pkginclude_internal_HEADERS = \
+ include/gmock/internal/gmock-generated-internal-utils.h \
+ include/gmock/internal/gmock-internal-utils.h \
+ include/gmock/internal/gmock-port.h
+
+lib_libgmock_main_la_SOURCES = src/gmock_main.cc
+lib_libgmock_main_la_LIBADD = lib/libgmock.la
+
+# Build rules for tests. Automake's naming for some of these variables isn't
+# terribly obvious, so this is a brief reference:
+#
+# TESTS -- Programs run automatically by "make check"
+# check_PROGRAMS -- Programs built by "make check" but not necessarily run
+
+TESTS=
+check_PROGRAMS=
+AM_LDFLAGS = $(GTEST_LDFLAGS)
+
+# This exercises all major components of Google Mock. It also
+# verifies that libgmock works.
+TESTS += test/gmock-spec-builders_test
+check_PROGRAMS += test/gmock-spec-builders_test
+test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc
+test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la
+
+# This tests using Google Mock in multiple translation units. It also
+# verifies that libgmock_main works.
+TESTS += test/gmock_link_test
+check_PROGRAMS += test/gmock_link_test
+test_gmock_link_test_SOURCES = test/gmock_link_test.cc \
+ test/gmock_link2_test.cc \
+ test/gmock_link_test.h
+test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la
+
+# Tests that fused gmock files compile and work.
+TESTS += test/gmock_fused_test
+check_PROGRAMS += test/gmock_fused_test
+test_gmock_fused_test_SOURCES = fused-src/gmock-gtest-all.cc \
+ fused-src/gmock_main.cc \
+ fused-src/gmock/gmock.h \
+ fused-src/gtest/gtest.h \
+ test/gmock_test.cc
+test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src"
+
+# Google Mock source files that we don't compile directly.
+GMOCK_SOURCE_INGLUDES = \
+ src/gmock.cc \
+ src/gmock-cardinalities.cc \
+ src/gmock-internal-utils.cc \
+ src/gmock-matchers.cc \
+ src/gmock-printers.cc \
+ src/gmock-spec-builders.cc
+
+EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES)
+
+# C++ tests that we don't compile using autotools.
+EXTRA_DIST += \
+ test/gmock_all_test.cc \
+ test/gmock-actions_test.cc \
+ test/gmock-cardinalities_test.cc \
+ test/gmock-generated-actions_test.cc \
+ test/gmock-generated-function-mockers_test.cc \
+ test/gmock-generated-internal-utils_test.cc \
+ test/gmock-generated-matchers_test.cc \
+ test/gmock-internal-utils_test.cc \
+ test/gmock-matchers_test.cc \
+ test/gmock-more-actions_test.cc \
+ test/gmock-nice-strict_test.cc \
+ test/gmock-port_test.cc \
+ test/gmock-printers_test.cc
+
+# Python tests, which we don't run using autotools.
+EXTRA_DIST += \
+ test/gmock_test_utils.py \
+ test/gmock_leak_test_.cc \
+ test/gmock_leak_test.py \
+ test/gmock_output_test_.cc \
+ test/gmock_output_test.py \
+ test/gmock_output_test_golden.txt
+
+# Nonstandard package files for distribution.
+EXTRA_DIST += \
+ CHANGES \
+ CONTRIBUTORS \
+ make/Makefile
+
+# Pump scripts for generating Google Mock headers.
+# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
+EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \
+ include/gmock/gmock-generated-function-mockers.h.pump \
+ include/gmock/gmock-generated-matchers.h.pump \
+ include/gmock/gmock-generated-nice-strict.h.pump \
+ include/gmock/internal/gmock-generated-internal-utils.h.pump
+
+# Script for fusing Google Mock and Google Test source files.
+EXTRA_DIST += \
+ scripts/fuse_gmock_files.py \
+ scripts/test/Makefile
+
+# The Google Mock Generator tool from the cppclean project.
+EXTRA_DIST += \
+ scripts/generator/COPYING \
+ scripts/generator/README \
+ scripts/generator/README.cppclean \
+ scripts/generator/cpp/__init__.py \
+ scripts/generator/cpp/ast.py \
+ scripts/generator/cpp/gmock_class.py \
+ scripts/generator/cpp/keywords.py \
+ scripts/generator/cpp/tokenize.py \
+ scripts/generator/cpp/utils.py \
+ scripts/generator/gmock_gen.py
+
+# Microsoft Visual Studio 2005 projects.
+EXTRA_DIST += \
+ msvc/gmock.sln \
+ msvc/gmock.vcproj \
+ msvc/gmock_config.vsprops \
+ msvc/gmock_link_test.vcproj \
+ msvc/gmock_main.vcproj \
+ msvc/gmock-spec-builders_test.vcproj \
+ msvc/gmock_test.vcproj
+
+# gmock_test.cc does not really depend on files generated by the
+# fused-gmock-internal rule. However, gmock_test.o does, and it is
+# important to include test/gmock_test.cc as part of this rule in order to
+# prevent compiling gmock_test.o until all dependent files have been
+# generated.
+$(test_gmock_fused_test_SOURCES): fused-gmock-internal
+
+# TODO(vladl@google.com): Find a way to add Google Tests's sources here.
+fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
+ $(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \
+ $(lib_libgmock_main_la_SOURCES) \
+ scripts/fuse_gmock_files.py
+ mkdir -p "$(srcdir)/fused-src"
+ chmod -R u+w "$(srcdir)/fused-src"
+ rm -f "$(srcdir)/fused-src/gtest/gtest.h"
+ rm -f "$(srcdir)/fused-src/gmock/gmock.h"
+ rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc"
+ "$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src"
+ cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src"
+
+maintainer-clean-local:
+ rm -rf "$(srcdir)/fused-src"
+
+# Death tests may produce core dumps in the build directory. In case
+# this happens, clean them to keep distcleancheck happy.
+CLEANFILES = core