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 2012/07/11 00:03:44 UTC
svn commit: r1359927 - in /incubator/mesos/trunk/src: Makefile.am
common/type_utils.hpp tests/allocator_tests.cpp
tests/resource_offers_tests.cpp tests/utils.hpp
Author: benh
Date: Tue Jul 10 22:03:44 2012
New Revision: 1359927
URL: http://svn.apache.org/viewvc?rev=1359927&view=rev
Log:
Added allocator tests (contributed by Thomas Marshall,
https://reviews.apache.org/r/5532).
Added:
incubator/mesos/trunk/src/tests/allocator_tests.cpp
Modified:
incubator/mesos/trunk/src/Makefile.am
incubator/mesos/trunk/src/common/type_utils.hpp
incubator/mesos/trunk/src/tests/resource_offers_tests.cpp
incubator/mesos/trunk/src/tests/utils.hpp
Modified: incubator/mesos/trunk/src/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.am?rev=1359927&r1=1359926&r2=1359927&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.am (original)
+++ incubator/mesos/trunk/src/Makefile.am Tue Jul 10 22:03:44 2012
@@ -751,7 +751,8 @@ mesos_tests_SOURCES = tests/main.cpp tes
tests/killtree_tests.cpp \
tests/exception_tests.cpp \
tests/attributes_tests.cpp \
- tests/master_detector_tests.cpp
+ tests/master_detector_tests.cpp \
+ tests/allocator_tests.cpp
mesos_tests_CPPFLAGS = $(MESOS_CPPFLAGS)
mesos_tests_CPPFLAGS += -DSOURCE_DIR=\"$(abs_top_srcdir)\"
Modified: incubator/mesos/trunk/src/common/type_utils.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/common/type_utils.hpp?rev=1359927&r1=1359926&r2=1359927&view=diff
==============================================================================
--- incubator/mesos/trunk/src/common/type_utils.hpp (original)
+++ incubator/mesos/trunk/src/common/type_utils.hpp Tue Jul 10 22:03:44 2012
@@ -96,6 +96,12 @@ inline bool operator == (const Framework
}
+inline bool operator == (const FrameworkInfo& left, const FrameworkInfo& right)
+{
+ return (left.name() == right.name()) && (left.user() == right.user());
+}
+
+
inline bool operator == (const OfferID& left, const OfferID& right)
{
return left.value() == right.value();
Added: incubator/mesos/trunk/src/tests/allocator_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/allocator_tests.cpp?rev=1359927&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/allocator_tests.cpp (added)
+++ incubator/mesos/trunk/src/tests/allocator_tests.cpp Tue Jul 10 22:03:44 2012
@@ -0,0 +1,676 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include <mesos/scheduler.hpp>
+
+#include "configurator/configuration.hpp"
+
+#include "detector/detector.hpp"
+
+#include "master/allocator.hpp"
+#include "master/dominant_share_allocator.hpp"
+#include "master/master.hpp"
+
+#include "slave/process_based_isolation_module.hpp"
+
+#include "tests/base_zookeeper_test.hpp"
+#include "tests/utils.hpp"
+
+using namespace mesos;
+using namespace mesos::internal;
+using namespace mesos::internal::test;
+
+using mesos::internal::master::Allocator;
+using mesos::internal::master::DominantShareAllocator;
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::ProcessBasedIsolationModule;
+using mesos::internal::slave::Slave;
+
+using process::PID;
+
+using std::string;
+using std::vector;
+
+using testing::AnyNumber;
+using testing::ByRef;
+using testing::DoDefault;
+using testing::Eq;
+using testing::_;
+using testing::Return;
+using testing::SaveArg;
+
+void checkResources(vector<Offer> offers, int cpus, int mem)
+{
+ EXPECT_EQ(offers.size(), 1);
+
+ EXPECT_EQ(offers[0].resources().size(), 2);
+
+ foreach (const Resource& resource, offers[0].resources()) {
+ if (resource.name() == "cpus") {
+ EXPECT_EQ(resource.scalar().value(), cpus);
+ } else if (resource.name() == "mem") {
+ EXPECT_EQ(resource.scalar().value(), mem);
+ }
+ }
+}
+
+
+TEST(AllocatorTest, DominantShareAllocator)
+{
+ FrameworkInfo frameworkInfo1;
+ frameworkInfo1.set_name("framework1");
+ frameworkInfo1.set_user("user1");
+ FrameworkID frameworkId1;
+
+ FrameworkInfo frameworkInfo2;
+ frameworkInfo2.set_name("framework2");
+ frameworkInfo2.set_user("user2");
+ FrameworkID frameworkId2;
+
+ FrameworkInfo frameworkInfo3;
+ frameworkInfo3.set_name("framework3");
+ frameworkInfo3.set_user("user1");
+ FrameworkID frameworkId3;
+
+ MockAllocator<DominantShareAllocator> a;
+
+ EXPECT_CALL(a, initialize(_));
+
+ EXPECT_CALL(a, frameworkAdded(_, Eq(frameworkInfo1)))
+ .WillOnce(DoAll(InvokeFrameworkAdded(&a),
+ SaveArg<0>(&frameworkId1)));
+
+ trigger framework2Added;
+ EXPECT_CALL(a, frameworkAdded(_, Eq(frameworkInfo2)))
+ .WillOnce(DoAll(InvokeFrameworkAdded(&a),
+ SaveArg<0>(&frameworkId2),
+ Trigger(&framework2Added)));
+
+ trigger framework3Added;
+ EXPECT_CALL(a, frameworkAdded(_, Eq(frameworkInfo3)))
+ .WillOnce(DoAll(InvokeFrameworkAdded(&a),
+ SaveArg<0>(&frameworkId3),
+ Trigger(&framework3Added)));
+
+ EXPECT_CALL(a, frameworkDeactivated(_))
+ .Times(3);
+
+ EXPECT_CALL(a, frameworkRemoved(Eq(ByRef(frameworkId1))));
+
+ EXPECT_CALL(a, frameworkRemoved(Eq(ByRef(frameworkId2))));
+
+ trigger lastFrameworkRemoved;
+ EXPECT_CALL(a, frameworkRemoved(Eq(ByRef(frameworkId3))))
+ .WillOnce(Trigger(&lastFrameworkRemoved));
+
+ SlaveID slaveId4;
+ EXPECT_CALL(a, slaveAdded(_, _, _))
+ .WillOnce(DoDefault())
+ .WillOnce(DoDefault())
+ .WillOnce(DoDefault())
+ .WillOnce(DoAll(InvokeSlaveAdded(&a),
+ SaveArg<0>(&slaveId4)));
+
+ EXPECT_CALL(a, slaveRemoved(_))
+ .Times(3);
+
+ trigger lastSlaveRemoved;
+ EXPECT_CALL(a, slaveRemoved(Eq(ByRef(slaveId4))))
+ .WillOnce(Trigger(&lastSlaveRemoved));
+
+ EXPECT_CALL(a, resourcesRecovered(_, _, _))
+ .WillRepeatedly(DoDefault());
+
+ Master m(&a);
+ PID<Master> master = process::spawn(m);
+
+ ProcessBasedIsolationModule isolationModule;
+ Resources resources = Resources::parse("cpus:2;mem:1024");
+ Slave s(resources, true, &isolationModule);
+ PID<Slave> slave1 = process::spawn(s);
+
+ BasicMasterDetector detector(master, slave1, true);
+
+ MockScheduler sched1;
+ MesosSchedulerDriver driver1(&sched1, frameworkInfo1, master);
+
+ EXPECT_CALL(sched1, registered(_, _, _));
+
+ vector<Offer> offers1;
+ trigger resourceOfferTrigger;
+ EXPECT_CALL(sched1, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers1),
+ Trigger(&resourceOfferTrigger)))
+ .WillRepeatedly(Return());
+
+ driver1.start();
+
+ WAIT_UNTIL(resourceOfferTrigger);
+
+ checkResources(offers1, 2, 1024);
+
+ MockScheduler sched2;
+ MesosSchedulerDriver driver2(&sched2, frameworkInfo2, master);
+
+ EXPECT_CALL(sched2, registered(_, _, _));
+
+ vector<Offer> offers2, offers3;
+ trigger resourceOfferTrigger2, resourceOfferTrigger3;
+ EXPECT_CALL(sched2, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers2),
+ Trigger(&resourceOfferTrigger2)))
+ .WillOnce(DoAll(SaveArg<1>(&offers3),
+ Trigger(&resourceOfferTrigger3)))
+ .WillRepeatedly(Return());
+
+ driver2.start();
+
+ WAIT_UNTIL(framework2Added);
+
+ Resources resources2 = Resources::parse("cpus:1;mem:512");
+ Slave s2(resources2, true, &isolationModule);
+ PID<Slave> slave2 = process::spawn(s2);
+
+ BasicMasterDetector detector2(master, slave2, true);
+
+ WAIT_UNTIL(resourceOfferTrigger2);
+
+ checkResources(offers2, 1, 512);
+
+ Resources resources3 = Resources::parse("cpus:3;mem:2048");
+ Slave s3(resources3, true, &isolationModule);
+ PID<Slave> slave3 = process::spawn(s3);
+ BasicMasterDetector detector3(master, slave3, true);
+
+ WAIT_UNTIL(resourceOfferTrigger3);
+
+ checkResources(offers3, 3, 2048);
+
+ MockScheduler sched3;
+ MesosSchedulerDriver driver3(&sched3, frameworkInfo3, master);
+
+ EXPECT_CALL(sched3, registered(_, _, _));
+
+ vector<Offer> offers4;
+ trigger resourceOfferTrigger4;
+ EXPECT_CALL(sched3, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers4),
+ Trigger(&resourceOfferTrigger4)));
+
+ driver3.start();
+
+ WAIT_UNTIL(framework3Added);
+
+ Resources resources4 = Resources::parse("cpus:4;mem:4096");
+ Slave s4(resources4, true, &isolationModule);
+ PID<Slave> slave4 = process::spawn(s4);
+ BasicMasterDetector detector4(master, slave4, true);
+
+ WAIT_UNTIL(resourceOfferTrigger4);
+
+ checkResources(offers4, 4, 4096);
+
+ driver3.stop();
+ driver2.stop();
+ driver1.stop();
+
+ WAIT_UNTIL(lastFrameworkRemoved);
+
+ process::terminate(slave1);
+ process::wait(slave1);
+
+ process::terminate(slave2);
+ process::wait(slave2);
+
+ process::terminate(slave3);
+ process::wait(slave3);
+
+ process::terminate(slave4);
+ process::wait(slave4);
+
+ WAIT_UNTIL(lastSlaveRemoved);
+
+ process::terminate(master);
+ process::wait(master);
+}
+
+
+template <typename T = Allocator>
+class AllocatorTest : public ::testing::Test
+{
+protected:
+ MockAllocator<T> allocator;
+};
+
+
+// Causes all TYPED_TEST(AllocatorTest, ...) to be run for
+// each of the specified Allocator classes.
+typedef ::testing::Types<DominantShareAllocator> AllocatorTypes;
+TYPED_TEST_CASE(AllocatorTest, AllocatorTypes);
+
+
+TYPED_TEST(AllocatorTest, MockAllocator)
+{
+ EXPECT_CALL(this->allocator, initialize(_));
+
+ EXPECT_CALL(this->allocator, frameworkAdded(_, _));
+
+ EXPECT_CALL(this->allocator, frameworkDeactivated(_));
+
+ trigger frameworkRemovedTrigger;
+ EXPECT_CALL(this->allocator, frameworkRemoved(_))
+ .WillOnce(Trigger(&frameworkRemovedTrigger));
+
+ EXPECT_CALL(this->allocator, slaveAdded(_, _, _));
+
+ trigger slaveRemovedTrigger;
+ EXPECT_CALL(this->allocator, slaveRemoved(_))
+ .WillOnce(Trigger(&slaveRemovedTrigger));
+
+ EXPECT_CALL(this->allocator, resourcesRecovered(_, _, _));
+
+ Master m(&this->allocator);
+ PID<Master> master = process::spawn(&m);
+
+ ProcessBasedIsolationModule isolationModule;
+ Resources resources = Resources::parse("cpus:2;mem:1024");
+
+ Slave s(resources, true, &isolationModule);
+ PID<Slave> slave = process::spawn(&s);
+
+ BasicMasterDetector detector(master, slave, true);
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+
+ trigger resourceOffers;
+
+ vector<Offer> offers;
+
+ EXPECT_CALL(sched, registered(_, _, _));
+
+ EXPECT_CALL(sched, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers),
+ Trigger(&resourceOffers)));
+
+ driver.start();
+
+ WAIT_UNTIL(resourceOffers);
+
+ checkResources(offers, 2, 1024);
+
+ driver.stop();
+
+ WAIT_UNTIL(frameworkRemovedTrigger);
+
+ process::terminate(slave);
+ process::wait(slave);
+
+ WAIT_UNTIL(slaveRemovedTrigger);
+
+ process::terminate(master);
+ process::wait(master);
+}
+
+
+TYPED_TEST(AllocatorTest, ResourcesUnused)
+{
+ EXPECT_CALL(this->allocator, initialize(_));
+
+ EXPECT_CALL(this->allocator, frameworkAdded(_, _))
+ .Times(2);
+
+ EXPECT_CALL(this->allocator, frameworkDeactivated(_))
+ .Times(2);
+
+ trigger frameworkRemovedTrigger;
+ EXPECT_CALL(this->allocator, frameworkRemoved(_))
+ .WillOnce(DoDefault())
+ .WillOnce(Trigger(&frameworkRemovedTrigger));
+
+ EXPECT_CALL(this->allocator, slaveAdded(_, _, _));
+
+ trigger slaveRemovedTrigger;
+ EXPECT_CALL(this->allocator, slaveRemoved(_))
+ .WillOnce(Trigger(&slaveRemovedTrigger));
+
+ trigger resourcesUnusedTrigger;
+ EXPECT_CALL(this->allocator, resourcesUnused(_, _, _, _))
+ .WillOnce(DoAll(InvokeResourcesUnused(&this->allocator),
+ Trigger(&resourcesUnusedTrigger),
+ Return()))
+ .WillRepeatedly(DoDefault());
+
+ // Prevent any resources from being recovered by returning instead
+ // of allowing resourcesRecovered to be invoked, so the only ones
+ // that are reallocated are those returned by resourcesUnused.
+ EXPECT_CALL(this->allocator, resourcesRecovered(_, _, _))
+ .WillRepeatedly(Return());
+
+ Master m(&(this->allocator));
+ PID<Master> master = process::spawn(m);
+
+ ProcessBasedIsolationModule isolationModule;
+ Resources resources1 = Resources::parse("cpus:2;mem:1024");
+ Slave s(resources1, true, &isolationModule);
+ PID<Slave> slave1 = process::spawn(s);
+ BasicMasterDetector(master, slave1, true);
+
+ MockScheduler sched1;
+ MesosSchedulerDriver driver1(&sched1, DEFAULT_FRAMEWORK_INFO, master);
+
+ EXPECT_CALL(sched1, registered(_, _, _));
+
+ EXPECT_CALL(sched1, resourceOffers(_, _))
+ .WillOnce(LaunchTasks(1, 1, 512))
+ .WillRepeatedly(DeclineOffers());
+
+ driver1.start();
+
+ WAIT_UNTIL(resourcesUnusedTrigger);
+
+ FrameworkInfo info2;
+ info2.set_user("user2");
+ info2.set_name("framework2");
+ MockScheduler sched2;
+ MesosSchedulerDriver driver2(&sched2, info2, master);
+
+ EXPECT_CALL(sched2, registered(_, _, _));
+
+ vector<Offer> offers;
+ trigger offered;
+ EXPECT_CALL(sched2, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers),
+ Trigger(&offered)))
+ .WillRepeatedly(Return());
+
+ driver2.start();
+
+ WAIT_UNTIL(offered);
+
+ checkResources(offers, 1, 512);
+
+ driver1.stop();
+ driver2.stop();
+
+ WAIT_UNTIL(frameworkRemovedTrigger);
+
+ process::terminate(slave1);
+ process::wait(slave1);
+
+ WAIT_UNTIL(slaveRemovedTrigger);
+
+ process::terminate(master);
+ process::wait(master);
+}
+
+
+// Tests the situation where a frameworkRemoved call is dispatched
+// while we're doing an allocation to that framework, so that
+// resourcesRecovered is called for an already removed framework.
+TYPED_TEST(AllocatorTest, OutOfOrderDispatch)
+{
+ FrameworkInfo frameworkInfo1;
+ frameworkInfo1.set_user("user1");
+ frameworkInfo1.set_name("framework1");
+ FrameworkID frameworkId1;
+
+ FrameworkInfo frameworkInfo2;
+ frameworkInfo2.set_user("user2");
+ frameworkInfo2.set_name("framework2");
+ FrameworkID frameworkId2;
+
+ EXPECT_CALL(this->allocator, initialize(_));
+
+ EXPECT_CALL(this->allocator, frameworkAdded(_, Eq(frameworkInfo1)))
+ .WillOnce(DoAll(InvokeFrameworkAdded(&this->allocator),
+ SaveArg<0>(&frameworkId1)));
+
+ EXPECT_CALL(this->allocator, frameworkAdded(_, Eq(frameworkInfo2)))
+ .WillOnce(DoAll(InvokeFrameworkAdded(&this->allocator),
+ SaveArg<0>(&frameworkId2)));
+
+ EXPECT_CALL(this->allocator, frameworkDeactivated(_))
+ .Times(2);
+
+ trigger frameworkRemoved, frameworkRemoved2;
+ EXPECT_CALL(this->allocator, frameworkRemoved(Eq(ByRef(frameworkId1))))
+ .WillOnce(DoAll(InvokeFrameworkRemoved(&this->allocator),
+ Trigger(&frameworkRemoved),
+ Return()));
+
+ EXPECT_CALL(this->allocator, frameworkRemoved(Eq(ByRef(frameworkId2))))
+ .WillOnce(Trigger(&frameworkRemoved2));
+
+ EXPECT_CALL(this->allocator, slaveAdded(_, _, _));
+
+ trigger slaveRemovedTrigger;
+ EXPECT_CALL(this->allocator, slaveRemoved(_))
+ .WillOnce(Trigger(&slaveRemovedTrigger));
+
+ FrameworkID frameworkId;
+ SlaveID slaveId;
+ Resources savedResources;
+ EXPECT_CALL(this->allocator, resourcesRecovered(_, _, _))
+ // "Catches" the resourcesRecovered call from the master, so
+ // that it doesn't get processed until we redispatch it after
+ // the frameworkRemoved trigger.
+ .WillOnce(DoAll(SaveArg<0>(&frameworkId),
+ SaveArg<1>(&slaveId),
+ SaveArg<2>(&savedResources)))
+ .WillRepeatedly(DoDefault());
+
+ Master m(&(this->allocator));
+ PID<Master> master = process::spawn(&m);
+
+ ProcessBasedIsolationModule isolationModule;
+
+ Resources resources = Resources::parse("cpus:2;mem:1024");
+
+ Slave s(resources, true, &isolationModule);
+ PID<Slave> slave = process::spawn(&s);
+
+ BasicMasterDetector detector(master, slave, true);
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(&sched, frameworkInfo1, master);
+
+ trigger offered;
+ vector<Offer> offers;
+
+ EXPECT_CALL(sched, registered(_, _, _));
+
+ EXPECT_CALL(sched, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers),
+ Trigger(&offered)));
+
+ driver.start();
+
+ WAIT_UNTIL(offered);
+
+ checkResources(offers, 2, 1024);
+
+ driver.stop();
+ driver.join();
+
+ WAIT_UNTIL(frameworkRemoved);
+
+ // Re-dispatch the resourcesRecovered call which we "caught"
+ // earlier now that the framework has been removed, to test
+ // that recovering resources from a removed framework works.
+ dispatch(this->allocator, &Allocator::resourcesRecovered,
+ frameworkId, slaveId, savedResources);
+
+ MockScheduler sched2;
+ MesosSchedulerDriver driver2(&sched2, frameworkInfo2, master);
+
+ EXPECT_CALL(sched2, registered(_, _, _));
+
+ trigger offered2;
+ vector<Offer> offers2;
+ EXPECT_CALL(sched2, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers2),
+ Trigger(&offered2)));
+
+ driver2.start();
+
+ WAIT_UNTIL(offered2);
+
+ checkResources(offers2, 2, 1024);
+
+ driver2.stop();
+ driver2.join();
+
+ WAIT_UNTIL(frameworkRemoved2);
+
+ process::terminate(slave);
+ process::wait(slave);
+
+ WAIT_UNTIL(slaveRemovedTrigger);
+
+ process::terminate(master);
+ process::wait(master);
+}
+
+
+template <typename T = Allocator>
+class MasterFailoverAllocatorTest : public BaseZooKeeperTest
+{
+public:
+ static void SetUpTestCase() {
+ BaseZooKeeperTest::SetUpTestCase();
+ }
+
+protected:
+ T allocator1;
+ MockAllocator<T> allocator2;
+};
+
+
+// Runs TYPED_TEST(MasterFailoverAllocatorTest, ...) on all AllocatorTypes.
+TYPED_TEST_CASE(MasterFailoverAllocatorTest, AllocatorTypes);
+
+
+TYPED_TEST(MasterFailoverAllocatorTest, MasterFailover)
+{
+ trigger slaveAdded;
+ EXPECT_CALL(this->allocator2, initialize(_));
+
+ trigger frameworkAdded;
+ EXPECT_CALL(this->allocator2, frameworkAdded(_, _));
+
+ EXPECT_CALL(this->allocator2, frameworkDeactivated(_));
+
+ trigger frameworkRemovedTrigger;
+ EXPECT_CALL(this->allocator2, frameworkRemoved(_))
+ .WillOnce(Trigger(&frameworkRemovedTrigger));
+
+ EXPECT_CALL(this->allocator2, slaveAdded(_, _, _));
+
+ trigger slaveRemovedTrigger;
+ EXPECT_CALL(this->allocator2, slaveRemoved(_))
+ .WillOnce(Trigger(&slaveRemovedTrigger));
+
+ EXPECT_CALL(this->allocator2, resourcesRecovered(_, _, _))
+ .WillRepeatedly(DoDefault());
+
+ MockFilter filter;
+ process::filter(&filter);
+
+ EXPECT_MESSAGE(filter, Eq(ShutdownMessage().GetTypeName()), _, _)
+ .WillRepeatedly(Return(true));
+
+ Master m1(&(this->allocator1));
+ PID<Master> master1 = process::spawn(m1);
+
+ string zk = "zk://" + this->zks->connectString() + "/znode";
+ Try<MasterDetector*> detector =
+ MasterDetector::create(zk, master1, true, true);
+ CHECK(!detector.isError())
+ << "Failed to create a master detector: " << detector.error();
+
+ ProcessBasedIsolationModule isolationModule;
+
+ Resources resources = Resources::parse("cpus:2;mem:1024");
+
+ Slave s(resources, true, &isolationModule);
+ PID<Slave> slave = process::spawn(s);
+
+ Try<MasterDetector*> slave_detector =
+ MasterDetector::create(zk, slave, false, true);
+ CHECK(!slave_detector.isError())
+ << "Failed to create a master detector: " << slave_detector.error();
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, zk);
+
+ trigger resourceOffers, resourceOffers2;
+
+ vector<Offer> offers, offers2;
+
+ EXPECT_CALL(sched, registered(_, _, _))
+ .Times(2);
+
+ EXPECT_CALL(sched, resourceOffers(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&offers),
+ Trigger(&resourceOffers)))
+ .WillOnce(DoAll(SaveArg<1>(&offers2),
+ Trigger(&resourceOffers2)));
+
+ EXPECT_CALL(sched, disconnected(_))
+ .WillRepeatedly(DoDefault());
+
+ driver.start();
+
+ WAIT_UNTIL(resourceOffers);
+
+ checkResources(offers, 2, 1024);
+
+ process::terminate(master1);
+ process::wait(master1);
+ MasterDetector::destroy(detector.get());
+
+ Master m2(&(this->allocator2));
+ PID<Master> master2 = process::spawn(m2);
+
+ Try<MasterDetector*> detector2 =
+ MasterDetector::create(zk, master2, true, true);
+ CHECK(!detector2.isError())
+ << "Failed to create a master detector: " << detector2.error();
+
+ WAIT_UNTIL(resourceOffers2);
+
+ checkResources(offers2, 2, 1024);
+
+ driver.stop();
+
+ WAIT_UNTIL(frameworkRemovedTrigger);
+
+ process::terminate(slave);
+ process::wait(slave);
+
+ WAIT_UNTIL(slaveRemovedTrigger);
+
+ process::terminate(master2);
+ process::wait(master2);
+
+ process::filter(NULL);
+}
Modified: incubator/mesos/trunk/src/tests/resource_offers_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/resource_offers_tests.cpp?rev=1359927&r1=1359926&r2=1359927&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/resource_offers_tests.cpp (original)
+++ incubator/mesos/trunk/src/tests/resource_offers_tests.cpp Tue Jul 10 22:03:44 2012
@@ -455,7 +455,7 @@ TEST(ResourceOffersTest, Request)
ASSERT_TRUE(GTEST_IS_THREADSAFE);
MockScheduler sched;
- MockAllocator allocator;
+ MockAllocator<DominantShareAllocator> allocator;
EXPECT_CALL(allocator, initialize(_))
.WillOnce(Return());
Modified: incubator/mesos/trunk/src/tests/utils.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/utils.hpp?rev=1359927&r1=1359926&r2=1359927&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/utils.hpp (original)
+++ incubator/mesos/trunk/src/tests/utils.hpp Tue Jul 10 22:03:44 2012
@@ -42,6 +42,8 @@
#include "slave/isolation_module.hpp"
#include "slave/slave.hpp"
+using ::testing::_;
+using ::testing::Invoke;
namespace mesos {
namespace internal {
@@ -136,6 +138,78 @@ public:
MOCK_METHOD2(error, void(SchedulerDriver*, const std::string&));
};
+// For use with a MockScheduler, for example:
+// EXPECT_CALL(sched, resourceOffers(_, _))
+// .WillOnce(LaunchTasks(TASKS, CPUS, MEM));
+// Launches up to TASKS no-op tasks, if possible,
+// each with CPUS cpus and MEM memory.
+ACTION_P3(LaunchTasks, tasks, cpus, mem)
+{
+ SchedulerDriver* driver = arg0;
+ std::vector<Offer> offers = arg1;
+ int numTasks = tasks;
+
+ int launched = 0;
+ for (int i = 0; i < offers.size(); i++) {
+ const Offer& offer = offers[i];
+ double offeredCpus = 0;
+ double offeredMem = 0;
+
+ for (int i = 0; i < offer.resources_size(); i++) {
+ const Resource& resource = offer.resources(i);
+ if (resource.name() == "cpus" &&
+ resource.type() == Value::SCALAR) {
+ offeredCpus = resource.scalar().value();
+ } else if (resource.name() == "mem" &&
+ resource.type() == Value::SCALAR) {
+ offeredMem = resource.scalar().value();
+ }
+ }
+
+ std::vector<TaskInfo> tasks;
+ if (offeredCpus >= cpus &&
+ offeredMem >= mem &&
+ launched < numTasks) {
+ TaskInfo task;
+ task.set_name("TestTask");
+ task.mutable_task_id()->set_value("TestTask1");
+ task.mutable_slave_id()->MergeFrom(offer.slave_id());
+
+ ExecutorInfo executor;
+ executor.mutable_executor_id()->set_value("default");
+ executor.mutable_command()->set_value(":");
+ task.mutable_executor()->MergeFrom(executor);
+
+ Resource* resource;
+ resource = task.add_resources();
+ resource->set_name("cpus");
+ resource->set_type(Value::SCALAR);
+ resource->mutable_scalar()->set_value(cpus);
+
+ resource = task.add_resources();
+ resource->set_name("mem");
+ resource->set_type(Value::SCALAR);
+ resource->mutable_scalar()->set_value(mem);
+
+ tasks.push_back(task);
+ launched++;
+ }
+
+ driver->launchTasks(offer.id(), tasks);
+ }
+}
+
+// Like LaunchTasks, but decline the entire offer and
+// don't launch any tasks.
+ACTION(DeclineOffers)
+{
+ SchedulerDriver* driver = arg0;
+ std::vector<Offer> offers = arg1;
+
+ for (int i = 0; i < offers.size(); i++) {
+ driver->declineOffer(offers[i].id());
+ }
+}
/**
* Definition of a mock Executor to be used in tests with gmock.
@@ -157,9 +231,41 @@ public:
};
+template <typename T = master::Allocator>
class MockAllocator : public master::Allocator
{
public:
+ MockAllocator() {
+ ON_CALL(*this, initialize(_))
+ .WillByDefault(Invoke(&real, &T::initialize));
+
+ ON_CALL(*this, frameworkAdded(_, _))
+ .WillByDefault(Invoke(&real, &T::frameworkAdded));
+
+ ON_CALL(*this, frameworkDeactivated(_))
+ .WillByDefault(Invoke(&real, &T::frameworkDeactivated));
+
+ ON_CALL(*this, frameworkRemoved(_))
+ .WillByDefault(Invoke(&real, &T::frameworkRemoved));
+
+ ON_CALL(*this, slaveAdded(_, _, _))
+ .WillByDefault(Invoke(&real, &T::slaveAdded));
+
+ ON_CALL(*this, slaveRemoved(_))
+ .WillByDefault(Invoke(&real, &T::slaveRemoved));
+
+ ON_CALL(*this, resourcesRequested(_, _))
+ .WillByDefault(Invoke(&real, &T::resourcesRequested));
+
+ ON_CALL(*this, resourcesUnused(_, _, _, _))
+ .WillByDefault(Invoke(&real, &T::resourcesUnused));
+
+ ON_CALL(*this, resourcesRecovered(_, _, _))
+ .WillByDefault(Invoke(&real, &T::resourcesRecovered));
+
+ ON_CALL(*this, offersRevived(_))
+ .WillByDefault(Invoke(&real, &T::offersRevived));
+ }
MOCK_METHOD1(initialize, void(const process::PID<master::Master>&));
MOCK_METHOD2(frameworkAdded, void(const FrameworkID&, const FrameworkInfo&));
MOCK_METHOD1(frameworkDeactivated, void(const FrameworkID&));
@@ -179,9 +285,40 @@ public:
const SlaveID&,
const Resources&));
MOCK_METHOD1(offersRevived, void(const FrameworkID&));
+
+ T real;
};
+// The following actions make up for the fact that DoDefault
+// cannot be used inside a DoAll, for example:
+// EXPECT_CALL(allocator, frameworkAdded(_))
+// .WillOnce(DoAll(InvokeFrameworkAdded(&allocator),
+// Trigger(&frameworkAddedTrigger)));
+ACTION_P(InvokeFrameworkAdded, allocator)
+{
+ allocator->real.frameworkAdded(arg0, arg1);
+}
+
+
+ACTION_P(InvokeFrameworkRemoved, allocator)
+{
+ allocator->real.frameworkRemoved(arg0);
+}
+
+
+ACTION_P(InvokeSlaveAdded, allocator)
+{
+ allocator->real.slaveAdded(arg0, arg1, arg2);
+}
+
+
+ACTION_P(InvokeResourcesUnused, allocator)
+{
+ allocator->real.resourcesUnused(arg0, arg1, arg2, arg3);
+}
+
+
/**
* Definition of a mock Filter so that messages can act as triggers.
*/