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(®istered));
+
+ 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(®istered));
-
- 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 {};