TEST_F(FilesTest, DownloadTest) { Files files; process::UPID upid("files", process::address()); // This is a one-pixel black gif image. const unsigned char gifData[] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x01, 0x00, 0x01, 0x00, 0x91, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x4c, 0x01, 0x00, 0x3b, 0x00 }; string data((const char*) gifData, sizeof(gifData)); ASSERT_SOME(os::write("binary", "no file extension")); ASSERT_SOME(os::write("black.gif", data)); AWAIT_EXPECT_READY(files.attach("binary", "binary")); AWAIT_EXPECT_READY(files.attach("black.gif", "black.gif")); Future<Response> response = process::http::get(upid, "download.json", "path=binary"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/octet-stream", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("no file extension", response); response = process::http::get(upid, "download.json", "path=black.gif"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ("image/gif", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ(data, response); }
TEST_F(FilesTest, ReadTest) { Files files; process::UPID upid("files", process::address()); Future<Response> response = process::http::get(upid, "read.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Expecting 'path=value' in query.\n", response); response = process::http::get(upid, "read.json", "path=none&offset=hello"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Failed to parse offset: Failed to convert 'hello' to number.\n", response); response = process::http::get(upid, "read.json", "path=none&length=hello"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Failed to parse length: Failed to convert 'hello' to number.\n", response); // Now write a file. ASSERT_SOME(os::write("file", "body")); AWAIT_EXPECT_READY(files.attach("file", "/myname")); AWAIT_EXPECT_READY(files.attach("file", "myname")); // Read a valid file. JSON::Object expected; expected.values["offset"] = 0; expected.values["data"] = "body"; response = process::http::get(upid, "read.json", "path=/myname&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=myname&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); // Missing file. AWAIT_EXPECT_RESPONSE_STATUS_EQ( NotFound().status, process::http::get(upid, "read.json", "path=missing")); }
TEST_F(FilesTest, BrowseTest) { Files files; process::UPID upid("files", process::address()); ASSERT_SOME(os::mkdir("1/2")); ASSERT_SOME(os::mkdir("1/3")); ASSERT_SOME(os::write("1/two", "two")); ASSERT_SOME(os::write("1/three", "three")); AWAIT_EXPECT_READY(files.attach("1", "one")); // Get the listing. struct stat s; JSON::Array expected; ASSERT_EQ(0, stat("1/2", &s)); expected.values.push_back(jsonFileInfo("one/2", s)); ASSERT_EQ(0, stat("1/3", &s)); expected.values.push_back(jsonFileInfo("one/3", s)); ASSERT_EQ(0, stat("1/three", &s)); expected.values.push_back(jsonFileInfo("one/three", s)); ASSERT_EQ(0, stat("1/two", &s)); expected.values.push_back(jsonFileInfo("one/two", s)); Future<Response> response = process::http::get(upid, "browse.json", "path=one/"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "browse.json", "path=one%2F"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "browse.json", "path=one"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); // Empty listing. response = process::http::get(upid, "browse.json", "path=one/2"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(JSON::Array()), response); // Missing dir. AWAIT_EXPECT_RESPONSE_STATUS_EQ( NotFound().status, process::http::get(upid, "browse.json", "path=missing")); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::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); CHECK_SOME(parse); return parse.get(); }
// This test verifies the correct handling of the statistics // endpoint when there is no executor running. TEST(MonitorTest, NoExecutor) { ResourceMonitor monitor([]() -> Future<ResourceUsage> { return ResourceUsage(); }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); // TODO(neilc): This request might timeout if the current value of a // metric cannot be determined. In tests, a common cause for this is // MESOS-6231 when multiple scheduler drivers are in use. process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
// This test verifies the correct handling of the statistics // endpoint when statistics is missing in ResourceUsage. TEST(MonitorTest, MissingStatistics) { ResourceMonitor monitor([]() -> Future<ResourceUsage> { 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"); Resources resources = Resources::parse("cpus:1;mem:2").get(); ResourceUsage usage; ResourceUsage::Executor* executor = usage.add_executors(); executor->mutable_executor_info()->CopyFrom(executorInfo); executor->mutable_allocated()->CopyFrom(resources); return usage; }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
TEST(MonitorTest, Statistics) { 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 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(1.0); statistics.set_mem_file_bytes(0); statistics.set_mem_anon_bytes(0); statistics.set_mem_mapped_file_bytes(0); statistics.set_mem_rss_bytes(1024); statistics.set_mem_limit_bytes(2048); statistics.set_timestamp(0); ResourceMonitor monitor([=]() -> Future<ResourceUsage> { Resources resources = Resources::parse("cpus:1;mem:2").get(); ResourceUsage usage; ResourceUsage::Executor* executor = usage.add_executors(); executor->mutable_executor_info()->CopyFrom(executorInfo); executor->mutable_allocated()->CopyFrom(resources); executor->mutable_statistics()->CopyFrom(statistics); return usage; }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); JSON::Array expected; JSON::Object usage; usage.values["executor_id"] = "executor"; usage.values["executor_name"] = "name"; usage.values["framework_id"] = "framework"; usage.values["source"] = "source"; usage.values["statistics"] = JSON::Protobuf(statistics); expected.values.push_back(usage); Try<JSON::Array> result = JSON::parse<JSON::Array>(response.get().body); ASSERT_SOME(result); ASSERT_EQ(expected, result.get()); }
// This is an end-to-end test that verfies that the slave returns the // correct ResourceUsage based on the currently running executors, and // the values get from the statistics endpoint are as expected. TEST_F(MonitorIntegrationTest, RunningExecutor) { 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_FALSE(offers.get().empty()); const Offer& offer = offers.get()[0]; // Launch a task and wait until it is in RUNNING status. TaskInfo task = createTask( offer.slave_id(), Resources::parse("cpus:1;mem:32").get(), "sleep 1000"); Future<TaskStatus> status; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status)); driver.launchTasks(offer.id(), {task}); AWAIT_READY(status); EXPECT_EQ(task.task_id(), status.get().task_id()); EXPECT_EQ(TASK_RUNNING, status.get().state()); // Hit the statistics endpoint and expect the response contains the // resource statistics for the running container. UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); // Verify that the statistics in the response contains the proper // resource limits for the container. Try<JSON::Value> value = JSON::parse(response.get().body); ASSERT_SOME(value); Try<JSON::Value> expected = JSON::parse(strings::format( "[{" "\"statistics\":{" "\"cpus_limit\":%g," "\"mem_limit_bytes\":%lu" "}" "}]", 1 + slave::DEFAULT_EXECUTOR_CPUS, (Megabytes(32) + slave::DEFAULT_EXECUTOR_MEM).bytes()).get()); ASSERT_SOME(expected); EXPECT_TRUE(value.get().contains(expected.get())); driver.stop(); driver.join(); Shutdown(); }
TEST_F(MetricsTest, Master) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Get the snapshot. process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); ASSERT_SOME(parse); JSON::Object stats = parse.get(); EXPECT_EQ(1u, stats.values.count("master/uptime_secs")); EXPECT_EQ(1u, stats.values.count("master/elected")); EXPECT_EQ(1u, stats.values.count("master/slaves_connected")); EXPECT_EQ(1u, stats.values.count("master/slaves_disconnected")); EXPECT_EQ(1u, stats.values.count("master/slaves_active")); EXPECT_EQ(1u, stats.values.count("master/slaves_inactive")); EXPECT_EQ(1u, stats.values.count("master/frameworks_connected")); EXPECT_EQ(1u, stats.values.count("master/frameworks_disconnected")); EXPECT_EQ(1u, stats.values.count("master/frameworks_active")); EXPECT_EQ(1u, stats.values.count("master/frameworks_inactive")); EXPECT_EQ(1u, stats.values.count("master/outstanding_offers")); EXPECT_EQ(1u, stats.values.count("master/tasks_staging")); EXPECT_EQ(1u, stats.values.count("master/tasks_starting")); EXPECT_EQ(1u, stats.values.count("master/tasks_running")); EXPECT_EQ(1u, stats.values.count("master/tasks_killing")); EXPECT_EQ(1u, stats.values.count("master/tasks_finished")); EXPECT_EQ(1u, stats.values.count("master/tasks_failed")); EXPECT_EQ(1u, stats.values.count("master/tasks_killed")); EXPECT_EQ(1u, stats.values.count("master/tasks_lost")); EXPECT_EQ(1u, stats.values.count("master/tasks_error")); EXPECT_EQ(1u, stats.values.count("master/dropped_messages")); // Messages from schedulers. EXPECT_EQ(1u, stats.values.count("master/messages_register_framework")); EXPECT_EQ(1u, stats.values.count("master/messages_reregister_framework")); EXPECT_EQ(1u, stats.values.count("master/messages_unregister_framework")); EXPECT_EQ(1u, stats.values.count("master/messages_deactivate_framework")); EXPECT_EQ(1u, stats.values.count("master/messages_kill_task")); EXPECT_EQ(1u, stats.values.count( "master/messages_status_update_acknowledgement")); EXPECT_EQ(1u, stats.values.count("master/messages_resource_request")); EXPECT_EQ(1u, stats.values.count("master/messages_launch_tasks")); EXPECT_EQ(1u, stats.values.count("master/messages_decline_offers")); EXPECT_EQ(1u, stats.values.count("master/messages_revive_offers")); EXPECT_EQ(1u, stats.values.count("master/messages_suppress_offers")); EXPECT_EQ(1u, stats.values.count("master/messages_reconcile_tasks")); EXPECT_EQ(1u, stats.values.count("master/messages_framework_to_executor")); // Messages from slaves. EXPECT_EQ(1u, stats.values.count("master/messages_register_slave")); EXPECT_EQ(1u, stats.values.count("master/messages_reregister_slave")); EXPECT_EQ(1u, stats.values.count("master/messages_unregister_slave")); EXPECT_EQ(1u, stats.values.count("master/messages_status_update")); EXPECT_EQ(1u, stats.values.count("master/messages_exited_executor")); // Messages from both schedulers and slaves. EXPECT_EQ(1u, stats.values.count("master/messages_authenticate")); EXPECT_EQ(1u, stats.values.count( "master/valid_framework_to_executor_messages")); EXPECT_EQ(1u, stats.values.count( "master/invalid_framework_to_executor_messages")); EXPECT_EQ(1u, stats.values.count("master/valid_status_updates")); EXPECT_EQ(1u, stats.values.count("master/invalid_status_updates")); EXPECT_EQ(1u, stats.values.count( "master/valid_status_update_acknowledgements")); EXPECT_EQ(1u, stats.values.count( "master/invalid_status_update_acknowledgements")); EXPECT_EQ(1u, stats.values.count("master/recovery_slave_removals")); EXPECT_EQ(1u, stats.values.count("master/event_queue_messages")); EXPECT_EQ(1u, stats.values.count("master/event_queue_dispatches")); EXPECT_EQ(1u, stats.values.count("master/event_queue_http_requests")); EXPECT_EQ(1u, stats.values.count("master/cpus_total")); EXPECT_EQ(1u, stats.values.count("master/cpus_used")); EXPECT_EQ(1u, stats.values.count("master/cpus_percent")); EXPECT_EQ(1u, stats.values.count("master/mem_total")); EXPECT_EQ(1u, stats.values.count("master/mem_used")); EXPECT_EQ(1u, stats.values.count("master/mem_percent")); EXPECT_EQ(1u, stats.values.count("master/disk_total")); EXPECT_EQ(1u, stats.values.count("master/disk_used")); EXPECT_EQ(1u, stats.values.count("master/disk_percent")); EXPECT_EQ(1u, stats.values.count("registrar/queued_operations")); EXPECT_EQ(1u, stats.values.count("registrar/registry_size_bytes")); EXPECT_EQ(1u, stats.values.count("registrar/state_fetch_ms")); EXPECT_EQ(1u, stats.values.count("registrar/state_store_ms")); }
TEST_F(MetricsTest, Slave) { // TODO(dhamon): https://issues.apache.org/jira/browse/MESOS-2134 to allow // only a Slave to be started. Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); // Get the snapshot. process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); ASSERT_SOME(parse); JSON::Object stats = parse.get(); EXPECT_EQ(1u, stats.values.count("slave/uptime_secs")); EXPECT_EQ(1u, stats.values.count("slave/registered")); EXPECT_EQ(1u, stats.values.count("slave/recovery_errors")); EXPECT_EQ(1u, stats.values.count("slave/frameworks_active")); EXPECT_EQ(1u, stats.values.count("slave/tasks_staging")); EXPECT_EQ(1u, stats.values.count("slave/tasks_starting")); EXPECT_EQ(1u, stats.values.count("slave/tasks_running")); EXPECT_EQ(1u, stats.values.count("slave/tasks_killing")); EXPECT_EQ(1u, stats.values.count("slave/tasks_finished")); EXPECT_EQ(1u, stats.values.count("slave/tasks_failed")); EXPECT_EQ(1u, stats.values.count("slave/tasks_killed")); EXPECT_EQ(1u, stats.values.count("slave/tasks_lost")); EXPECT_EQ(1u, stats.values.count("slave/executors_registering")); EXPECT_EQ(1u, stats.values.count("slave/executors_running")); EXPECT_EQ(1u, stats.values.count("slave/executors_terminating")); EXPECT_EQ(1u, stats.values.count("slave/executors_terminated")); EXPECT_EQ(1u, stats.values.count("slave/valid_status_updates")); EXPECT_EQ(1u, stats.values.count("slave/invalid_status_updates")); EXPECT_EQ(1u, stats.values.count("slave/valid_framework_messages")); EXPECT_EQ(1u, stats.values.count("slave/invalid_framework_messages")); EXPECT_EQ(1u, stats.values.count("slave/container_launch_errors")); EXPECT_EQ(1u, stats.values.count("slave/cpus_total")); EXPECT_EQ(1u, stats.values.count("slave/cpus_used")); EXPECT_EQ(1u, stats.values.count("slave/cpus_percent")); EXPECT_EQ(1u, stats.values.count("slave/mem_total")); EXPECT_EQ(1u, stats.values.count("slave/mem_used")); EXPECT_EQ(1u, stats.values.count("slave/mem_percent")); EXPECT_EQ(1u, stats.values.count("slave/disk_total")); EXPECT_EQ(1u, stats.values.count("slave/disk_used")); EXPECT_EQ(1u, stats.values.count("slave/disk_percent")); }
TEST_F(FilesTest, ResolveTest) { Files files; process::UPID upid("files", process::address()); // Test the directory / file resolution. ASSERT_SOME(os::mkdir("1/2")); ASSERT_SOME(os::write("1/two", "two")); ASSERT_SOME(os::write("1/2/three", "three")); // Attach some paths. AWAIT_EXPECT_READY(files.attach("1", "one")); AWAIT_EXPECT_READY(files.attach("1", "/one/")); AWAIT_EXPECT_READY(files.attach("1/2", "two")); AWAIT_EXPECT_READY(files.attach("1/2", "one/two")); // Resolve 1/2/3 via each attached path. JSON::Object expected; expected.values["offset"] = 0; expected.values["data"] = "three"; Future<Response> response = process::http::get(upid, "read.json", "path=one/2/three&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=/one/2/three&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=two/three&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=one/two/three&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); // Percent encoded '/' urls. response = process::http::get(upid, "read.json", "path=%2Fone%2F2%2Fthree&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=one%2Ftwo%2Fthree&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); // Reading dirs not allowed. AWAIT_EXPECT_RESPONSE_STATUS_EQ( BadRequest().status, process::http::get(upid, "read.json", "path=one/2")); AWAIT_EXPECT_RESPONSE_STATUS_EQ( BadRequest().status, process::http::get(upid, "read.json", "path=one")); AWAIT_EXPECT_RESPONSE_STATUS_EQ( BadRequest().status, process::http::get(upid, "read.json", "path=one/")); // Breaking out of sandbox. AWAIT_EXPECT_RESPONSE_STATUS_EQ( BadRequest().status, process::http::get(upid, "read.json", "path=two/../two")); }