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 2014/04/30 05:50:39 UTC

[2/5] git commit: Added test for slave stopping before containerizer launches.

Added test for slave stopping before containerizer launches.

Review: https://reviews.apache.org/r/20179


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/46afda85
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/46afda85
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/46afda85

Branch: refs/heads/master
Commit: 46afda855b9a1f516c0353c637d495fb3b0fcb65
Parents: 1c0f56f
Author: Benjamin Hindman <be...@gmail.com>
Authored: Wed Apr 9 14:52:45 2014 -0600
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 src/tests/containerizer.cpp        | 40 ++++++++++++-----
 src/tests/containerizer.hpp        | 28 ++++++++----
 src/tests/slave_recovery_tests.cpp | 79 +++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.cpp b/src/tests/containerizer.cpp
index 50803a0..7dacab5 100644
--- a/src/tests/containerizer.cpp
+++ b/src/tests/containerizer.cpp
@@ -22,6 +22,10 @@
 using std::map;
 using std::string;
 
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
 using namespace process;
 
 namespace mesos {
@@ -69,7 +73,7 @@ TestContainerizer::~TestContainerizer()
 }
 
 
-Future<Nothing> TestContainerizer::launch(
+Future<Nothing> TestContainerizer::_launch(
     const ContainerID& containerId,
     const ExecutorInfo& executorInfo,
     const string& directory,
@@ -161,8 +165,11 @@ Future<Nothing> TestContainerizer::launch(
 Future<containerizer::Termination> TestContainerizer::wait(
     const ContainerID& containerId)
 {
-  CHECK(promises.contains(containerId))
-    << "Container " << containerId << " not started";
+  // An unknown container is possible for tests where we "drop" the
+  // 'launch' in order to verify recovery still works correctly.
+  if (!promises.contains(containerId)) {
+    return Failure("Unknown container: " + stringify(containerId));
+  }
 
   return promises[containerId]->future();
 }
@@ -210,14 +217,25 @@ Future<hashset<ContainerID> > TestContainerizer::containers()
 
 void TestContainerizer::setup()
 {
-  EXPECT_CALL(*this, recover(testing::_))
-    .WillRepeatedly(testing::Return(Nothing()));
-
-  EXPECT_CALL(*this, usage(testing::_))
-    .WillRepeatedly(testing::Return(ResourceStatistics()));
-
-  EXPECT_CALL(*this, update(testing::_, testing::_))
-    .WillRepeatedly(testing::Return(Nothing()));
+  // NOTE: We use 'EXPECT_CALL' and 'WillRepeatedly' here instead of
+  // 'ON_CALL' and 'WillByDefault' because the latter gives the gmock
+  // warning "Uninteresting mock function call" unless each tests puts
+  // the expectations in place which would make the tests much more
+  // verbose.
+  // See groups.google.com/forum/#!topic/googlemock/EX4kLxddlko for a
+  // suggestion for how we might be able to use 'NiceMock' here
+  // instead.
+  EXPECT_CALL(*this, recover(_))
+    .WillRepeatedly(Return(Nothing()));
+
+  EXPECT_CALL(*this, usage(_))
+    .WillRepeatedly(Return(ResourceStatistics()));
+
+  EXPECT_CALL(*this, update(_, _))
+    .WillRepeatedly(Return(Nothing()));
+
+  EXPECT_CALL(*this, launch(_, _, _, _, _, _, _))
+    .WillRepeatedly(Invoke(this, &TestContainerizer::_launch));
 }
 
 } // namespace tests {

http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.hpp b/src/tests/containerizer.hpp
index 2b7ee0d..8e21bd1 100644
--- a/src/tests/containerizer.hpp
+++ b/src/tests/containerizer.hpp
@@ -64,14 +64,16 @@ public:
 
   virtual ~TestContainerizer();
 
-  virtual process::Future<Nothing> launch(
-      const ContainerID& containerId,
-      const ExecutorInfo& executorInfo,
-      const std::string& directory,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
-      const process::PID<slave::Slave>& slavePid,
-      bool checkpoint);
+  MOCK_METHOD7(
+      launch,
+      process::Future<Nothing>(
+          const ContainerID&,
+          const ExecutorInfo&,
+          const std::string&,
+          const Option<std::string>&,
+          const SlaveID&,
+          const process::PID<slave::Slave>&,
+          bool checkpoint));
 
   virtual process::Future<Nothing> launch(
       const ContainerID& containerId,
@@ -109,6 +111,16 @@ public:
 private:
   void setup();
 
+  // Default 'launch' implementation.
+  process::Future<Nothing> _launch(
+      const ContainerID& containerId,
+      const ExecutorInfo& executorInfo,
+      const std::string& directory,
+      const Option<std::string>& user,
+      const SlaveID& slaveId,
+      const process::PID<slave::Slave>& slavePid,
+      bool checkpoint);
+
   hashmap<ExecutorID, Executor*> executors;
 
   hashmap<std::pair<FrameworkID, ExecutorID>, ContainerID> containers_;

http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index cd28c8b..21b1345 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -52,6 +52,7 @@
 
 #include "messages/messages.hpp"
 
+#include "tests/containerizer.hpp"
 #include "tests/mesos.hpp"
 #include "tests/utils.hpp"
 
@@ -73,6 +74,7 @@ using std::vector;
 
 using testing::_;
 using testing::AtMost;
+using testing::DoAll;
 using testing::Eq;
 using testing::Return;
 using testing::SaveArg;
@@ -3087,3 +3089,80 @@ TYPED_TEST(SlaveRecoveryTest, ResourceStatistics)
 
   delete containerizer2.get();
 }
+
+
+// The slave is stopped after it dispatched Containerizer::launch but
+// before the containerizer has processed the launch. When the slave
+// comes back up it should send a TASK_LOST for the task.
+// NOTE: This is a 'TYPED_TEST' but we don't use 'TypeParam'.
+TYPED_TEST(SlaveRecoveryTest, RestartBeforeContainerizerLaunch)
+{
+  Try<PID<Master> > master = this->StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = this->CreateSlaveFlags();
+
+  TestContainerizer* containerizer1 = new TestContainerizer();
+
+  Try<PID<Slave> > slave = this->StartSlave(containerizer1, flags);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  // Enable checkpointing for the framework.
+  FrameworkInfo frameworkInfo;
+  frameworkInfo.CopyFrom(DEFAULT_FRAMEWORK_INFO);
+  frameworkInfo.set_checkpoint(true);
+
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(_, _, _));
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());      // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
+  vector<TaskInfo> tasks;
+  tasks.push_back(task); // Long-running task.
+
+  // Expect the launch but don't do anything.
+  Future<Nothing> launch;
+  EXPECT_CALL(*containerizer1, launch(_, _, _, _, _, _, _))
+    .WillOnce(DoAll(FutureSatisfy(&launch),
+                    Return(Future<Nothing>())));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  // Once we get the launch restart the slave.
+  AWAIT_READY(launch);
+
+  this->Stop(slave.get());
+  delete containerizer1;
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  TestContainerizer* containerizer2 = new TestContainerizer();
+
+  slave = this->StartSlave(containerizer2, flags);
+  ASSERT_SOME(slave);
+
+  // Scheduler should receive an update for the lost task.
+  AWAIT_READY(status);
+  ASSERT_EQ(TASK_LOST, status.get().state());
+
+  driver.stop();
+  driver.join();
+
+  this->Shutdown();
+  delete containerizer2;
+}