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:38 UTC

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

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 {};