inline bool operator!=(const FrameworkID& left, const FrameworkID& right) { return left.value() != right.value(); }
inline bool operator==(const FrameworkID& left, const std::string& right) { return left.value() == right; }
// TODO(bmahler): Add additional tests: // 1. Check that the data has been published to statistics. // 2. Check that metering is occurring on subsequent resource data. TEST(MonitorTest, WatchUnwatch) { FrameworkID frameworkId; frameworkId.set_value("framework"); ExecutorID executorId; executorId.set_value("executor"); ExecutorInfo executorInfo; executorInfo.mutable_executor_id()->CopyFrom(executorId); executorInfo.mutable_framework_id()->CopyFrom(frameworkId); executorInfo.set_name("name"); executorInfo.set_source("source"); ResourceStatistics initialStatistics; initialStatistics.set_cpus_user_time_secs(0); initialStatistics.set_cpus_system_time_secs(0); initialStatistics.set_cpus_limit(2.5); initialStatistics.set_mem_rss_bytes(0); initialStatistics.set_mem_limit_bytes(2048); initialStatistics.set_timestamp(Clock::now().secs()); ResourceStatistics statistics; statistics.set_cpus_nr_periods(100); statistics.set_cpus_nr_throttled(2); statistics.set_cpus_user_time_secs(4); statistics.set_cpus_system_time_secs(1); statistics.set_cpus_throttled_time_secs(0.5); statistics.set_cpus_limit(2.5); statistics.set_mem_rss_bytes(1024); statistics.set_mem_limit_bytes(2048); statistics.set_timestamp( initialStatistics.timestamp() + slave::RESOURCE_MONITORING_INTERVAL.secs()); TestingIsolator isolator; process::spawn(isolator); Future<Nothing> usage1, usage2; EXPECT_CALL(isolator, usage(frameworkId, executorId)) .WillOnce(DoAll(FutureSatisfy(&usage1), Return(initialStatistics))) .WillOnce(DoAll(FutureSatisfy(&usage2), Return(statistics))); slave::ResourceMonitor monitor(&isolator); // We pause the clock first in order to make sure that we can // advance time below to force the 'delay' in // ResourceMonitorProcess::watch to execute. process::Clock::pause(); monitor.watch( frameworkId, executorId, executorInfo, slave::RESOURCE_MONITORING_INTERVAL); // Now wait for ResouorceMonitorProcess::watch to finish so we can // advance time to cause collection to begin. process::Clock::settle(); process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); AWAIT_READY(usage1); // Wait until the isolator has finished returning the statistics. process::Clock::settle(); // The second collection will populate the cpus_usage. process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); AWAIT_READY(usage2); // Wait until the isolator has finished returning the statistics. process::Clock::settle(); process::UPID upid("monitor", process::ip(), process::port()); Future<Response> response = process::http::get(upid, "usage.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); // TODO(bmahler): Verify metering directly through statistics. AWAIT_EXPECT_RESPONSE_BODY_EQ( strings::format( "[{" "\"executor_id\":\"executor\"," "\"executor_name\":\"name\"," "\"framework_id\":\"framework\"," "\"resource_usage\":{" "\"cpu_time\":%g," "\"cpu_usage\":%g," "\"memory_rss\":%lu" "}," "\"source\":\"source\"" "}]", statistics.cpus_system_time_secs() + statistics.cpus_user_time_secs(), (statistics.cpus_system_time_secs() + statistics.cpus_user_time_secs()) / slave::RESOURCE_MONITORING_INTERVAL.secs(), statistics.mem_rss_bytes()).get(), response); response = process::http::get(upid, "statistics.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); // TODO(bmahler): Verify metering directly through statistics. AWAIT_EXPECT_RESPONSE_BODY_EQ( strings::format( "[{" "\"executor_id\":\"executor\"," "\"executor_name\":\"name\"," "\"framework_id\":\"framework\"," "\"source\":\"source\"," "\"statistics\":{" "\"cpus_limit\":%g," "\"cpus_nr_periods\":%d," "\"cpus_nr_throttled\":%d," "\"cpus_system_time_secs\":%g," "\"cpus_throttled_time_secs\":%g," "\"cpus_user_time_secs\":%g," "\"mem_limit_bytes\":%lu," "\"mem_rss_bytes\":%lu" "}" "}]", statistics.cpus_limit(), statistics.cpus_nr_periods(), statistics.cpus_nr_throttled(), statistics.cpus_system_time_secs(), statistics.cpus_throttled_time_secs(), statistics.cpus_user_time_secs(), statistics.mem_limit_bytes(), statistics.mem_rss_bytes()).get(), response); // Ensure the monitor stops polling the isolator. monitor.unwatch(frameworkId, executorId); // Wait until ResourceMonitorProcess::unwatch has completed. process::Clock::settle(); // This time, Isolator::usage should not get called. EXPECT_CALL(isolator, usage(frameworkId, executorId)) .Times(0); process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); response = process::http::get(upid, "usage.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
inline std::size_t hash_value(const FrameworkID& frameworkId) { size_t seed = 0; boost::hash_combine(seed, frameworkId.value()); return seed; }
// This test ensures we don't break the API when it comes to JSON // representation of tasks. TEST(HTTPTest, ModelTask) { TaskID taskId; taskId.set_value("t"); SlaveID slaveId; slaveId.set_value("s"); ExecutorID executorId; executorId.set_value("t"); FrameworkID frameworkId; frameworkId.set_value("f"); TaskState state = TASK_RUNNING; vector<TaskStatus> statuses; TaskStatus status; status.mutable_task_id()->CopyFrom(taskId); status.set_state(state); status.mutable_slave_id()->CopyFrom(slaveId); status.mutable_executor_id()->CopyFrom(executorId); status.set_timestamp(0.0); statuses.push_back(status); Labels labels; labels.add_labels()->CopyFrom(createLabel("ACTION", "port:7987 DENY")); Ports ports; Port* port = ports.add_ports(); port->set_number(80); port->mutable_labels()->CopyFrom(labels); DiscoveryInfo discovery; discovery.set_visibility(DiscoveryInfo::CLUSTER); discovery.set_name("discover"); discovery.mutable_ports()->CopyFrom(ports); TaskInfo taskInfo; taskInfo.set_name("task"); taskInfo.mutable_task_id()->CopyFrom(taskId); taskInfo.mutable_slave_id()->CopyFrom(slaveId); taskInfo.mutable_command()->set_value("echo hello"); taskInfo.mutable_discovery()->CopyFrom(discovery); Task task = createTask(taskInfo, state, frameworkId); task.add_statuses()->CopyFrom(statuses[0]); JSON::Value object = model(task); Try<JSON::Value> expected = JSON::parse( "{" " \"executor_id\":\"\"," " \"framework_id\":\"f\"," " \"id\":\"t\"," " \"name\":\"task\"," " \"resources\":" " {" " \"cpus\":0," " \"disk\":0," " \"gpus\":0," " \"mem\":0" " }," " \"slave_id\":\"s\"," " \"state\":\"TASK_RUNNING\"," " \"statuses\":" " [" " {" " \"state\":\"TASK_RUNNING\"," " \"timestamp\":0" " }" " ]," " \"discovery\":" " {" " \"name\":\"discover\"," " \"ports\":" " {" " \"ports\":" " [" " {" " \"number\":80," " \"labels\":" " {" " \"labels\":" " [" " {" " \"key\":\"ACTION\"," " \"value\":\"port:7987 DENY\"" " }" " ]" " }" " }" " ]" " }," " \"visibility\":\"CLUSTER\"" " }" "}"); ASSERT_SOME(expected); EXPECT_EQ(expected.get(), object); }