Improved testing around state.json endpoints. Review: https://reviews.apache.org/r/32463
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/99cd79ce Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/99cd79ce Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/99cd79ce Branch: refs/heads/master Commit: 99cd79ce5d3014ce8e6ed258322f5b922c62e07b Parents: a5a2833 Author: Benjamin Mahler <[email protected]> Authored: Tue Mar 24 16:08:09 2015 -0700 Committer: Benjamin Mahler <[email protected]> Committed: Thu Apr 9 12:26:36 2015 -0700 ---------------------------------------------------------------------- src/tests/master_tests.cpp | 126 ++++++++++++++++++++++++++++++++-------- src/tests/slave_tests.cpp | 78 ++++++++++++++++++++----- 2 files changed, 166 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/99cd79ce/src/tests/master_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp index 2bfd0f8..32b1e9b 100644 --- a/src/tests/master_tests.cpp +++ b/src/tests/master_tests.cpp @@ -30,7 +30,6 @@ #include <process/future.hpp> #include <process/gmock.hpp> #include <process/http.hpp> -#include <process/owned.hpp> #include <process/pid.hpp> #include <process/metrics/counter.hpp> @@ -44,6 +43,8 @@ #include <stout/strings.hpp> #include <stout/try.hpp> +#include "common/build.hpp" + #include "master/flags.hpp" #include "master/master.hpp" @@ -74,10 +75,8 @@ using mesos::internal::slave::MesosContainerizerProcess; using process::Clock; using process::Future; -using process::Owned; using process::PID; using process::Promise; -using process::UPID; using std::string; using std::vector; @@ -94,6 +93,8 @@ namespace mesos { namespace internal { namespace tests { +namespace http = process::http; + // Those of the overall Mesos master/slave/scheduler/driver tests // that seem vaguely more master than slave-related are in this file. // The others are in "slave_tests.cpp". @@ -271,8 +272,7 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning) Clock::resume(); // Request master state. - Future<process::http::Response> response = - process::http::get(master.get(), "state.json"); + Future<http::Response> response = http::get(master.get(), "state.json"); AWAIT_READY(response); // These checks are not essential for the test, but may help @@ -1596,8 +1596,7 @@ TEST_F(MasterTest, SlavesEndpointWithoutSlaves) ASSERT_SOME(master); // Query the master. - const Future<process::http::Response> response = - process::http::get(master.get(), "slaves"); + Future<http::Response> response = http::get(master.get(), "slaves"); AWAIT_READY(response); @@ -1645,8 +1644,7 @@ TEST_F(MasterTest, SlavesEndpointTwoSlaves) AWAIT_READY(slave2RegisteredMessage); // Query the master. - const Future<process::http::Response> response = - process::http::get(master.get(), "slaves"); + Future<http::Response> response = http::get(master.get(), "slaves"); AWAIT_READY(response); @@ -2192,8 +2190,7 @@ TEST_F(MasterTest, OrphanTasks) EXPECT_EQ(TASK_RUNNING, status.get().state()); // Get the master's state. - Future<process::http::Response> response = - process::http::get(master.get(), "state.json"); + Future<http::Response> response = http::get(master.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ( @@ -2258,7 +2255,7 @@ TEST_F(MasterTest, OrphanTasks) AWAIT_READY(reregisterFrameworkMessage); // Get the master's state. - response = process::http::get(master.get(), "state.json"); + response = http::get(master.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ( @@ -2290,7 +2287,7 @@ TEST_F(MasterTest, OrphanTasks) AWAIT_READY(frameworkRegisteredMessage); // Get the master's state. - response = process::http::get(master.get(), "state.json"); + response = http::get(master.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ( @@ -2743,6 +2740,93 @@ TEST_F(MasterTest, ReleaseResourcesForTerminalTaskWithPendingUpdates) } +TEST_F(MasterTest, StateEndpoint) +{ + master::Flags flags = CreateMasterFlags(); + + flags.hostname = "localhost"; + flags.cluster = "test-cluster"; + + // Capture the start time deterministically. + Clock::pause(); + + Try<PID<Master>> master = StartMaster(flags); + ASSERT_SOME(master); + + Future<http::Response> response = http::get(master.get(), "state.json"); + + AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); + + EXPECT_SOME_EQ( + "application/json", + response.get().headers.get("Content-Type")); + + Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); + ASSERT_SOME(parse); + + JSON::Object state = parse.get(); + + EXPECT_EQ(MESOS_VERSION, state.values["version"]); + + if (build::GIT_SHA.isSome()) { + EXPECT_EQ(build::GIT_SHA.get(), state.values["git_sha"]); + } + + if (build::GIT_BRANCH.isSome()) { + EXPECT_EQ(build::GIT_BRANCH.get(), state.values["git_branch"]); + } + + if (build::GIT_TAG.isSome()) { + EXPECT_EQ(build::GIT_TAG.get(), state.values["git_tag"]); + } + + EXPECT_EQ(build::DATE, state.values["build_date"]); + EXPECT_EQ(build::TIME, state.values["build_time"]); + EXPECT_EQ(build::USER, state.values["build_user"]); + + ASSERT_TRUE(state.values["start_time"].is<JSON::Number>()); + EXPECT_EQ( + static_cast<int>(Clock::now().secs()), + static_cast<int>(state.values["start_time"].as<JSON::Number>().value)); + + ASSERT_TRUE(state.values["id"].is<JSON::String>()); + EXPECT_NE("", state.values["id"].as<JSON::String>().value); + + EXPECT_EQ(stringify(master.get()), state.values["pid"]); + EXPECT_EQ(flags.hostname.get(), state.values["hostname"]); + + EXPECT_EQ(0, state.values["activated_slaves"]); + EXPECT_EQ(0, state.values["deactivated_slaves"]); + + EXPECT_EQ(flags.cluster.get(), state.values["cluster"]); + + // TODO(bmahler): Test "leader", "log_dir", "external_log_file". + + // TODO(bmahler): Ensure this contains all the flags. + ASSERT_TRUE(state.values["flags"].is<JSON::Object>()); + EXPECT_FALSE(state.values["flags"].as<JSON::Object>().values.empty()); + + ASSERT_TRUE(state.values["slaves"].is<JSON::Array>()); + EXPECT_TRUE(state.values["slaves"].as<JSON::Array>().values.empty()); + + ASSERT_TRUE(state.values["orphan_tasks"].is<JSON::Array>()); + EXPECT_TRUE(state.values["orphan_tasks"].as<JSON::Array>().values.empty()); + + ASSERT_TRUE(state.values["frameworks"].is<JSON::Array>()); + EXPECT_TRUE(state.values["frameworks"].as<JSON::Array>().values.empty()); + + ASSERT_TRUE( + state.values["completed_frameworks"].is<JSON::Array>()); + EXPECT_TRUE( + state.values["completed_frameworks"].as<JSON::Array>().values.empty()); + + ASSERT_TRUE( + state.values["unregistered_frameworks"].is<JSON::Array>()); + EXPECT_TRUE( + state.values["unregistered_frameworks"].as<JSON::Array>().values.empty()); +} + + // This test ensures that the web UI of a framework is included in the // state.json endpoint, if provided by the framework. TEST_F(MasterTest, FrameworkWebUIUrl) @@ -2765,9 +2849,8 @@ TEST_F(MasterTest, FrameworkWebUIUrl) AWAIT_READY(registered); - Future<process::http::Response> masterState = - process::http::get(master.get(), "state.json"); - AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, masterState); + Future<http::Response> masterState = http::get(master.get(), "state.json"); + AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, masterState); Try<JSON::Object> masterStateObject = JSON::parse<JSON::Object>(masterState.get().body); @@ -2876,8 +2959,7 @@ TEST_F(MasterTest, TaskLabels) AWAIT_READY(update); // Verify label key and value in master state.json. - Future<process::http::Response> response = - process::http::get(master.get(), "state.json"); + Future<http::Response> response = http::get(master.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ( @@ -2954,8 +3036,7 @@ TEST_F(MasterTest, SlaveActiveEndpoint) AWAIT_READY(slaveRegisteredMessage); // Verify slave is active. - Future<process::http::Response> response = - process::http::get(master.get(), "state.json"); + Future<http::Response> response = http::get(master.get(), "state.json"); AWAIT_READY(response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); @@ -2977,7 +3058,7 @@ TEST_F(MasterTest, SlaveActiveEndpoint) AWAIT_READY(deactivateSlave); // Verify slave is inactive. - response = process::http::get(master.get(), "state.json"); + response = http::get(master.get(), "state.json"); AWAIT_READY(response); parse = JSON::parse<JSON::Object>(response.get().body); @@ -3082,8 +3163,7 @@ TEST_F(MasterTest, TaskDiscoveryInfo) AWAIT_READY(update); // Verify label key and value in master state.json. - Future<process::http::Response> response = - process::http::get(master.get(), "state.json"); + Future<http::Response> response = http::get(master.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ( http://git-wip-us.apache.org/repos/asf/mesos/blob/99cd79ce/src/tests/slave_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp index fd09d65..29d23c6 100644 --- a/src/tests/slave_tests.cpp +++ b/src/tests/slave_tests.cpp @@ -31,8 +31,6 @@ #include <process/clock.hpp> #include <process/future.hpp> #include <process/gmock.hpp> -#include <process/io.hpp> -#include <process/owned.hpp> #include <process/pid.hpp> #include <process/subprocess.hpp> @@ -41,6 +39,7 @@ #include <stout/os.hpp> #include <stout/try.hpp> +#include "common/build.hpp" #include "common/http.hpp" #include "master/flags.hpp" @@ -64,10 +63,14 @@ using memory::shared_ptr; using namespace mesos::internal::slave; -using namespace process; - using mesos::internal::master::Master; +using process::Clock; +using process::Future; +using process::PID; +using process::Promise; +using process::UPID; + using std::map; using std::string; using std::vector; @@ -86,6 +89,8 @@ namespace mesos { namespace internal { namespace tests { +namespace http = process::http; + // Those of the overall Mesos master/slave/scheduler/driver tests // that seem vaguely more slave than master-related are in this file. // The others are in "master_tests.cpp". @@ -887,16 +892,19 @@ TEST_F(SlaveTest, StateEndpoint) slave::Flags flags = this->CreateSlaveFlags(); + flags.hostname = "localhost"; flags.resources = "cpus:4;mem:2048;disk:512;ports:[33000-34000]"; flags.attributes = "rack:abc;host:myhost"; + // Capture the start time deterministically. + Clock::pause(); + Try<PID<Slave> > slave = StartSlave(flags); ASSERT_SOME(slave); - Future<http::Response> response = - http::get(slave.get(), "state.json"); + Future<http::Response> response = http::get(slave.get(), "state.json"); - AWAIT_READY(response); + AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); EXPECT_SOME_EQ( "application/json", @@ -908,20 +916,61 @@ TEST_F(SlaveTest, StateEndpoint) JSON::Object state = parse.get(); - // Check if 'resources' matches. + EXPECT_EQ(MESOS_VERSION, state.values["version"]); + + if (build::GIT_SHA.isSome()) { + EXPECT_EQ(build::GIT_SHA.get(), state.values["git_sha"]); + } + + if (build::GIT_BRANCH.isSome()) { + EXPECT_EQ(build::GIT_BRANCH.get(), state.values["git_branch"]); + } + + if (build::GIT_TAG.isSome()) { + EXPECT_EQ(build::GIT_TAG.get(), state.values["git_tag"]); + } + + EXPECT_EQ(build::DATE, state.values["build_date"]); + EXPECT_EQ(build::TIME, state.values["build_time"]); + EXPECT_EQ(build::USER, state.values["build_user"]); + + ASSERT_TRUE(state.values["start_time"].is<JSON::Number>()); + EXPECT_EQ( + static_cast<int>(Clock::now().secs()), + static_cast<int>(state.values["start_time"].as<JSON::Number>().value)); + + // TODO(bmahler): The slave must register for the 'id' + // to be non-empty. + ASSERT_TRUE(state.values["id"].is<JSON::String>()); + + EXPECT_EQ(stringify(slave.get()), state.values["pid"]); + EXPECT_EQ(flags.hostname.get(), state.values["hostname"]); + Try<Resources> resources = Resources::parse( flags.resources.get(), flags.default_role); ASSERT_SOME(resources); - ASSERT_EQ(1u, state.values.count("resources")); - EXPECT_EQ(state.values["resources"], JSON::Value(model(resources.get()))); + EXPECT_EQ(model(resources.get()), state.values["resources"]); - // Check if 'attributes' matches. Attributes attributes = Attributes::parse(flags.attributes.get()); - ASSERT_EQ(1u, state.values.count("attributes")); - EXPECT_EQ(state.values["attributes"], JSON::Value(model(attributes))); + EXPECT_EQ(model(attributes), state.values["attributes"]); + + // TODO(bmahler): Test "master_hostname", "log_dir", + // "external_log_file". + + ASSERT_TRUE(state.values["frameworks"].is<JSON::Array>()); + EXPECT_TRUE(state.values["frameworks"].as<JSON::Array>().values.empty()); + + ASSERT_TRUE( + state.values["completed_frameworks"].is<JSON::Array>()); + EXPECT_TRUE( + state.values["completed_frameworks"].as<JSON::Array>().values.empty()); + + // TODO(bmahler): Ensure this contains all the flags. + ASSERT_TRUE(state.values["flags"].is<JSON::Object>()); + EXPECT_FALSE(state.values["flags"].as<JSON::Object>().values.empty()); Shutdown(); } @@ -1749,8 +1798,7 @@ TEST_F(SlaveTest, TaskLabels) AWAIT_READY(update); // Verify label key and value in slave state.json. - Future<http::Response> response = - http::get(slave.get(), "state.json"); + Future<http::Response> response = http::get(slave.get(), "state.json"); AWAIT_READY(response); EXPECT_SOME_EQ(
