Added test case `MasterAPITest.CreateAndDetroyVolumes`.

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


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

Branch: refs/heads/master
Commit: 589d5b260a17969889430fc84728c2a4455be552
Parents: 1c7ff6e
Author: Shuai Lin <linshuai2...@gmail.com>
Authored: Wed Jun 22 14:18:12 2016 -0700
Committer: Vinod Kone <vinodk...@gmail.com>
Committed: Wed Jun 22 14:18:12 2016 -0700

----------------------------------------------------------------------
 src/internal/evolve.cpp |   6 ++
 src/internal/evolve.hpp |   1 +
 src/tests/api_tests.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/internal/evolve.cpp
----------------------------------------------------------------------
diff --git a/src/internal/evolve.cpp b/src/internal/evolve.cpp
index 6b1cf3c..f63d606 100644
--- a/src/internal/evolve.cpp
+++ b/src/internal/evolve.cpp
@@ -162,6 +162,12 @@ v1::MasterInfo evolve(const MasterInfo& masterInfo)
 }
 
 
+v1::Resource evolve(const Resource& resource)
+{
+  return evolve<v1::Resource>(resource);
+}
+
+
 v1::agent::Response evolve(const mesos::agent::Response& response)
 {
   return evolve<v1::agent::Response>(response);

http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/internal/evolve.hpp
----------------------------------------------------------------------
diff --git a/src/internal/evolve.hpp b/src/internal/evolve.hpp
index 321e0cc..a8648f5 100644
--- a/src/internal/evolve.hpp
+++ b/src/internal/evolve.hpp
@@ -69,6 +69,7 @@ v1::TaskInfo evolve(const TaskInfo& taskInfo);
 v1::TaskStatus evolve(const TaskStatus& status);
 v1::Task evolve(const Task& task);
 v1::MasterInfo evolve(const MasterInfo& masterInfo);
+v1::Resource evolve(const Resource& resource);
 
 v1::agent::Response evolve(const mesos::agent::Response& response);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index bf1a294..7f16f43 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -63,6 +63,7 @@ using process::Failure;
 using process::Future;
 using process::Owned;
 
+using process::http::Accepted;
 using process::http::OK;
 using process::http::Pipe;
 using process::http::Response;
@@ -938,6 +939,155 @@ TEST_P(MasterAPITest, SetQuota)
   AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
 }
 
+// Test create and destroy persistent volumes through the master operator API.
+// In this test case, we create a persistent volume with the API, then launch a
+// task using the volume. Then we destroy the volume with the API after the 
task
+// is finished.
+TEST_P(MasterAPITest, CreateAndDestroyVolumes)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  // For capturing the SlaveID so we can use it in the create/destroy volumes
+  // API call.
+  Future<SlaveRegisteredMessage> slaveRegisteredMessage =
+    FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
+
+  MockExecutor exec(DEFAULT_EXECUTOR_ID);
+  TestContainerizer containerizer(&exec);
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  slave::Flags slaveFlags = CreateSlaveFlags();
+  // Do Static reservation so we can create persistent volumes from it.
+  slaveFlags.resources = "disk(role1):1024";
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(), &containerizer, slaveFlags);
+
+  ASSERT_SOME(slave);
+
+  AWAIT_READY(slaveRegisteredMessage);
+  SlaveID slaveId = slaveRegisteredMessage.get().slave_id();
+
+  // Create the persistent volume.
+  v1::master::Call v1CreateVolumesCall;
+  v1CreateVolumesCall.set_type(v1::master::Call::CREATE_VOLUMES);
+  v1::master::Call_CreateVolumes* createVolumes =
+    v1CreateVolumesCall.mutable_create_volumes();
+
+  Resource volume = createPersistentVolume(
+      Megabytes(64),
+      "role1",
+      "id1",
+      "path1",
+      None(),
+      None(),
+      DEFAULT_CREDENTIAL.principal());
+
+  createVolumes->add_volumes()->CopyFrom(evolve<v1::Resource>(volume));
+  createVolumes->mutable_agent_id()->CopyFrom(evolve<v1::AgentID>(slaveId));
+
+  ContentType contentType = GetParam();
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
+  headers["Accept"] = stringify(contentType);
+
+  Future<Nothing> v1CreateVolumesResponse = process::http::post(
+      master.get()->pid,
+      "api/v1",
+      headers,
+      serialize(contentType, v1CreateVolumesCall),
+      stringify(contentType))
+    .then([contentType](const Response& response) -> Future<Nothing> {
+      if (response.status != Accepted().status) {
+        return Failure("Unexpected response status " + response.status);
+      }
+      return Nothing();
+    });
+
+  AWAIT_READY(v1CreateVolumesResponse);
+
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.set_role("role1");
+
+  // Start a framework and launch a task on the persistent volume.
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get()->pid, 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());
+  Offer offer = offers.get()[0];
+
+  EXPECT_TRUE(Resources(offer.resources()).contains(volume));
+
+  Resources taskResources = Resources::parse(
+      "disk:256",
+      frameworkInfo.role()).get();
+
+  TaskInfo taskInfo = createTask(
+      offer.slave_id(),
+      taskResources,
+      "sleep 1",
+      DEFAULT_EXECUTOR_ID);
+
+  EXPECT_CALL(exec, registered(_, _, _, _))
+    .Times(1);
+
+  EXPECT_CALL(exec, launchTask(_, _))
+    .WillOnce(SendStatusUpdateFromTask(TASK_FINISHED));
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.acceptOffers({offer.id()}, {LAUNCH({taskInfo})});
+
+  AWAIT_READY(status);
+  EXPECT_EQ(TASK_FINISHED, status.get().state());
+
+  // Destroy the persistent volume.
+  v1::master::Call v1DestroyVolumesCall;
+  v1DestroyVolumesCall.set_type(v1::master::Call::DESTROY_VOLUMES);
+  v1::master::Call_DestroyVolumes* destroyVolumes =
+    v1DestroyVolumesCall.mutable_destroy_volumes();
+
+  destroyVolumes->mutable_agent_id()->CopyFrom(evolve<v1::AgentID>(slaveId));
+  destroyVolumes->add_volumes()->CopyFrom(evolve<v1::Resource>(volume));
+
+  Future<Nothing> v1DestroyVolumesResponse = process::http::post(
+      master.get()->pid,
+      "api/v1",
+      headers,
+      serialize(contentType, v1DestroyVolumesCall),
+      stringify(contentType))
+    .then([contentType](const Response& response) -> Future<Nothing> {
+      if (response.status != Accepted().status) {
+        return Failure("Unexpected response status " + response.status);
+      }
+      return Nothing();
+    });
+
+  AWAIT_READY(v1DestroyVolumesResponse);
+
+  EXPECT_CALL(exec, shutdown(_))
+    .Times(AtMost(1));
+
+  driver.stop();
+  driver.join();
+}
+
 
 TEST_P(MasterAPITest, GetWeights)
 {

Reply via email to