You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2013/08/26 21:38:42 UTC

git commit: Added a slave recovery test for the case of multiple slaves.

Updated Branches:
  refs/heads/master 9a866c1a0 -> f00832a1d


Added a slave recovery test for the case of multiple slaves.

From: Jie Yu <yu...@gmail.com>
Review: https://reviews.apache.org/r/13753


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

Branch: refs/heads/master
Commit: f00832a1d8cb164cc1e2a12a89565dc36b10d048
Parents: 9a866c1
Author: Vinod Kone <vi...@twitter.com>
Authored: Mon Aug 26 15:38:19 2013 -0400
Committer: Vinod Kone <vi...@twitter.com>
Committed: Mon Aug 26 15:38:19 2013 -0400

----------------------------------------------------------------------
 src/tests/slave_recovery_tests.cpp | 182 ++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/f00832a1/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index c0f130e..0735dba 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -2260,3 +2260,185 @@ TYPED_TEST(SlaveRecoveryTest, MultipleFrameworks)
 
   this->Shutdown(); // Shutdown before isolator(s) get deallocated.
 }
+
+
+// Create a test fixture for those slave recovery tests that only work
+// when ProcessIsolator is used.
+// TODO(jieyu): We use typed test here because it magically allows us
+// to access protected members in Slave (e.g. Slave::_recover).
+template <typename T>
+class SlaveRecoveryProcessIsolatorTest : public IsolatorTest<T>
+{
+public:
+  virtual slave::Flags CreateSlaveFlags()
+  {
+    slave::Flags flags = IsolatorTest<T>::CreateSlaveFlags();
+
+    // Setup recovery slave flags.
+    flags.checkpoint = true;
+    flags.recover = "reconnect";
+    flags.strict = true;
+
+    return flags;
+  }
+};
+
+
+TYPED_TEST_CASE(SlaveRecoveryProcessIsolatorTest,
+                ::testing::Types<ProcessIsolator>);
+
+
+// This test verifies that slave recovery works properly even if
+// multiple slaves are co-located on the same host.
+TYPED_TEST(SlaveRecoveryProcessIsolatorTest, MultipleSlaves)
+{
+  Try<PID<Master> > master = this->StartMaster();
+  ASSERT_SOME(master);
+
+  // Enable checkpointing for the framework.
+  FrameworkInfo frameworkInfo;
+  frameworkInfo.CopyFrom(DEFAULT_FRAMEWORK_INFO);
+  frameworkInfo.set_checkpoint(true);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(&sched, frameworkInfo, master.get());
+
+  EXPECT_CALL(sched, registered(_, _, _));
+
+  driver.start();
+
+  Future<vector<Offer> > offers1;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers1));
+
+  // Start the first slave.
+  slave::Flags flags1 = this->CreateSlaveFlags();
+  slave::ProcessIsolator isolator1;
+
+  Try<PID<Slave> > slave1 = this->StartSlave(&isolator1, flags1);
+  ASSERT_SOME(slave1);
+
+  AWAIT_READY(offers1);
+  ASSERT_EQ(1u, offers1.get().size());
+
+  // Launch a long running task in the first slave.
+  TaskInfo task1 = createTask(offers1.get()[0], "sleep 1000");
+  vector<TaskInfo> tasks1;
+  tasks1.push_back(task1);
+
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .Times(1);
+
+  Future<Nothing> _statusUpdateAcknowledgement1 =
+    FUTURE_DISPATCH(slave1.get(), &Slave::_statusUpdateAcknowledgement);
+
+  driver.launchTasks(offers1.get()[0].id(), tasks1);
+
+  // Wait for the ACK to be checkpointed.
+  AWAIT_READY(_statusUpdateAcknowledgement1);
+
+  Future<vector<Offer> > offers2;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers2));
+
+  // Start the second slave.
+  slave::Flags flags2 = this->CreateSlaveFlags();
+  slave::ProcessIsolator isolator2;
+
+  Try<PID<Slave> > slave2 = this->StartSlave(&isolator2, flags2);
+  ASSERT_SOME(slave2);
+
+  AWAIT_READY(offers2);
+  ASSERT_EQ(1u, offers2.get().size());
+
+  // Launch a long running task in each slave.
+  TaskInfo task2 = createTask(offers2.get()[0], "sleep 1000");
+  vector<TaskInfo> tasks2;
+  tasks2.push_back(task2);
+
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .Times(1);
+
+  Future<Nothing> _statusUpdateAcknowledgement2 =
+    FUTURE_DISPATCH(slave2.get(), &Slave::_statusUpdateAcknowledgement);
+
+  driver.launchTasks(offers2.get()[0].id(), tasks2);
+
+  // Wait for the ACKs to be checkpointed.
+  AWAIT_READY(_statusUpdateAcknowledgement2);
+
+  this->Stop(slave1.get());
+  this->Stop(slave2.get());
+
+  Future<Nothing> _recover1 = FUTURE_DISPATCH(_, &Slave::_recover);
+  Future<Nothing> _recover2 = FUTURE_DISPATCH(_, &Slave::_recover);
+
+  Future<ReregisterSlaveMessage> reregisterSlave1 =
+    FUTURE_PROTOBUF(ReregisterSlaveMessage(), _, _);
+  Future<ReregisterSlaveMessage> reregisterSlave2 =
+    FUTURE_PROTOBUF(ReregisterSlaveMessage(), _, _);
+
+  // Restart both slaves using the same flags with new isolators.
+  slave::ProcessIsolator isolator3;
+
+  slave1 = this->StartSlave(&isolator3, flags1);
+  ASSERT_SOME(slave1);
+
+  slave::ProcessIsolator isolator4;
+
+  slave2 = this->StartSlave(&isolator4, flags2);
+  ASSERT_SOME(slave2);
+
+  Clock::pause();
+
+  AWAIT_READY(_recover1);
+  AWAIT_READY(_recover2);
+
+  // Wait for slaves to schedule reregister timeout.
+  Clock::settle();
+
+  Clock::advance(EXECUTOR_REREGISTER_TIMEOUT);
+
+  // Make sure all pending timeouts are fired.
+  Clock::settle();
+
+  Clock::resume();
+
+  // Wait for the slaves to re-register.
+  AWAIT_READY(reregisterSlave1);
+  AWAIT_READY(reregisterSlave2);
+
+  Future<TaskStatus> status1;
+  Future<TaskStatus> status2;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&status1))
+    .WillOnce(FutureArg<1>(&status2))
+    .WillRepeatedly(Return());        // Ignore subsequent updates.
+
+  Future<Nothing> executorTerminated1 =
+    FUTURE_DISPATCH(_, &Slave::executorTerminated);
+  Future<Nothing> executorTerminated2 =
+    FUTURE_DISPATCH(_, &Slave::executorTerminated);
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillRepeatedly(Return());        // Ignore subsequent offers.
+
+  // Kill both tasks.
+  driver.killTask(task1.task_id());
+  driver.killTask(task2.task_id());
+
+  AWAIT_READY(status1);
+  ASSERT_EQ(TASK_KILLED, status1.get().state());
+
+  AWAIT_READY(status2);
+  ASSERT_EQ(TASK_KILLED, status2.get().state());
+
+  AWAIT_READY(executorTerminated1);
+  AWAIT_READY(executorTerminated2);
+
+  driver.stop();
+  driver.join();
+
+  this->Shutdown(); // Shutdown before isolator(s) get deallocated.
+}