You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by me...@apache.org on 2015/12/19 10:21:04 UTC
[2/5] mesos git commit: Added test cases for implicit roles.
Added test cases for implicit roles.
Review: https://reviews.apache.org/r/41225/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ff4f8ca9
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ff4f8ca9
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ff4f8ca9
Branch: refs/heads/master
Commit: ff4f8ca9b3e8a0938bb4b167329d3612b13067b3
Parents: f81adfa
Author: Neil Conway <ne...@gmail.com>
Authored: Fri Dec 18 15:35:00 2015 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Fri Dec 18 23:35:56 2015 -0800
----------------------------------------------------------------------
src/tests/role_tests.cpp | 428 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 414 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/ff4f8ca9/src/tests/role_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/role_tests.cpp b/src/tests/role_tests.cpp
index 240017c..2c5f68c 100644
--- a/src/tests/role_tests.cpp
+++ b/src/tests/role_tests.cpp
@@ -14,6 +14,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <string>
+#include <vector>
+
+#include <mesos/http.hpp>
+
#include <process/pid.hpp>
#include "tests/mesos.hpp"
@@ -21,10 +26,16 @@
using mesos::internal::master::Master;
using mesos::internal::slave::Slave;
+using std::string;
+using std::vector;
+
+using google::protobuf::RepeatedPtrField;
+
using process::Future;
using process::PID;
-using std::vector;
+using process::http::OK;
+using process::http::Response;
namespace mesos {
namespace internal {
@@ -66,6 +77,178 @@ TEST_F(RoleTest, BadRegister)
}
+// This test checks that when using implicit roles, a framework can
+// register with a new role, make a dynamic reservation, and create a
+// persistent volume.
+TEST_F(RoleTest, ImplicitRoleRegister)
+{
+ master::Flags masterFlags = CreateMasterFlags();
+ masterFlags.allocation_interval = Milliseconds(50);
+
+ Try<PID<Master>> master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ slave::Flags slaveFlags = CreateSlaveFlags();
+ slaveFlags.resources = "cpus:1;mem:512;disk:1024";
+
+ Try<PID<Slave>> slave = StartSlave(slaveFlags);
+ ASSERT_SOME(slave);
+
+ FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo.set_role("new-role-name");
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+ // We use the filter explicitly here so that the resources will not
+ // be filtered for 5 seconds (by default).
+ Filters filters;
+ filters.set_refuse_seconds(0);
+
+ Resources unreserved = Resources::parse("disk:1024").get();
+ Resources dynamicallyReserved = unreserved.flatten(
+ frameworkInfo.role(), createReservationInfo(frameworkInfo.principal()));
+
+ // We use this to capture offers from `resourceOffers`.
+ Future<vector<Offer>> offers;
+
+ EXPECT_CALL(sched, registered(&driver, _, _));
+
+ // The expectation for the first offer.
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers));
+
+ driver.start();
+
+ // In the first offer, expect an offer with unreserved resources.
+ AWAIT_READY(offers);
+
+ ASSERT_EQ(1u, offers.get().size());
+ Offer offer = offers.get()[0];
+
+ EXPECT_TRUE(Resources(offer.resources()).contains(unreserved));
+ EXPECT_FALSE(Resources(offer.resources()).contains(dynamicallyReserved));
+
+ // The expectation for the next offer.
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers));
+
+ // Reserve the resources.
+ driver.acceptOffers({offer.id()}, {RESERVE(dynamicallyReserved)}, filters);
+
+ // In the next offer, expect an offer with reserved resources.
+ AWAIT_READY(offers);
+
+ ASSERT_EQ(1u, offers.get().size());
+ offer = offers.get()[0];
+
+ EXPECT_TRUE(Resources(offer.resources()).contains(dynamicallyReserved));
+ EXPECT_FALSE(Resources(offer.resources()).contains(unreserved));
+
+ Resources volume = createPersistentVolume(
+ Megabytes(64),
+ frameworkInfo.role(),
+ "id1",
+ "path1",
+ frameworkInfo.principal());
+
+ // The expectation for the next offer.
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers));
+
+ driver.acceptOffers({offer.id()}, {CREATE(volume)}, filters);
+
+ // In the next offer, expect an offer with a persistent volume.
+ AWAIT_READY(offers);
+
+ ASSERT_EQ(1u, offers.get().size());
+ offer = offers.get()[0];
+
+ EXPECT_TRUE(Resources(offer.resources()).contains(volume));
+ EXPECT_FALSE(Resources(offer.resources()).contains(dynamicallyReserved));
+ EXPECT_FALSE(Resources(offer.resources()).contains(unreserved));
+
+ driver.stop();
+ driver.join();
+
+ Shutdown();
+}
+
+
+// This test checks that when using implicit roles, a static
+// reservation for a new role can be made and used to launch a task.
+TEST_F(RoleTest, ImplicitRoleStaticReservation)
+{
+ master::Flags masterFlags = CreateMasterFlags();
+ masterFlags.allocation_interval = Milliseconds(50);
+
+ Try<PID<Master>> master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ MockExecutor exec(DEFAULT_EXECUTOR_ID);
+
+ slave::Flags slaveFlags = CreateSlaveFlags();
+ slaveFlags.resources = "cpus(role):1;mem(role):512";
+
+ Try<PID<Slave>> slave = StartSlave(&exec, slaveFlags);
+ ASSERT_SOME(slave);
+
+ FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo.set_role("role");
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+ // We use the filter explicitly here so that the resources will not
+ // be filtered for 5 seconds (by default).
+ Filters filters;
+ filters.set_refuse_seconds(0);
+
+ Resources staticallyReserved =
+ Resources::parse(slaveFlags.resources.get()).get();
+
+ // We use this to capture offers from `resourceOffers`.
+ Future<vector<Offer>> offers;
+
+ EXPECT_CALL(sched, registered(&driver, _, _));
+
+ // The expectation for the first offer.
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers));
+
+ driver.start();
+
+ AWAIT_READY(offers);
+
+ ASSERT_EQ(1u, offers.get().size());
+ Offer offer = offers.get()[0];
+
+ EXPECT_TRUE(Resources(offer.resources()).contains(staticallyReserved));
+
+ // Create a task to launch with the resources of `staticallyReserved`.
+ TaskInfo taskInfo =
+ createTask(offer.slave_id(), staticallyReserved, "exit 1", exec.id);
+
+ EXPECT_CALL(exec, registered(_, _, _, _));
+
+ Future<TaskInfo> launchTask;
+
+ EXPECT_CALL(exec, launchTask(_, _))
+ .WillOnce(FutureArg<1>(&launchTask));
+
+ driver.acceptOffers({offer.id()}, {LAUNCH({taskInfo})}, filters);
+
+ AWAIT_READY(launchTask);
+
+ driver.stop();
+ driver.join();
+
+ Shutdown();
+}
+
+
// This test checks that the "/roles" endpoint returns the expected
// information when there are no active roles.
TEST_F(RoleTest, EndpointEmpty)
@@ -73,14 +256,12 @@ TEST_F(RoleTest, EndpointEmpty)
Try<PID<Master>> master = StartMaster();
ASSERT_SOME(master);
- Future<process::http::Response> response =
- process::http::get(master.get(), "roles");
+ Future<Response> response = process::http::get(master.get(), "roles");
- AWAIT_READY(response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response)
+ << response.get().body;
- EXPECT_SOME_EQ(
- "application/json",
- response.get().headers.get("Content-Type"));
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
Try<JSON::Value> parse = JSON::parse(response.get().body);
ASSERT_SOME(parse);
@@ -110,7 +291,7 @@ TEST_F(RoleTest, EndpointEmpty)
// This test checks that the "/roles" endpoint returns the expected
// information when there are configured weights and explicit roles,
-// but no active frameworks.
+// but no registered frameworks.
TEST_F(RoleTest, EndpointNoFrameworks)
{
master::Flags masterFlags = CreateMasterFlags();
@@ -120,14 +301,12 @@ TEST_F(RoleTest, EndpointNoFrameworks)
Try<PID<Master>> master = StartMaster(masterFlags);
ASSERT_SOME(master);
- Future<process::http::Response> response =
- process::http::get(master.get(), "roles");
+ Future<Response> response = process::http::get(master.get(), "roles");
- AWAIT_READY(response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response)
+ << response.get().body;
- EXPECT_SOME_EQ(
- "application/json",
- response.get().headers.get("Content-Type"));
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
Try<JSON::Value> parse = JSON::parse(response.get().body);
ASSERT_SOME(parse);
@@ -175,6 +354,227 @@ TEST_F(RoleTest, EndpointNoFrameworks)
}
+// This test checks that when using implicit roles, the "/roles"
+// endpoint shows roles that have a configured weight even if they
+// have no registered frameworks.
+TEST_F(RoleTest, EndpointImplicitRolesWeights)
+{
+ master::Flags masterFlags = CreateMasterFlags();
+ masterFlags.weights = "roleX=5,roleY=4";
+
+ Try<PID<Master>> master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ FrameworkInfo frameworkInfo1 = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo1.set_role("roleX");
+
+ MockScheduler sched1;
+ MesosSchedulerDriver driver1(
+ &sched1, frameworkInfo1, master.get(), DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId1;
+ EXPECT_CALL(sched1, registered(&driver1, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId1));;
+
+ driver1.start();
+
+ FrameworkInfo frameworkInfo2 = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo2.set_role("roleZ");
+
+ MockScheduler sched2;
+ MesosSchedulerDriver driver2(
+ &sched2, frameworkInfo2, master.get(), DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId2;
+ EXPECT_CALL(sched2, registered(&driver2, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId2));;
+
+ driver2.start();
+
+ AWAIT_READY(frameworkId1);
+ AWAIT_READY(frameworkId2);
+
+ Future<Response> response = process::http::get(master.get(), "roles");
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response)
+ << response.get().body;
+
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+
+ Try<JSON::Value> parse = JSON::parse(response.get().body);
+ ASSERT_SOME(parse);
+
+ Try<JSON::Value> expected = JSON::parse(
+ "{"
+ " \"roles\": ["
+ " {"
+ " \"frameworks\": [],"
+ " \"name\": \"*\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 1.0"
+ " },"
+ " {"
+ " \"frameworks\": [\"" + frameworkId1.get().value() + "\"],"
+ " \"name\": \"roleX\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 5.0"
+ " },"
+ " {"
+ " \"frameworks\": [],"
+ " \"name\": \"roleY\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 4.0"
+ " },"
+ " {"
+ " \"frameworks\": [\"" + frameworkId2.get().value() + "\"],"
+ " \"name\": \"roleZ\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 1.0"
+ " }"
+ " ]"
+ "}");
+
+ ASSERT_SOME(expected);
+ EXPECT_EQ(expected.get(), parse.get());
+
+ driver1.stop();
+ driver1.join();
+
+ driver2.stop();
+ driver2.join();
+
+ Shutdown();
+}
+
+
+// This test checks that when using implicit roles, the "/roles"
+// endpoint shows roles that have a configured quota even if they have
+// no registered frameworks.
+TEST_F(RoleTest, EndpointImplicitRolesQuotas)
+{
+ Try<PID<Master>> master = StartMaster();
+ ASSERT_SOME(master);
+
+ Resources quotaResources =
+ Resources::parse("cpus:1;mem:512", "non-existent-role").get();
+ const RepeatedPtrField<Resource>& jsonQuotaResources =
+ static_cast<const RepeatedPtrField<Resource>&>(quotaResources);
+
+ // Send a quota request for a new role name. Note that we set
+ // "force" to true because we're setting a quota that can't
+ // currently be satisfied by the resources in the cluster (because
+ // there are no slaves registered).
+ string quotaRequestBody = strings::format(
+ "resources=%s&force=true", JSON::protobuf(jsonQuotaResources)).get();
+
+ Future<Response> quotaResponse = process::http::post(
+ master.get(),
+ "quota",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ quotaRequestBody);
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, quotaResponse)
+ << quotaResponse.get().body;
+
+ Future<Response> rolesResponse = process::http::get(master.get(), "roles");
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, rolesResponse)
+ << rolesResponse.get().body;
+
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(
+ APPLICATION_JSON, "Content-Type", rolesResponse);
+
+ Try<JSON::Value> parse = JSON::parse(rolesResponse.get().body);
+ ASSERT_SOME(parse);
+
+ Try<JSON::Value> expected = JSON::parse(
+ "{"
+ " \"roles\": ["
+ " {"
+ " \"frameworks\": [],"
+ " \"name\": \"*\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 1.0"
+ " },"
+ " {"
+ " \"frameworks\": [],"
+ " \"name\": \"non-existent-role\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 1.0"
+ " }"
+ " ]"
+ "}");
+
+ ASSERT_SOME(expected);
+ EXPECT_EQ(expected.get(), parse.get());
+
+ // Remove the quota, and check that the role no longer appears in
+ // the "/roles" endpoint.
+ Future<Response> deleteResponse = process::http::requestDelete(
+ master.get(),
+ "quota/non-existent-role",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, deleteResponse)
+ << deleteResponse.get().body;
+
+ rolesResponse = process::http::get(master.get(), "roles");
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, rolesResponse)
+ << rolesResponse.get().body;
+
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(
+ APPLICATION_JSON, "Content-Type", rolesResponse);
+
+ parse = JSON::parse(rolesResponse.get().body);
+ ASSERT_SOME(parse);
+
+ expected = JSON::parse(
+ "{"
+ " \"roles\": ["
+ " {"
+ " \"frameworks\": [],"
+ " \"name\": \"*\","
+ " \"resources\": {"
+ " \"cpus\": 0,"
+ " \"disk\": 0,"
+ " \"mem\": 0"
+ " },"
+ " \"weight\": 1.0"
+ " }"
+ " ]"
+ "}");
+
+ ASSERT_SOME(expected);
+ EXPECT_EQ(expected.get(), parse.get());
+
+ Shutdown();
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {