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")); }
// Testing route without frameworkId value. TEST_F(TeardownTest, NoFrameworkId) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); Future<Response> response = process::http::post( master.get()->pid, "teardown", createBasicAuthHeaders(DEFAULT_CREDENTIAL), ""); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); driver.stop(); driver.join(); }
// Testing route without frameworkId value. TEST_F(TeardownTest, TeardownEndpointNoFrameworkId) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); process::http::Headers headers; headers["Authorization"] = "Basic " + base64::encode(DEFAULT_CREDENTIAL.principal() + ":" + DEFAULT_CREDENTIAL.secret()); Future<Response> response = process::http::post(master.get(), "teardown", headers, ""); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); driver.stop(); driver.join(); Shutdown(); }
// This test verifies that the client will receive a `BadRequest` response if it // includes a stream ID header with a subscribe call. TEST_P(SchedulerHttpApiTest, SubscribeWithStreamId) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO); // Retrieve the parameter passed as content type to this test. const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; headers["Mesos-Stream-Id"] = UUID::random().toString(); Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test expects a BadRequest when 'Content-Type' is omitted. TEST_F(ExecutorHttpApiTest, NoContentType) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); Call call; call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); call.set_type(Call::MESSAGE); call.mutable_message()->set_data("hello world"); Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", None(), serialize(ContentType::JSON, call), None()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a valid JSON blob that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_F(ExecutorHttpApiTest, ValidJsonButInvalidProtobuf) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); JSON::Object object; object.values["string"] = "valid_json"; process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, stringify(object), APPLICATION_JSON); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a malformed body that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_P(ExecutorHttpApiTest, MalformedContent) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); const string body = "MALFORMED_CONTENT"; const ContentType contentType = GetParam(); process::http::Headers headers; headers["Accept"] = stringify(contentType); Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, body, stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a malformed body that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_P(ExecutorHttpApiTest, MalformedContent) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); AWAIT_READY(__recover); const string body = "MALFORMED_CONTENT"; const ContentType contentType = GetParam(); hashmap<string, string> headers; headers["Accept"] = stringify(contentType); Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, body, stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// This test sends a Call from an unknown FrameworkID. The call // should return a BadRequest. TEST_P(ExecutorHttpApiTest, MessageFromUnknownFramework) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); AWAIT_READY(__recover); ContentType contentType = GetParam(); hashmap<string, string> headers; headers["Accept"] = stringify(contentType); Call call; call.set_type(Call::MESSAGE); call.mutable_message()->set_data("hello world"); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// This test sends a valid JSON blob that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_F(ExecutorHttpApiTest, ValidJsonButInvalidProtobuf) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); AWAIT_READY(__recover); JSON::Object object; object.values["string"] = "valid_json"; hashmap<string, string> headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, stringify(object), APPLICATION_JSON); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// TODO(anand): Add additional tests for validation. TEST_F(SchedulerHttpApiTest, NoContentType) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Expect a BadRequest when 'Content-Type' is omitted. // // TODO(anand): Send a valid call here to ensure that // the BadRequest is only due to the missing header. Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", createBasicAuthHeaders(DEFAULT_CREDENTIAL), None()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a valid JSON blob that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_F(SchedulerHttpApiTest, ValidJsonButInvalidProtobuf) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); JSON::Object object; object.values["string"] = "valid_json"; process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, stringify(object), APPLICATION_JSON); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a malformed body that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_P(SchedulerHttpApiTest, MalformedContent) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); const string body = "MALFORMED_CONTENT"; const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, body, contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
TEST_P(ExecutorHttpApiTest, ValidProtobufInvalidCall) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); // We send a Call protobuf message with missing // required message per type. { Call call; call.set_type(Call::SUBSCRIBE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); } { Call call; call.set_type(Call::UPDATE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); } { Call call; call.set_type(Call::MESSAGE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); } }
// This test verifies that the scheduler will receive a `BadRequest` response // when it tries to acknowledge a status update with a malformed UUID. TEST_P(SchedulerHttpApiTest, MalformedUUID) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Retrieve the parameter passed as content type to this test. const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; v1::FrameworkID frameworkId; string streamId; // Subscribe once to get a valid stream ID. { Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO); Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); ASSERT_EQ(Response::PIPE, response.get().type); ASSERT_TRUE(response.get().headers.contains("Mesos-Stream-Id")); streamId = response.get().headers.at("Mesos-Stream-Id"); Option<Pipe::Reader> reader = response.get().reader; ASSERT_SOME(reader); auto deserializer = lambda::bind( &SchedulerHttpApiTest::deserialize, this, contentType, lambda::_1); Reader<Event> responseDecoder(Decoder<Event>(deserializer), reader.get()); Future<Result<Event>> event = responseDecoder.read(); AWAIT_READY(event); ASSERT_SOME(event.get()); // Check that the event type is subscribed and the framework ID is set. ASSERT_EQ(Event::SUBSCRIBED, event.get().get().type()); frameworkId = event.get().get().subscribed().framework_id(); EXPECT_NE("", frameworkId.value()); } // Make an acknowledge call with a malformed UUID. This should result in a // `BadResponse`. { headers["Mesos-Stream-Id"] = streamId; Call call; call.set_type(Call::ACKNOWLEDGE); // Set the framework ID in the subscribe call. call.mutable_framework_id()->CopyFrom(frameworkId); Call::Acknowledge* acknowledge = call.mutable_acknowledge(); acknowledge->mutable_task_id()->set_value("task-id"); acknowledge->mutable_agent_id()->set_value("agent-id"); // Set a malformed uuid. acknowledge->set_uuid("bad-uuid"); Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Failed to validate scheduler::Call: Not a valid UUID", response); } }
Future<http::Response> ResourceProviderManagerProcess::api( const http::Request& request, const Option<Principal>& principal) { if (request.method != "POST") { return MethodNotAllowed({"POST"}, request.method); } v1::resource_provider::Call v1Call; // TODO(anand): Content type values are case-insensitive. Option<string> contentType = request.headers.get("Content-Type"); if (contentType.isNone()) { return BadRequest("Expecting 'Content-Type' to be present"); } if (contentType.get() == APPLICATION_PROTOBUF) { if (!v1Call.ParseFromString(request.body)) { return BadRequest("Failed to parse body into Call protobuf"); } } else if (contentType.get() == APPLICATION_JSON) { Try<JSON::Value> value = JSON::parse(request.body); if (value.isError()) { return BadRequest("Failed to parse body into JSON: " + value.error()); } Try<v1::resource_provider::Call> parse = ::protobuf::parse<v1::resource_provider::Call>(value.get()); if (parse.isError()) { return BadRequest("Failed to convert JSON into Call protobuf: " + parse.error()); } v1Call = parse.get(); } else { return UnsupportedMediaType( string("Expecting 'Content-Type' of ") + APPLICATION_JSON + " or " + APPLICATION_PROTOBUF); } Call call = devolve(v1Call); Option<Error> error = validate(call); if (error.isSome()) { return BadRequest( "Failed to validate resource_provider::Call: " + error->message); } ContentType acceptType; if (request.acceptsMediaType(APPLICATION_JSON)) { acceptType = ContentType::JSON; } else if (request.acceptsMediaType(APPLICATION_PROTOBUF)) { acceptType = ContentType::PROTOBUF; } else { return NotAcceptable( string("Expecting 'Accept' to allow ") + "'" + APPLICATION_PROTOBUF + "' or '" + APPLICATION_JSON + "'"); } switch(call.type()) { case Call::UNKNOWN: { return NotImplemented(); } case Call::SUBSCRIBE: { Pipe pipe; OK ok; ok.headers["Content-Type"] = stringify(acceptType); ok.type = http::Response::PIPE; ok.reader = pipe.reader(); HttpConnection http(pipe.writer(), acceptType); subscribe(http, call.subscribe()); return ok; } case Call::UPDATE: { if (!resourceProviders.contains(call.resource_provider_id())) { return BadRequest("Resource provider cannot be found"); } auto resourceProvider = resourceProviders.at(call.resource_provider_id()); update(&resourceProvider, call.update()); return Accepted(); } } UNREACHABLE(); }
TEST_P(ExecutorHttpApiTest, StatusUpdateCallFailedValidation) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get()); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); // We send a Call::Update message with inconsistent executor id between // Call::executor_id and Call::Update::TaskInfo::executor_id. // This should result in failed validation. { Call call; call.set_type(Call::UPDATE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("call_level_executor_id"); v1::TaskStatus* status = call.mutable_update()->mutable_status(); status->mutable_executor_id()->set_value("update_level_executor_id"); status->set_state(mesos::v1::TaskState::TASK_STARTING); status->mutable_task_id()->set_value("dummy_task_id"); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); } // We send a Call Update message with a TASK_STAGING // status update. This should fail validation. { Call call; call.set_type(Call::UPDATE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("call_level_executor_id"); v1::TaskStatus* status = call.mutable_update()->mutable_status(); status->mutable_executor_id()->set_value("call_level_executor_id"); status->mutable_task_id()->set_value("dummy_task_id"); status->set_state(mesos::v1::TaskState::TASK_STAGING); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> responseStatusUpdate = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, responseStatusUpdate); } // We send a Call Update message with a different source than // SOURCE_EXECUTOR in the status update. This should fail validation. { Call call; call.set_type(Call::UPDATE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("call_level_executor_id"); v1::TaskStatus* status = call.mutable_update()->mutable_status(); status->mutable_executor_id()->set_value("call_level_executor_id"); status->mutable_task_id()->set_value("dummy_task_id"); status->set_state(mesos::v1::TaskState::TASK_STARTING); status->set_source(mesos::v1::TaskStatus::SOURCE_MASTER); process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> responseStatusUpdate = process::http::post( slave.get()->pid, "api/v1/executor", headers, serialize(ContentType::PROTOBUF, call), APPLICATION_PROTOBUF); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, responseStatusUpdate); } }
// This test verifies that the scheduler will receive a `BadRequest` response // when a teardown call is made with an incorrect stream ID header. TEST_P(SchedulerHttpApiTest, TeardownWrongStreamId) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Retrieve the parameter passed as content type to this test. const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; v1::FrameworkID frameworkId; string streamId; // Subscribe once to get a valid stream ID. { Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO); Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ("chunked", "Transfer-Encoding", response); ASSERT_EQ(Response::PIPE, response.get().type); ASSERT_TRUE(response.get().headers.contains("Mesos-Stream-Id")); streamId = response.get().headers.at("Mesos-Stream-Id"); Option<Pipe::Reader> reader = response.get().reader; ASSERT_SOME(reader); auto deserializer = lambda::bind( &SchedulerHttpApiTest::deserialize, this, contentType, lambda::_1); Reader<Event> responseDecoder(Decoder<Event>(deserializer), reader.get()); Future<Result<Event>> event = responseDecoder.read(); AWAIT_READY(event); ASSERT_SOME(event.get()); // Check that the event type is subscribed and the framework ID is set. ASSERT_EQ(Event::SUBSCRIBED, event.get().get().type()); EXPECT_NE("", event.get().get().subscribed().framework_id().value()); frameworkId = event.get().get().subscribed().framework_id(); } // Subscribe again to invalidate the first stream ID and acquire another one. { Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO); // Set the framework ID in the subscribe call. call.mutable_framework_id()->CopyFrom(frameworkId); subscribe->mutable_framework_info()->mutable_id()->CopyFrom(frameworkId); Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ("chunked", "Transfer-Encoding", response); ASSERT_EQ(Response::PIPE, response.get().type); ASSERT_TRUE(response.get().headers.contains("Mesos-Stream-Id")); // Make sure that the new stream ID is different. ASSERT_NE(streamId, response.get().headers.at("Mesos-Stream-Id")); Option<Pipe::Reader> reader = response.get().reader; ASSERT_SOME(reader); auto deserializer = lambda::bind( &SchedulerHttpApiTest::deserialize, this, contentType, lambda::_1); Reader<Event> responseDecoder(Decoder<Event>(deserializer), reader.get()); Future<Result<Event>> event = responseDecoder.read(); AWAIT_READY(event); ASSERT_SOME(event.get()); ASSERT_EQ(Event::SUBSCRIBED, event.get().get().type()); EXPECT_NE("", event.get().get().subscribed().framework_id().value()); } { Call call; call.set_type(Call::TEARDOWN); call.mutable_framework_id()->CopyFrom(frameworkId); // Send the first (now incorrect) stream ID with the teardown call. headers["Mesos-Stream-Id"] = streamId; Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); } }
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")); }