You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2015/03/05 01:18:37 UTC

[1/2] mesos git commit: Moved and re-enabled a persistent volume test.

Repository: mesos
Updated Branches:
  refs/heads/master d8b36f1b8 -> 9a4f7434d


Moved and re-enabled a persistent volume test.

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


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

Branch: refs/heads/master
Commit: 9a4f7434d97907ea14fe2dd3976d52fabc37b002
Parents: 79d2139
Author: Jie Yu <yu...@gmail.com>
Authored: Tue Mar 3 12:12:20 2015 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Mar 4 16:18:21 2015 -0800

----------------------------------------------------------------------
 src/tests/master_validation_tests.cpp | 178 +++++++++++++++--------------
 src/tests/mesos.hpp                   |  53 +++++++++
 src/tests/persistent_volume_tests.cpp |  78 +++----------
 3 files changed, 163 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/9a4f7434/src/tests/master_validation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_validation_tests.cpp b/src/tests/master_validation_tests.cpp
index 70ec6db..c874292 100644
--- a/src/tests/master_validation_tests.cpp
+++ b/src/tests/master_validation_tests.cpp
@@ -27,6 +27,10 @@
 #include <mesos/resources.hpp>
 #include <mesos/scheduler.hpp>
 
+#include <process/clock.hpp>
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+
 #include <stout/gtest.hpp>
 #include <stout/strings.hpp>
 #include <stout/uuid.hpp>
@@ -46,6 +50,7 @@ using mesos::internal::master::Master;
 
 using mesos::internal::slave::Slave;
 
+using process::Clock;
 using process::Future;
 using process::PID;
 
@@ -136,7 +141,7 @@ TEST_F(ResourceValidationTest, NonPersistentVolume)
 }
 
 
-class CreateOperationValidationTest : public ::testing::Test {};
+class CreateOperationValidationTest : public MesosTest {};
 
 
 // This test verifies that all resources specified in the CREATE
@@ -180,6 +185,94 @@ TEST_F(CreateOperationValidationTest, DuplicatedPersistenceID)
 }
 
 
+// This test verifies that creating a persistent volume that is larger
+// than the offered disk resource results won't succeed.
+TEST_F(CreateOperationValidationTest, InsufficientDiskResource)
+{
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.set_role("role1");
+
+  master::Flags masterFlags = CreateMasterFlags();
+
+  ACLs acls;
+  mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+  acl->mutable_principals()->add_values(frameworkInfo.principal());
+  acl->mutable_roles()->add_values(frameworkInfo.role());
+
+  masterFlags.acls = acls;
+  masterFlags.roles = "role1";
+
+  Try<PID<Master>> master = StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  slave::Flags slaveFlags = CreateSlaveFlags();
+  slaveFlags.checkpoint = true;
+  slaveFlags.resources = "disk(role1):1024";
+
+  Try<PID<Slave>> slave = StartSlave(slaveFlags);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers1;
+  Future<vector<Offer>> offers2;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers1))
+    .WillOnce(FutureArg<1>(&offers2))
+    .WillRepeatedly(Return());        // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers1);
+  EXPECT_FALSE(offers1.get().empty());
+
+  Offer offer1 = offers1.get()[0];
+
+  // Since the CREATE operation will fail, we don't expect any
+  // CheckpointResourcesMessage to be sent.
+  EXPECT_NO_FUTURE_PROTOBUFS(CheckpointResourcesMessage(), _, _);
+
+  Resources volume = createPersistentVolume(
+      Megabytes(2048),
+      "role1",
+      "id1",
+      "path1");
+
+  // We want to be notified immediately with new offer.
+  Filters filters;
+  filters.set_refuse_seconds(0);
+
+  driver.acceptOffers(
+      {offer1.id()},
+      {CREATE(volume)},
+      filters);
+
+  // Advance the clock to trigger another allocation.
+  Clock::pause();
+
+  Clock::settle();
+  Clock::advance(masterFlags.allocation_interval);
+
+  AWAIT_READY(offers2);
+  EXPECT_FALSE(offers2.get().empty());
+
+  Offer offer2 = offers2.get()[0];
+
+  EXPECT_EQ(Resources(offer1.resources()), Resources(offer2.resources()));
+
+  Clock::resume();
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
 class DestroyOperationValidationTest : public ::testing::Test {};
 
 
@@ -722,89 +815,6 @@ TEST_F(TaskValidationTest, ExecutorInfoDiffersOnDifferentSlaves)
   Shutdown();
 }
 
-
-// This test ensures that a persistent volume that is larger than the
-// offered disk resources results in a failed task.
-TEST_F(TaskValidationTest, DISABLED_AcquirePersistentDiskTooBig)
-{
-  // Create a framework with role "role1";
-  FrameworkInfo frameworkInfo;
-  frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_role("role1");
-
-  // Setup ACLs in order to receive offers for "role1".
-  ACLs acls;
-  mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
-  acl->mutable_principals()->add_values(frameworkInfo.principal());
-  acl->mutable_roles()->add_values(frameworkInfo.role());
-
-  // Start master with ACLs.
-  master::Flags masterFlags = CreateMasterFlags();
-  masterFlags.roles = frameworkInfo.role();
-  masterFlags.acls = acls;
-
-  Try<PID<Master>> master = StartMaster(masterFlags);
-  ASSERT_SOME(master);
-
-  slave::Flags slaveFlags = CreateSlaveFlags();
-  slaveFlags.resources = "cpus(*):4;mem(*):2048;disk(role1):1024";
-
-  Try<PID<Slave>> slave = StartSlave(slaveFlags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .Times(1);
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  // Create a persistent volume whose size is larger than the size of
-  // the offered disk.
-  Resource diskResource = Resources::parse("disk", "2048", "role1").get();
-  diskResource.mutable_disk()->CopyFrom(createDiskInfo("1", "1"));
-
-  // Include other resources in task resources.
-  Resources taskResources =
-    Resources::parse("cpus:1;mem:128").get() + diskResource;
-
-  Offer offer = offers.get()[0];
-  TaskInfo task =
-    createTask(offer.slave_id(), taskResources, "", DEFAULT_EXECUTOR_ID);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task);
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offer.id(), tasks);
-
-  AWAIT_READY(status);
-  EXPECT_EQ(task.task_id(), status.get().task_id());
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-  EXPECT_TRUE(status.get().has_message());
-  EXPECT_TRUE(strings::contains(
-      status.get().message(), "Failed to create persistent volumes"));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
 // TODO(jieyu): Add tests for checking duplicated persistence ID
 // against offered resources.
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/9a4f7434/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index e91e5e4..45e3520 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -22,6 +22,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include <mesos/executor.hpp>
 #include <mesos/scheduler.hpp>
@@ -33,6 +34,8 @@
 #include <process/pid.hpp>
 #include <process/process.hpp>
 
+#include <stout/bytes.hpp>
+#include <stout/foreach.hpp>
 #include <stout/gtest.hpp>
 #include <stout/lambda.hpp>
 #include <stout/none.hpp>
@@ -401,6 +404,56 @@ inline Resource::DiskInfo createDiskInfo(
 }
 
 
+inline Resource createPersistentVolume(
+    const Bytes& size,
+    const std::string& role,
+    const std::string& persistenceId,
+    const std::string& containerPath)
+{
+  Resource volume = Resources::parse(
+      "disk",
+      stringify(size.megabytes()),
+      role).get();
+
+  volume.mutable_disk()->CopyFrom(
+      createDiskInfo(persistenceId, containerPath));
+
+  return volume;
+}
+
+
+// Helpers for creating offer operations.
+inline Offer::Operation CREATE(const Resources& volumes)
+{
+  Offer::Operation operation;
+  operation.set_type(Offer::Operation::CREATE);
+  operation.mutable_create()->mutable_volumes()->CopyFrom(volumes);
+  return operation;
+}
+
+
+inline Offer::Operation DESTROY(const Resources& volumes)
+{
+  Offer::Operation operation;
+  operation.set_type(Offer::Operation::DESTROY);
+  operation.mutable_destroy()->mutable_volumes()->CopyFrom(volumes);
+  return operation;
+}
+
+
+inline Offer::Operation LAUNCH(const std::vector<TaskInfo>& tasks)
+{
+  Offer::Operation operation;
+  operation.set_type(Offer::Operation::LAUNCH);
+
+  foreach (const TaskInfo& task, tasks) {
+    operation.mutable_launch()->add_task_infos()->CopyFrom(task);
+  }
+
+  return operation;
+}
+
+
 // Definition of a mock Scheduler to be used in tests with gmock.
 class MockScheduler : public Scheduler
 {

http://git-wip-us.apache.org/repos/asf/mesos/blob/9a4f7434/src/tests/persistent_volume_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/persistent_volume_tests.cpp b/src/tests/persistent_volume_tests.cpp
index e739cf5..b617117 100644
--- a/src/tests/persistent_volume_tests.cpp
+++ b/src/tests/persistent_volume_tests.cpp
@@ -28,7 +28,6 @@
 #include <process/gmock.hpp>
 #include <process/gtest.hpp>
 
-#include <stout/bytes.hpp>
 #include <stout/foreach.hpp>
 #include <stout/format.hpp>
 #include <stout/hashset.hpp>
@@ -87,51 +86,6 @@ protected:
 
     return flags;
   }
-
-  Resource PersistentVolume(
-      const Bytes& size,
-      const string& role,
-      const string& persistenceId,
-      const string& containerPath)
-  {
-    Resource volume = Resources::parse(
-        "disk",
-        stringify(size.megabytes()),
-        role).get();
-
-    volume.mutable_disk()->CopyFrom(
-        createDiskInfo(persistenceId, containerPath));
-
-    return volume;
-  }
-
-  Offer::Operation CreateOperation(const Resources& volumes)
-  {
-    Offer::Operation operation;
-    operation.set_type(Offer::Operation::CREATE);
-    operation.mutable_create()->mutable_volumes()->CopyFrom(volumes);
-    return operation;
-  }
-
-  Offer::Operation DestroyOperation(const Resources& volumes)
-  {
-    Offer::Operation operation;
-    operation.set_type(Offer::Operation::DESTROY);
-    operation.mutable_destroy()->mutable_volumes()->CopyFrom(volumes);
-    return operation;
-  }
-
-  Offer::Operation LaunchOperation(const vector<TaskInfo>& tasks)
-  {
-    Offer::Operation operation;
-    operation.set_type(Offer::Operation::LAUNCH);
-
-    foreach (const TaskInfo& task, tasks) {
-      operation.mutable_launch()->add_task_infos()->CopyFrom(task);
-    }
-
-    return operation;
-  }
 };
 
 
@@ -180,13 +134,13 @@ TEST_F(PersistentVolumeTest, SendingCheckpointResourcesMessage)
   Future<CheckpointResourcesMessage> message1 =
     FUTURE_PROTOBUF(CheckpointResourcesMessage(), _, _);
 
-  Resources volume1 = PersistentVolume(
+  Resources volume1 = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
       "path1");
 
-  Resources volume2 = PersistentVolume(
+  Resources volume2 = createPersistentVolume(
       Megabytes(128),
       "role1",
       "id2",
@@ -194,9 +148,9 @@ TEST_F(PersistentVolumeTest, SendingCheckpointResourcesMessage)
 
   driver.acceptOffers(
       {offer.id()},
-      {CreateOperation(volume1),
-       CreateOperation(volume2),
-       DestroyOperation(volume1)});
+      {CREATE(volume1),
+       CREATE(volume2),
+       DESTROY(volume1)});
 
   // NOTE: Currently, we send one message per operation. But this is
   // an implementation detail which is subject to change.
@@ -255,7 +209,7 @@ TEST_F(PersistentVolumeTest, ResourcesCheckpointing)
   Future<CheckpointResourcesMessage> checkpointResources =
     FUTURE_PROTOBUF(CheckpointResourcesMessage(), _, slave.get());
 
-  Resources volume = PersistentVolume(
+  Resources volume = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
@@ -263,7 +217,7 @@ TEST_F(PersistentVolumeTest, ResourcesCheckpointing)
 
   driver.acceptOffers(
       {offer.id()},
-      {CreateOperation(volume)});
+      {CREATE(volume)});
 
   AWAIT_READY(checkpointResources);
 
@@ -318,7 +272,7 @@ TEST_F(PersistentVolumeTest, PreparePersistentVolume)
 
   Offer offer = offers.get()[0];
 
-  Resources volume = PersistentVolume(
+  Resources volume = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
@@ -329,7 +283,7 @@ TEST_F(PersistentVolumeTest, PreparePersistentVolume)
 
   driver.acceptOffers(
       {offer.id()},
-      {CreateOperation(volume)});
+      {CREATE(volume)});
 
   AWAIT_READY(checkpointResources);
 
@@ -389,7 +343,7 @@ TEST_F(PersistentVolumeTest, MasterFailover)
 
   Offer offer1 = offers1.get()[0];
 
-  Resources volume = PersistentVolume(
+  Resources volume = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
@@ -400,7 +354,7 @@ TEST_F(PersistentVolumeTest, MasterFailover)
 
   driver.acceptOffers(
       {offer1.id()},
-      {CreateOperation(volume)});
+      {CREATE(volume)});
 
   AWAIT_READY(checkpointResources);
 
@@ -488,7 +442,7 @@ TEST_F(PersistentVolumeTest, IncompatibleCheckpointedResources)
 
   Offer offer = offers.get()[0];
 
-  Resources volume = PersistentVolume(
+  Resources volume = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
@@ -499,7 +453,7 @@ TEST_F(PersistentVolumeTest, IncompatibleCheckpointedResources)
 
   driver.acceptOffers(
       {offer.id()},
-      {CreateOperation(volume)});
+      {CREATE(volume)});
 
   AWAIT_READY(checkpointResources);
 
@@ -576,7 +530,7 @@ TEST_F(PersistentVolumeTest, AccessPersistentVolume)
 
   Offer offer = offers.get()[0];
 
-  Resources volume = PersistentVolume(
+  Resources volume = createPersistentVolume(
       Megabytes(64),
       "role1",
       "id1",
@@ -599,8 +553,8 @@ TEST_F(PersistentVolumeTest, AccessPersistentVolume)
 
   driver.acceptOffers(
       {offer.id()},
-      {CreateOperation(volume),
-       LaunchOperation({task})});
+      {CREATE(volume),
+       LAUNCH({task})});
 
   AWAIT_READY(status1);
   EXPECT_EQ(task.task_id(), status1.get().task_id());


[2/2] mesos git commit: Moved task validation tests to master_validation_tests.cpp.

Posted by ji...@apache.org.
Moved task validation tests to master_validation_tests.cpp.

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


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

Branch: refs/heads/master
Commit: 79d213986cbcd898bb38e26ed9cf84773b818b6b
Parents: d8b36f1
Author: Jie Yu <yu...@gmail.com>
Authored: Tue Mar 3 11:42:49 2015 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Mar 4 16:18:21 2015 -0800

----------------------------------------------------------------------
 src/tests/master_validation_tests.cpp | 623 ++++++++++++++++++++++++++++-
 src/tests/resource_offers_tests.cpp   | 606 +---------------------------
 2 files changed, 624 insertions(+), 605 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/79d21398/src/tests/master_validation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_validation_tests.cpp b/src/tests/master_validation_tests.cpp
index 38ddb1d..70ec6db 100644
--- a/src/tests/master_validation_tests.cpp
+++ b/src/tests/master_validation_tests.cpp
@@ -16,23 +16,45 @@
  * limitations under the License.
  */
 
+#include <gmock/gmock.h>
+
 #include <google/protobuf/repeated_field.h>
 
-#include <gtest/gtest.h>
+#include <vector>
 
+#include <mesos/executor.hpp>
 #include <mesos/mesos.hpp>
 #include <mesos/resources.hpp>
+#include <mesos/scheduler.hpp>
 
 #include <stout/gtest.hpp>
+#include <stout/strings.hpp>
+#include <stout/uuid.hpp>
 
+#include "master/master.hpp"
 #include "master/validation.hpp"
 
+#include "slave/slave.hpp"
+
 #include "tests/mesos.hpp"
 
 using namespace mesos::internal::master::validation;
 
 using google::protobuf::RepeatedPtrField;
 
+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;
+
 namespace mesos {
 namespace internal {
 namespace tests {
@@ -200,6 +222,605 @@ TEST_F(DestroyOperationValidationTest, UnknownPersistentVolume)
   EXPECT_SOME(operation::validate(destroy, Resources()));
 }
 
+
+// TODO(jieyu): All of the task validation tests have the same flow:
+// launch a task, expect an update of a particular format (invalid w/
+// message). Consider providing common functionalities in the test
+// fixture to avoid code bloat. Ultimately, we should make task or
+// offer validation unit testable.
+class TaskValidationTest : public MesosTest {};
+
+
+TEST_F(TaskValidationTest, TaskUsesInvalidFrameworkID)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  // Create an executor with a random framework id.
+  ExecutorInfo executor;
+  executor = DEFAULT_EXECUTOR_INFO;
+  executor.mutable_framework_id()->set_value(UUID::random().toString());
+
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(LaunchTasks(executor, 1, 1, 16, "*"))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.start();
+
+  AWAIT_READY(status);
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_TRUE(strings::startsWith(
+      status.get().message(), "ExecutorInfo has an invalid FrameworkID"));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+TEST_F(TaskValidationTest, TaskUsesCommandInfoAndExecutorInfo)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  // Create a task that uses both command info and task info.
+  TaskInfo task = createTask(offers.get()[0], ""); // Command task.
+  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO); // Executor task.
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(status);
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_TRUE(strings::contains(
+      status.get().message(), "CommandInfo or ExecutorInfo present"));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+TEST_F(TaskValidationTest, TaskUsesNoResources)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("1");
+  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(status);
+  EXPECT_EQ(task.task_id(), status.get().task_id());
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
+  EXPECT_TRUE(status.get().has_message());
+  EXPECT_EQ("Task uses no resources", status.get().message());
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+TEST_F(TaskValidationTest, TaskUsesMoreResourcesThanOffered)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("1");
+  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
+
+  Resource* cpus = task.add_resources();
+  cpus->set_name("cpus");
+  cpus->set_type(Value::SCALAR);
+  cpus->mutable_scalar()->set_value(2.01);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(status);
+
+  EXPECT_EQ(task.task_id(), status.get().task_id());
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
+  EXPECT_TRUE(status.get().has_message());
+  EXPECT_TRUE(strings::contains(
+      status.get().message(), "Task uses more resources"));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test verifies that if two tasks are launched with the same
+// task ID, the second task will get rejected.
+TEST_F(TaskValidationTest, DuplicatedTaskID)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockExecutor exec(DEFAULT_EXECUTOR_ID);
+
+  Try<PID<Slave>> slave = StartSlave(&exec);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  ExecutorInfo executor;
+  executor.mutable_executor_id()->set_value("default");
+  executor.mutable_command()->set_value("exit 1");
+
+  // Create two tasks with the same id.
+  TaskInfo task1;
+  task1.set_name("");
+  task1.mutable_task_id()->set_value("1");
+  task1.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task1.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:32").get());
+  task1.mutable_executor()->MergeFrom(executor);
+
+  TaskInfo task2;
+  task2.set_name("");
+  task2.mutable_task_id()->set_value("1");
+  task2.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task2.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:32").get());
+  task2.mutable_executor()->MergeFrom(executor);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task1);
+  tasks.push_back(task2);
+
+  EXPECT_CALL(exec, registered(_, _, _, _));
+
+  // Grab the first task but don't send a status update.
+  Future<TaskInfo> task;
+  EXPECT_CALL(exec, launchTask(_, _))
+    .WillOnce(FutureArg<1>(&task));
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(task);
+  EXPECT_EQ(task1.task_id(), task.get().task_id());
+
+  AWAIT_READY(status);
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
+
+  EXPECT_TRUE(strings::startsWith(
+      status.get().message(), "Task has duplicate ID"));
+
+  EXPECT_CALL(exec, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test verifies that two tasks launched on the same slave with
+// the same executor id but different executor info are rejected.
+TEST_F(TaskValidationTest, ExecutorInfoDiffersOnSameSlave)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockExecutor exec(DEFAULT_EXECUTOR_ID);
+
+  Try<PID<Slave>> slave = StartSlave(&exec);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  ExecutorInfo executor;
+  executor.mutable_executor_id()->set_value("default");
+  executor.mutable_command()->set_value("exit 1");
+
+  TaskInfo task1;
+  task1.set_name("");
+  task1.mutable_task_id()->set_value("1");
+  task1.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task1.mutable_resources()->MergeFrom(
+      Resources::parse("cpus:1;mem:512").get());
+  task1.mutable_executor()->MergeFrom(executor);
+
+  executor.mutable_command()->set_value("exit 2");
+
+  TaskInfo task2;
+  task2.set_name("");
+  task2.mutable_task_id()->set_value("2");
+  task2.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task2.mutable_resources()->MergeFrom(
+      Resources::parse("cpus:1;mem:512").get());
+  task2.mutable_executor()->MergeFrom(executor);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task1);
+  tasks.push_back(task2);
+
+  EXPECT_CALL(exec, registered(_, _, _, _))
+    .Times(1);
+
+  // Grab the "good" task but don't send a status update.
+  Future<TaskInfo> task;
+  EXPECT_CALL(exec, launchTask(_, _))
+    .WillOnce(FutureArg<1>(&task));
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(task);
+  EXPECT_EQ(task1.task_id(), task.get().task_id());
+
+  AWAIT_READY(status);
+  EXPECT_EQ(task2.task_id(), status.get().task_id());
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
+  EXPECT_TRUE(status.get().has_message());
+  EXPECT_TRUE(strings::contains(
+      status.get().message(), "Task has invalid ExecutorInfo"));
+
+  EXPECT_CALL(exec, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test verifies that two tasks each launched on a different
+// slave with same executor id but different executor info are
+// allowed.
+TEST_F(TaskValidationTest, ExecutorInfoDiffersOnDifferentSlaves)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<Nothing> registered;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureSatisfy(&registered));
+
+  driver.start();
+
+  AWAIT_READY(registered);
+
+  Future<vector<Offer>> offers1;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers1));
+
+  // Start the first slave.
+  MockExecutor exec1(DEFAULT_EXECUTOR_ID);
+
+  Try<PID<Slave>> slave1 = StartSlave(&exec1);
+  ASSERT_SOME(slave1);
+
+  AWAIT_READY(offers1);
+  EXPECT_NE(0u, offers1.get().size());
+
+  // Launch the first task with the default executor id.
+  ExecutorInfo executor1;
+  executor1 = DEFAULT_EXECUTOR_INFO;
+  executor1.mutable_command()->set_value("exit 1");
+
+  TaskInfo task1 = createTask(
+      offers1.get()[0], executor1.command().value(), executor1.executor_id());
+
+  vector<TaskInfo> tasks1;
+  tasks1.push_back(task1);
+
+  EXPECT_CALL(exec1, registered(_, _, _, _))
+    .Times(1);
+
+  EXPECT_CALL(exec1, launchTask(_, _))
+    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
+
+  Future<TaskStatus> status1;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status1));
+
+  driver.launchTasks(offers1.get()[0].id(), tasks1);
+
+  AWAIT_READY(status1);
+  ASSERT_EQ(TASK_RUNNING, status1.get().state());
+
+  Future<vector<Offer>> offers2;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers2))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  // Now start the second slave.
+  MockExecutor exec2(DEFAULT_EXECUTOR_ID);
+
+  Try<PID<Slave>> slave2 = StartSlave(&exec2);
+  ASSERT_SOME(slave2);
+
+  AWAIT_READY(offers2);
+  EXPECT_NE(0u, offers2.get().size());
+
+  // Now launch the second task with the same executor id but
+  // a different executor command.
+  ExecutorInfo executor2;
+  executor2 = executor1;
+  executor2.mutable_command()->set_value("exit 2");
+
+  TaskInfo task2 = createTask(
+      offers2.get()[0], executor2.command().value(), executor2.executor_id());
+
+  vector<TaskInfo> tasks2;
+  tasks2.push_back(task2);
+
+  EXPECT_CALL(exec2, registered(_, _, _, _))
+    .Times(1);
+
+  EXPECT_CALL(exec2, launchTask(_, _))
+    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
+
+  Future<TaskStatus> status2;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status2));
+
+  driver.launchTasks(offers2.get()[0].id(), tasks2);
+
+  AWAIT_READY(status2);
+  ASSERT_EQ(TASK_RUNNING, status2.get().state());
+
+  EXPECT_CALL(exec1, shutdown(_))
+    .Times(AtMost(1));
+
+  EXPECT_CALL(exec2, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
+// This test ensures that a persistent volume that is larger than the
+// offered disk resources results in a failed task.
+TEST_F(TaskValidationTest, DISABLED_AcquirePersistentDiskTooBig)
+{
+  // Create a framework with role "role1";
+  FrameworkInfo frameworkInfo;
+  frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.set_role("role1");
+
+  // Setup ACLs in order to receive offers for "role1".
+  ACLs acls;
+  mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+  acl->mutable_principals()->add_values(frameworkInfo.principal());
+  acl->mutable_roles()->add_values(frameworkInfo.role());
+
+  // Start master with ACLs.
+  master::Flags masterFlags = CreateMasterFlags();
+  masterFlags.roles = frameworkInfo.role();
+  masterFlags.acls = acls;
+
+  Try<PID<Master>> master = StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  slave::Flags slaveFlags = CreateSlaveFlags();
+  slaveFlags.resources = "cpus(*):4;mem(*):2048;disk(role1):1024";
+
+  Try<PID<Slave>> slave = StartSlave(slaveFlags);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Create a persistent volume whose size is larger than the size of
+  // the offered disk.
+  Resource diskResource = Resources::parse("disk", "2048", "role1").get();
+  diskResource.mutable_disk()->CopyFrom(createDiskInfo("1", "1"));
+
+  // Include other resources in task resources.
+  Resources taskResources =
+    Resources::parse("cpus:1;mem:128").get() + diskResource;
+
+  Offer offer = offers.get()[0];
+  TaskInfo task =
+    createTask(offer.slave_id(), taskResources, "", DEFAULT_EXECUTOR_ID);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offer.id(), tasks);
+
+  AWAIT_READY(status);
+  EXPECT_EQ(task.task_id(), status.get().task_id());
+  EXPECT_EQ(TASK_ERROR, status.get().state());
+  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
+  EXPECT_TRUE(status.get().has_message());
+  EXPECT_TRUE(strings::contains(
+      status.get().message(), "Failed to create persistent volumes"));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+// TODO(jieyu): Add tests for checking duplicated persistence ID
+// against offered resources.
+
+// TODO(jieyu): Add tests for checking duplicated persistence ID
+// across task and executors.
+
+// TODO(jieyu): Add tests for checking duplicated persistence ID
+// within an executor.
+
+// TODO(benh): Add tests for checking correct slave IDs.
+
+// TODO(benh): Add tests for checking executor resource usage.
+
+// TODO(benh): Add tests which launch multiple tasks and check for
+// aggregate resource usage.
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/79d21398/src/tests/resource_offers_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/resource_offers_tests.cpp b/src/tests/resource_offers_tests.cpp
index d1eb2fc..882a9ff 100644
--- a/src/tests/resource_offers_tests.cpp
+++ b/src/tests/resource_offers_tests.cpp
@@ -16,15 +16,14 @@
  * limitations under the License.
  */
 
-#include <gmock/gmock.h>
-
 #include <vector>
 
+#include <gmock/gmock.h>
+
 #include <mesos/executor.hpp>
 #include <mesos/scheduler.hpp>
 
 #include <stout/strings.hpp>
-#include <stout/uuid.hpp>
 
 #include "master/master.hpp"
 
@@ -44,613 +43,12 @@ using process::PID;
 using std::vector;
 
 using testing::_;
-using testing::AtMost;
-using testing::Return;
 
 namespace mesos {
 namespace internal {
 namespace tests {
 
 
-// TODO(jieyu): All of the task validation tests have the same flow:
-// launch a task, expect an update of a particular format (invalid w/
-// message). Consider providing common functionalities in the test
-// fixture to avoid code bloat. Ultimately, we should make task or
-// offer validation unit testable.
-class TaskValidationTest : public MesosTest {};
-
-
-TEST_F(TaskValidationTest, TaskUsesInvalidFrameworkID)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  Try<PID<Slave>> slave = StartSlave();
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _));
-
-  // Create an executor with a random framework id.
-  ExecutorInfo executor;
-  executor = DEFAULT_EXECUTOR_INFO;
-  executor.mutable_framework_id()->set_value(UUID::random().toString());
-
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(LaunchTasks(executor, 1, 1, 16, "*"))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.start();
-
-  AWAIT_READY(status);
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_TRUE(strings::startsWith(
-      status.get().message(), "ExecutorInfo has an invalid FrameworkID"));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-TEST_F(TaskValidationTest, TaskUsesCommandInfoAndExecutorInfo)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  Try<PID<Slave>> slave = StartSlave();
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _));
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  // Create a task that uses both command info and task info.
-  TaskInfo task = createTask(offers.get()[0], ""); // Command task.
-  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO); // Executor task.
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task);
-
-  driver.launchTasks(offers.get()[0].id(), tasks);
-
-  AWAIT_READY(status);
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_TRUE(strings::contains(
-      status.get().message(), "CommandInfo or ExecutorInfo present"));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-TEST_F(TaskValidationTest, TaskUsesNoResources)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  Try<PID<Slave>> slave = StartSlave();
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .Times(1);
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  TaskInfo task;
-  task.set_name("");
-  task.mutable_task_id()->set_value("1");
-  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task);
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), tasks);
-
-  AWAIT_READY(status);
-  EXPECT_EQ(task.task_id(), status.get().task_id());
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-  EXPECT_TRUE(status.get().has_message());
-  EXPECT_EQ("Task uses no resources", status.get().message());
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-TEST_F(TaskValidationTest, TaskUsesMoreResourcesThanOffered)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  Try<PID<Slave>> slave = StartSlave();
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .Times(1);
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  TaskInfo task;
-  task.set_name("");
-  task.mutable_task_id()->set_value("1");
-  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
-
-  Resource* cpus = task.add_resources();
-  cpus->set_name("cpus");
-  cpus->set_type(Value::SCALAR);
-  cpus->mutable_scalar()->set_value(2.01);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task);
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), tasks);
-
-  AWAIT_READY(status);
-
-  EXPECT_EQ(task.task_id(), status.get().task_id());
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-  EXPECT_TRUE(status.get().has_message());
-  EXPECT_TRUE(strings::contains(
-      status.get().message(), "Task uses more resources"));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-// This test verifies that if two tasks are launched with the same
-// task ID, the second task will get rejected.
-TEST_F(TaskValidationTest, DuplicatedTaskID)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  MockExecutor exec(DEFAULT_EXECUTOR_ID);
-
-  Try<PID<Slave>> slave = StartSlave(&exec);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _));
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  ExecutorInfo executor;
-  executor.mutable_executor_id()->set_value("default");
-  executor.mutable_command()->set_value("exit 1");
-
-  // Create two tasks with the same id.
-  TaskInfo task1;
-  task1.set_name("");
-  task1.mutable_task_id()->set_value("1");
-  task1.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task1.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:32").get());
-  task1.mutable_executor()->MergeFrom(executor);
-
-  TaskInfo task2;
-  task2.set_name("");
-  task2.mutable_task_id()->set_value("1");
-  task2.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task2.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:32").get());
-  task2.mutable_executor()->MergeFrom(executor);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task1);
-  tasks.push_back(task2);
-
-  EXPECT_CALL(exec, registered(_, _, _, _));
-
-  // Grab the first task but don't send a status update.
-  Future<TaskInfo> task;
-  EXPECT_CALL(exec, launchTask(_, _))
-    .WillOnce(FutureArg<1>(&task));
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), tasks);
-
-  AWAIT_READY(task);
-  EXPECT_EQ(task1.task_id(), task.get().task_id());
-
-  AWAIT_READY(status);
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-
-  EXPECT_TRUE(strings::startsWith(
-      status.get().message(), "Task has duplicate ID"));
-
-  EXPECT_CALL(exec, shutdown(_))
-    .Times(AtMost(1));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-// This test verifies that two tasks launched on the same slave with
-// the same executor id but different executor info are rejected.
-TEST_F(TaskValidationTest, ExecutorInfoDiffersOnSameSlave)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  MockExecutor exec(DEFAULT_EXECUTOR_ID);
-
-  Try<PID<Slave>> slave = StartSlave(&exec);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .Times(1);
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  ExecutorInfo executor;
-  executor.mutable_executor_id()->set_value("default");
-  executor.mutable_command()->set_value("exit 1");
-
-  TaskInfo task1;
-  task1.set_name("");
-  task1.mutable_task_id()->set_value("1");
-  task1.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task1.mutable_resources()->MergeFrom(
-      Resources::parse("cpus:1;mem:512").get());
-  task1.mutable_executor()->MergeFrom(executor);
-
-  executor.mutable_command()->set_value("exit 2");
-
-  TaskInfo task2;
-  task2.set_name("");
-  task2.mutable_task_id()->set_value("2");
-  task2.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task2.mutable_resources()->MergeFrom(
-      Resources::parse("cpus:1;mem:512").get());
-  task2.mutable_executor()->MergeFrom(executor);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task1);
-  tasks.push_back(task2);
-
-  EXPECT_CALL(exec, registered(_, _, _, _))
-    .Times(1);
-
-  // Grab the "good" task but don't send a status update.
-  Future<TaskInfo> task;
-  EXPECT_CALL(exec, launchTask(_, _))
-    .WillOnce(FutureArg<1>(&task));
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), tasks);
-
-  AWAIT_READY(task);
-  EXPECT_EQ(task1.task_id(), task.get().task_id());
-
-  AWAIT_READY(status);
-  EXPECT_EQ(task2.task_id(), status.get().task_id());
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-  EXPECT_TRUE(status.get().has_message());
-  EXPECT_TRUE(strings::contains(
-      status.get().message(), "Task has invalid ExecutorInfo"));
-
-  EXPECT_CALL(exec, shutdown(_))
-    .Times(AtMost(1));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-// This test verifies that two tasks each launched on a different
-// slave with same executor id but different executor info are
-// allowed.
-TEST_F(TaskValidationTest, ExecutorInfoDiffersOnDifferentSlaves)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  Future<Nothing> registered;
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .WillOnce(FutureSatisfy(&registered));
-
-  driver.start();
-
-  AWAIT_READY(registered);
-
-  Future<vector<Offer>> offers1;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers1));
-
-  // Start the first slave.
-  MockExecutor exec1(DEFAULT_EXECUTOR_ID);
-
-  Try<PID<Slave>> slave1 = StartSlave(&exec1);
-  ASSERT_SOME(slave1);
-
-  AWAIT_READY(offers1);
-  EXPECT_NE(0u, offers1.get().size());
-
-  // Launch the first task with the default executor id.
-  ExecutorInfo executor1;
-  executor1 = DEFAULT_EXECUTOR_INFO;
-  executor1.mutable_command()->set_value("exit 1");
-
-  TaskInfo task1 = createTask(
-      offers1.get()[0], executor1.command().value(), executor1.executor_id());
-
-  vector<TaskInfo> tasks1;
-  tasks1.push_back(task1);
-
-  EXPECT_CALL(exec1, registered(_, _, _, _))
-    .Times(1);
-
-  EXPECT_CALL(exec1, launchTask(_, _))
-    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
-
-  Future<TaskStatus> status1;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status1));
-
-  driver.launchTasks(offers1.get()[0].id(), tasks1);
-
-  AWAIT_READY(status1);
-  ASSERT_EQ(TASK_RUNNING, status1.get().state());
-
-  Future<vector<Offer>> offers2;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers2))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  // Now start the second slave.
-  MockExecutor exec2(DEFAULT_EXECUTOR_ID);
-
-  Try<PID<Slave>> slave2 = StartSlave(&exec2);
-  ASSERT_SOME(slave2);
-
-  AWAIT_READY(offers2);
-  EXPECT_NE(0u, offers2.get().size());
-
-  // Now launch the second task with the same executor id but
-  // a different executor command.
-  ExecutorInfo executor2;
-  executor2 = executor1;
-  executor2.mutable_command()->set_value("exit 2");
-
-  TaskInfo task2 = createTask(
-      offers2.get()[0], executor2.command().value(), executor2.executor_id());
-
-  vector<TaskInfo> tasks2;
-  tasks2.push_back(task2);
-
-  EXPECT_CALL(exec2, registered(_, _, _, _))
-    .Times(1);
-
-  EXPECT_CALL(exec2, launchTask(_, _))
-    .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
-
-  Future<TaskStatus> status2;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status2));
-
-  driver.launchTasks(offers2.get()[0].id(), tasks2);
-
-  AWAIT_READY(status2);
-  ASSERT_EQ(TASK_RUNNING, status2.get().state());
-
-  EXPECT_CALL(exec1, shutdown(_))
-    .Times(AtMost(1));
-
-  EXPECT_CALL(exec2, shutdown(_))
-    .Times(AtMost(1));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-// This test ensures that a persistent volume that is larger than the
-// offered disk resources results in a failed task.
-TEST_F(TaskValidationTest, DISABLED_AcquirePersistentDiskTooBig)
-{
-  // Create a framework with role "role1";
-  FrameworkInfo frameworkInfo;
-  frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_role("role1");
-
-  // Setup ACLs in order to receive offers for "role1".
-  ACLs acls;
-  mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
-  acl->mutable_principals()->add_values(frameworkInfo.principal());
-  acl->mutable_roles()->add_values(frameworkInfo.role());
-
-  // Start master with ACLs.
-  master::Flags masterFlags = CreateMasterFlags();
-  masterFlags.roles = frameworkInfo.role();
-  masterFlags.acls = acls;
-
-  Try<PID<Master>> master = StartMaster(masterFlags);
-  ASSERT_SOME(master);
-
-  slave::Flags slaveFlags = CreateSlaveFlags();
-  slaveFlags.resources = "cpus(*):4;mem(*):2048;disk(role1):1024";
-
-  Try<PID<Slave>> slave = StartSlave(slaveFlags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(&driver, _, _))
-    .Times(1);
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return()); // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  // Create a persistent volume whose size is larger than the size of
-  // the offered disk.
-  Resource diskResource = Resources::parse("disk", "2048", "role1").get();
-  diskResource.mutable_disk()->CopyFrom(createDiskInfo("1", "1"));
-
-  // Include other resources in task resources.
-  Resources taskResources =
-    Resources::parse("cpus:1;mem:128").get() + diskResource;
-
-  Offer offer = offers.get()[0];
-  TaskInfo task =
-    createTask(offer.slave_id(), taskResources, "", DEFAULT_EXECUTOR_ID);
-
-  vector<TaskInfo> tasks;
-  tasks.push_back(task);
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offer.id(), tasks);
-
-  AWAIT_READY(status);
-  EXPECT_EQ(task.task_id(), status.get().task_id());
-  EXPECT_EQ(TASK_ERROR, status.get().state());
-  EXPECT_EQ(TaskStatus::REASON_TASK_INVALID, status.get().reason());
-  EXPECT_TRUE(status.get().has_message());
-  EXPECT_TRUE(strings::contains(
-      status.get().message(), "Failed to create persistent volumes"));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-// TODO(jieyu): Add tests for checking duplicated persistence ID
-// against offered resources.
-
-// TODO(jieyu): Add tests for checking duplicated persistence ID
-// across task and executors.
-
-// TODO(jieyu): Add tests for checking duplicated persistence ID
-// within an executor.
-
-// TODO(benh): Add tests for checking correct slave IDs.
-
-// TODO(benh): Add tests for checking executor resource usage.
-
-// TODO(benh): Add tests which launch multiple tasks and check for
-// aggregate resource usage.
-
-
 class ResourceOffersTest : public MesosTest {};