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 2014/05/12 21:51:12 UTC

[1/2] git commit: Moved ReconcileTaskTest test to its own file.

Repository: mesos
Updated Branches:
  refs/heads/master c4188341d -> cceb071a0


Moved ReconcileTaskTest test to its own file.

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


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

Branch: refs/heads/master
Commit: 63a51849217a563b58a6a271ac1d69e147562cc8
Parents: c418834
Author: Vinod Kone <vi...@twitter.com>
Authored: Thu May 8 13:54:23 2014 -0700
Committer: Vinod Kone <vi...@twitter.com>
Committed: Mon May 12 12:50:52 2014 -0700

----------------------------------------------------------------------
 src/Makefile.am                    |   1 +
 src/tests/master_tests.cpp         |  79 ------------------
 src/tests/reconciliation_tests.cpp | 144 ++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/63a51849/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 812ad2c..12374c4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -909,6 +909,7 @@ mesos_tests_SOURCES =				\
   tests/monitor_tests.cpp			\
   tests/paths_tests.cpp				\
   tests/protobuf_io_tests.cpp			\
+  tests/reconciliation_tests.cpp		\
   tests/registrar_tests.cpp			\
   tests/repair_tests.cpp			\
   tests/resource_offers_tests.cpp		\

http://git-wip-us.apache.org/repos/asf/mesos/blob/63a51849/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 30ea7ff..639e760 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -958,85 +958,6 @@ TEST_F(MasterTest, MasterLost)
 }
 
 
-// Test sends different state than current and expects an update with
-// the current state of task.
-//
-// TODO(nnielsen): Stubs have been left for future test, where test sends
-// expected state of non-existing task and an update with TASK_LOST should
-// be received. Also (not currently covered) if statuses are up to date,
-// nothing should happen.
-TEST_F(MasterTest, ReconcileTaskTest)
-{
-  Try<PID<Master> > master = StartMaster();
-  ASSERT_SOME(master);
-
-  MockExecutor exec(DEFAULT_EXECUTOR_ID);
-
-  TestContainerizer containerizer(&exec);
-
-  Try<PID<Slave> > slave = StartSlave(&containerizer);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  Future<FrameworkID> frameworkId;
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .WillOnce(FutureArg<1>(&frameworkId));
-
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 1, 512, "*"))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  EXPECT_CALL(exec, registered(_, _, _, _));
-
-  EXPECT_CALL(exec, launchTask(_, _))
-    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.start();
-
-  AWAIT_READY(status);
-  EXPECT_EQ(TASK_RUNNING, status.get().state());
-
-  EXPECT_EQ(true, status.get().has_slave_id());
-
-  const TaskID taskId = status.get().task_id();
-  const SlaveID slaveId = status.get().slave_id();
-
-  // If framwework has different state, current state should be reported.
-  Future<TaskStatus> status2;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status2));
-
-  vector<TaskStatus> statuses;
-
-  TaskStatus differentStatus;
-  differentStatus.mutable_task_id()->CopyFrom(taskId);
-  differentStatus.mutable_slave_id()->CopyFrom(slaveId);
-  differentStatus.set_state(TASK_KILLED);
-
-  statuses.push_back(differentStatus);
-
-  driver.reconcileTasks(statuses);
-
-  AWAIT_READY(status2);
-  EXPECT_EQ(TASK_RUNNING, status2.get().state());
-
-  EXPECT_CALL(exec, shutdown(_))
-    .Times(AtMost(1));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
-}
-
-
 // Test ensures two offers from same slave can be used for single task.
 // This is done by first launching single task which utilize half of the
 // available resources. A subsequent offer for the rest of the available

http://git-wip-us.apache.org/repos/asf/mesos/blob/63a51849/src/tests/reconciliation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reconciliation_tests.cpp b/src/tests/reconciliation_tests.cpp
new file mode 100644
index 0000000..e1c8a49
--- /dev/null
+++ b/src/tests/reconciliation_tests.cpp
@@ -0,0 +1,144 @@
+/**
+ * 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 <stdint.h>
+#include <unistd.h>
+
+#include <gmock/gmock.h>
+
+#include <vector>
+
+#include <mesos/mesos.hpp>
+#include <mesos/scheduler.hpp>
+
+#include <process/future.hpp>
+#include <process/pid.hpp>
+#include <process/process.hpp>
+
+#include <stout/uuid.hpp>
+
+#include "common/protobuf_utils.hpp"
+
+#include "master/master.hpp"
+
+#include "slave/slave.hpp"
+
+#include "tests/containerizer.hpp"
+#include "tests/mesos.hpp"
+
+using namespace mesos;
+using namespace mesos::internal;
+using namespace mesos::internal::tests;
+
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::Slave;
+
+using process::Future;
+using process::PID;
+
+using std::vector;
+
+using testing::_;
+using testing::AtMost;
+using testing::Return;
+
+
+class ReconciliationTest : public MesosTest {};
+
+
+// Test sends different state than current and expects an update with
+// the current state of task.
+//
+// TODO(nnielsen): Stubs have been left for future test, where test sends
+// expected state of non-existing task and an update with TASK_LOST should
+// be received. Also (not currently covered) if statuses are up to date,
+// nothing should happen.
+TEST_F(ReconciliationTest, TaskStateMismatch)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockExecutor exec(DEFAULT_EXECUTOR_ID);
+
+  TestContainerizer containerizer(&exec);
+
+  Try<PID<Slave> > slave = StartSlave(&containerizer);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 1, 512, "*"))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  EXPECT_CALL(exec, registered(_, _, _, _));
+
+  EXPECT_CALL(exec, launchTask(_, _))
+    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.start();
+
+  // Wait until the framework is registered.
+  AWAIT_READY(frameworkId);
+
+  AWAIT_READY(status);
+  EXPECT_EQ(TASK_RUNNING, status.get().state());
+
+  EXPECT_EQ(true, status.get().has_slave_id());
+
+  const TaskID taskId = status.get().task_id();
+  const SlaveID slaveId = status.get().slave_id();
+
+  // If framework has different state, current state should be reported.
+  Future<TaskStatus> status2;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status2));
+
+  vector<TaskStatus> statuses;
+
+  TaskStatus differentStatus;
+  differentStatus.mutable_task_id()->CopyFrom(taskId);
+  differentStatus.mutable_slave_id()->CopyFrom(slaveId);
+  differentStatus.set_state(TASK_KILLED);
+
+  statuses.push_back(differentStatus);
+
+  driver.reconcileTasks(statuses);
+
+  AWAIT_READY(status2);
+  EXPECT_EQ(TASK_RUNNING, status2.get().state());
+
+  EXPECT_CALL(exec, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+}


[2/2] git commit: Fixed tasks reconciliation and added tests.

Posted by vi...@apache.org.
Fixed tasks reconciliation and added tests.

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


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

Branch: refs/heads/master
Commit: cceb071a0af8ea4ea2597cb5519c8c98fa43b7bc
Parents: 63a5184
Author: Vinod Kone <vi...@twitter.com>
Authored: Thu May 8 13:55:25 2014 -0700
Committer: Vinod Kone <vi...@twitter.com>
Committed: Mon May 12 12:50:53 2014 -0700

----------------------------------------------------------------------
 src/master/master.cpp              |  13 +-
 src/master/master.hpp              |  20 +-
 src/tests/reconciliation_tests.cpp | 392 ++++++++++++++++++++++++++++++--
 3 files changed, 389 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/cceb071a/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index d851a72..0499877 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -2584,8 +2584,8 @@ void Master::reconcileTasks(
     return;
   }
 
-  LOG(INFO) << "Performing best-effort task state reconciliation for framework "
-            << frameworkId;
+  LOG(INFO) << "Performing task state reconciliation for " << statuses.size()
+            << " task statuses of framework " << frameworkId;
 
   // Reconciliation occurs for the following cases:
   //   (1) If the slave is unknown, we send TASK_LOST.
@@ -2609,13 +2609,13 @@ void Master::reconcileTasks(
         !slaves.reregistering.contains(status.slave_id()) &&
         !slaves.activated.contains(status.slave_id()) &&
         !slaves.removing.contains(status.slave_id())) {
-      // Slave is removed!
+      // Slave is unknown or removed!
       update = protobuf::createStatusUpdate(
           frameworkId,
           status.slave_id(),
           status.task_id(),
           TASK_LOST,
-          "Reconciliation: Slave is removed");
+          "Reconciliation: Slave is unknown/removed");
     }
 
     // Check for a known slave / task (cases (2) and (3)).
@@ -2645,7 +2645,10 @@ void Master::reconcileTasks(
     }
 
     if (update.isSome()) {
-      statusUpdate(update.get(), UPID());
+      CHECK_NOTNULL(framework);
+      StatusUpdateMessage message;
+      message.mutable_update()->CopyFrom(update.get());
+      send(framework->pid, message);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/cceb071a/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 0a350b0..de2ae62 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -199,6 +199,18 @@ public:
   // Made public for testing purposes.
   process::Future<Nothing> _recover(const Registry& registry);
 
+  // Continuation of reregisterSlave().
+  // Made public for testing purposes.
+  // TODO(vinod): Instead of doing this create and use a
+  // MockRegistrar.
+  void _reregisterSlave(
+      const SlaveInfo& slaveInfo,
+      const process::UPID& pid,
+      const std::vector<ExecutorInfo>& executorInfos,
+      const std::vector<Task>& tasks,
+      const std::vector<Archive::Framework>& completedFrameworks,
+      const process::Future<bool>& readmit);
+
   MasterInfo info() const
   {
     return info_;
@@ -219,14 +231,6 @@ protected:
       const process::UPID& pid,
       const process::Future<bool>& admit);
 
-  void _reregisterSlave(
-      const SlaveInfo& slaveInfo,
-      const process::UPID& pid,
-      const std::vector<ExecutorInfo>& executorInfos,
-      const std::vector<Task>& tasks,
-      const std::vector<Archive::Framework>& completedFrameworks,
-      const process::Future<bool>& readmit);
-
   void __reregisterSlave(
       Slave* slave,
       const std::vector<Task>& tasks);

http://git-wip-us.apache.org/repos/asf/mesos/blob/cceb071a/src/tests/reconciliation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reconciliation_tests.cpp b/src/tests/reconciliation_tests.cpp
index e1c8a49..677d18e 100644
--- a/src/tests/reconciliation_tests.cpp
+++ b/src/tests/reconciliation_tests.cpp
@@ -26,6 +26,7 @@
 #include <mesos/mesos.hpp>
 #include <mesos/scheduler.hpp>
 
+#include <process/clock.hpp>
 #include <process/future.hpp>
 #include <process/pid.hpp>
 #include <process/process.hpp>
@@ -34,6 +35,7 @@
 
 #include "common/protobuf_utils.hpp"
 
+#include "master/flags.hpp"
 #include "master/master.hpp"
 
 #include "slave/slave.hpp"
@@ -49,6 +51,7 @@ using mesos::internal::master::Master;
 
 using mesos::internal::slave::Slave;
 
+using process::Clock;
 using process::Future;
 using process::PID;
 
@@ -62,13 +65,9 @@ using testing::Return;
 class ReconciliationTest : public MesosTest {};
 
 
-// Test sends different state than current and expects an update with
-// the current state of task.
-//
-// TODO(nnielsen): Stubs have been left for future test, where test sends
-// expected state of non-existing task and an update with TASK_LOST should
-// be received. Also (not currently covered) if statuses are up to date,
-// nothing should happen.
+// This test verifies that task state reconciliation for a task
+// whose state differs between framework and master results in a
+// status update.
 TEST_F(ReconciliationTest, TaskStateMismatch)
 {
   Try<PID<Master> > master = StartMaster();
@@ -98,41 +97,41 @@ TEST_F(ReconciliationTest, TaskStateMismatch)
   EXPECT_CALL(exec, launchTask(_, _))
     .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
 
-  Future<TaskStatus> status;
+  Future<TaskStatus> update;
   EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
+    .WillOnce(FutureArg<1>(&update));
 
   driver.start();
 
   // Wait until the framework is registered.
   AWAIT_READY(frameworkId);
 
-  AWAIT_READY(status);
-  EXPECT_EQ(TASK_RUNNING, status.get().state());
+  AWAIT_READY(update);
+  EXPECT_EQ(TASK_RUNNING, update.get().state());
 
-  EXPECT_EQ(true, status.get().has_slave_id());
+  EXPECT_EQ(true, update.get().has_slave_id());
 
-  const TaskID taskId = status.get().task_id();
-  const SlaveID slaveId = status.get().slave_id();
+  const TaskID taskId = update.get().task_id();
+  const SlaveID slaveId = update.get().slave_id();
 
   // If framework has different state, current state should be reported.
-  Future<TaskStatus> status2;
+  Future<TaskStatus> update2;
   EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status2));
+    .WillOnce(FutureArg<1>(&update2));
 
   vector<TaskStatus> statuses;
 
-  TaskStatus differentStatus;
-  differentStatus.mutable_task_id()->CopyFrom(taskId);
-  differentStatus.mutable_slave_id()->CopyFrom(slaveId);
-  differentStatus.set_state(TASK_KILLED);
+  TaskStatus status;
+  status.mutable_task_id()->CopyFrom(taskId);
+  status.mutable_slave_id()->CopyFrom(slaveId);
+  status.set_state(TASK_KILLED);
 
-  statuses.push_back(differentStatus);
+  statuses.push_back(status);
 
   driver.reconcileTasks(statuses);
 
-  AWAIT_READY(status2);
-  EXPECT_EQ(TASK_RUNNING, status2.get().state());
+  AWAIT_READY(update2);
+  EXPECT_EQ(TASK_RUNNING, update2.get().state());
 
   EXPECT_CALL(exec, shutdown(_))
     .Times(AtMost(1));
@@ -142,3 +141,350 @@ TEST_F(ReconciliationTest, TaskStateMismatch)
 
   Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
 }
+
+
+// This test verifies that task state reconciliation for a task
+// whose state does not differ between framework and master does not
+// result in a status update.
+TEST_F(ReconciliationTest, TaskStateMatch)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockExecutor exec(DEFAULT_EXECUTOR_ID);
+
+  TestContainerizer containerizer(&exec);
+
+  Try<PID<Slave> > slave = StartSlave(&containerizer);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 1, 512, "*"))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  EXPECT_CALL(exec, registered(_, _, _, _));
+
+  EXPECT_CALL(exec, launchTask(_, _))
+    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
+
+  Future<TaskStatus> update;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&update));
+
+  driver.start();
+
+  // Wait until the framework is registered.
+  AWAIT_READY(frameworkId);
+
+  AWAIT_READY(update);
+  EXPECT_EQ(TASK_RUNNING, update.get().state());
+
+  EXPECT_EQ(true, update.get().has_slave_id());
+
+  const TaskID taskId = update.get().task_id();
+  const SlaveID slaveId = update.get().slave_id();
+
+  // Framework should not receive a status udpate.
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .Times(0);
+
+  vector<TaskStatus> statuses;
+
+  TaskStatus status;
+  status.mutable_task_id()->CopyFrom(taskId);
+  status.mutable_slave_id()->CopyFrom(slaveId);
+  status.set_state(TASK_RUNNING);
+
+  statuses.push_back(status);
+
+  Future<ReconcileTasksMessage> reconcileTasksMessage =
+    FUTURE_PROTOBUF(ReconcileTasksMessage(), _ , _);
+
+  Clock::pause();
+
+  driver.reconcileTasks(statuses);
+
+  // Make sure the master received the reconcile tasks message.
+  AWAIT_READY(reconcileTasksMessage);
+
+  // The Clock::settle() will ensure that framework would receive
+  // a status update if it is sent by the master. In this test it
+  // shouldn't receive any.
+  Clock::settle();
+
+  EXPECT_CALL(exec, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+}
+
+
+// This test verifies that reconciliation of a task that belongs to an
+// unknown slave results in TASK_LOST.
+TEST_F(ReconciliationTest, UnknownSlave)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  driver.start();
+
+  // Wait until the framework is registered.
+  AWAIT_READY(frameworkId);
+
+  Future<TaskStatus> update;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&update));
+
+  vector<TaskStatus> statuses;
+
+  // Create a task status with a random slave id (and task id).
+  TaskStatus status;
+  status.mutable_task_id()->set_value(UUID::random().toString());
+  status.mutable_slave_id()->set_value(UUID::random().toString());
+  status.set_state(TASK_RUNNING);
+
+  statuses.push_back(status);
+
+  driver.reconcileTasks(statuses);
+
+  // Framework should receive TASK_LOST because the slave is unknown.
+  AWAIT_READY(update);
+  EXPECT_EQ(TASK_LOST, update.get().state());
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test verifies that reconciliation of a task that belongs to an
+// unknown slave but with non-strict registry doesn't result in a
+// status update.
+TEST_F(ReconciliationTest, UnknownSlaveNonStrictRegistry)
+{
+  master::Flags flags = CreateMasterFlags();
+  flags.registry_strict = false; // Non-strict registry.
+  Try<PID<Master> > master = StartMaster(flags);
+  ASSERT_SOME(master);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  driver.start();
+
+  // Wait until the framework is registered.
+  AWAIT_READY(frameworkId);
+
+  // Framework should not receive any update.
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .Times(0);
+
+  vector<TaskStatus> statuses;
+
+  // Create a task status with a random slave id (and task id).
+  TaskStatus status;
+  status.mutable_task_id()->set_value(UUID::random().toString());
+  status.mutable_slave_id()->set_value(UUID::random().toString());
+  status.set_state(TASK_RUNNING);
+
+  statuses.push_back(status);
+
+  Future<ReconcileTasksMessage> reconcileTasksMessage =
+    FUTURE_PROTOBUF(ReconcileTasksMessage(), _ , _);
+
+  Clock::pause();
+
+  driver.reconcileTasks(statuses);
+
+  // Make sure the master received the reconcile tasks message.
+  AWAIT_READY(reconcileTasksMessage);
+
+  // The Clock::settle() will ensure that framework would receive
+  // a status update if it is sent by the master. In this test it
+  // shouldn't receive any.
+  Clock::settle();
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test verifies that reconciliation of an unknown task that
+// belongs to a known slave results in TASK_LOST.
+TEST_F(ReconciliationTest, UnknownTask)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  Future<SlaveRegisteredMessage> slaveRegisteredMessage =
+    FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
+
+  Try<PID<Slave> > slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  // Wait for the slave to register and get the slave id.
+  AWAIT_READY(slaveRegisteredMessage);
+  const SlaveID slaveId = slaveRegisteredMessage.get().slave_id();
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+    &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillRepeatedly(Return()); // Ignore offers.
+
+  driver.start();
+
+  // Wait until the framework is registered.
+  AWAIT_READY(frameworkId);
+
+  Future<TaskStatus> update;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&update));
+
+  vector<TaskStatus> statuses;
+
+  // Create a task status with a random task id.
+  TaskStatus status;
+  status.mutable_task_id()->set_value(UUID::random().toString());
+  status.mutable_slave_id()->CopyFrom(slaveId);
+  status.set_state(TASK_RUNNING);
+
+  statuses.push_back(status);
+
+  driver.reconcileTasks(statuses);
+
+  // Framework should receive TASK_LOST for unknown task.
+  AWAIT_READY(update);
+  EXPECT_EQ(TASK_LOST, update.get().state());
+
+  driver.stop();
+  driver.join();
+
+  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+}
+
+
+// This test verifies that reconciliation of a task that belongs to a
+// slave that is a transitional state doesn't result in an update.
+TEST_F(ReconciliationTest, SlaveInTransition)
+{
+  master::Flags masterFlags = CreateMasterFlags();
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Start a checkpointing slave.
+  slave::Flags slaveFlags = CreateSlaveFlags();
+  slaveFlags.checkpoint = true;
+
+  Future<SlaveRegisteredMessage> slaveRegisteredMessage =
+    FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
+
+  Try<PID<Slave> > slave = StartSlave(slaveFlags);
+  ASSERT_SOME(slave);
+
+  // Wait for the slave to register and get the slave id.
+  AWAIT_READY(slaveRegisteredMessage);
+  const SlaveID slaveId = slaveRegisteredMessage.get().slave_id();
+
+  // Stop the master and slave.
+  Stop(master.get());
+  Stop(slave.get());
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillRepeatedly(Return()); // Ignore offers.
+
+  // Framework should not receive any update.
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .Times(0);
+
+  // Drop '&Master::_reregisterSlave' dispatch so that the slave is
+  // in 'reregistering' state.
+  Future<Nothing> _reregisterSlave =
+    DROP_DISPATCH(_, &Master::_reregisterSlave);
+
+  // Restart the master.
+  master = StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  driver.start();
+
+  // Wait for the framework to register.
+  AWAIT_READY(frameworkId);
+
+  // Restart the slave.
+  slave = StartSlave(slaveFlags);
+  ASSERT_SOME(slave);
+
+  // Slave will be in 'reregistering' state here.
+  AWAIT_READY(_reregisterSlave);
+
+  vector<TaskStatus> statuses;
+
+  // Create a task status with a random task id.
+  TaskStatus status;
+  status.mutable_task_id()->set_value(UUID::random().toString());
+  status.mutable_slave_id()->CopyFrom(slaveId);
+  status.set_state(TASK_RUNNING);
+
+  statuses.push_back(status);
+
+  Future<ReconcileTasksMessage> reconcileTasksMessage =
+    FUTURE_PROTOBUF(ReconcileTasksMessage(), _ , _);
+
+  Clock::pause();
+
+  driver.reconcileTasks(statuses);
+
+  // Make sure the master received the reconcile tasks message.
+  AWAIT_READY(reconcileTasksMessage);
+
+  // The Clock::settle() will ensure that framework would receive
+  // a status update if it is sent by the master. In this test it
+  // shouldn't receive any.
+  Clock::settle();
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}