| Index: chrome/browser/policy/cloud/test_request_interceptor.cc | 
| diff --git a/chrome/browser/policy/cloud/test_request_interceptor.cc b/chrome/browser/policy/cloud/test_request_interceptor.cc | 
| index ce185ab94dbfbae2705f837033b4ff328d34fbe0..34427b223213a244d84a5fe1262264ff51ee9c1d 100644 | 
| --- a/chrome/browser/policy/cloud/test_request_interceptor.cc | 
| +++ b/chrome/browser/policy/cloud/test_request_interceptor.cc | 
| @@ -14,6 +14,7 @@ | 
| #include "base/message_loop/message_loop_proxy.h" | 
| #include "base/run_loop.h" | 
| #include "base/sequenced_task_runner.h" | 
| +#include "components/policy/core/common/remote_commands/testing_remote_commands_server.h" | 
| #include "content/public/browser/browser_thread.h" | 
| #include "net/base/net_errors.h" | 
| #include "net/base/upload_bytes_element_reader.h" | 
| @@ -32,6 +33,15 @@ namespace policy { | 
|  | 
| namespace { | 
|  | 
| +static const char kGoodHeaders[] = | 
| +    "HTTP/1.1 200 OK\0" | 
| +    "Content-type: application/protobuf\0" | 
| +    "\0"; | 
| +static const char kBadHeaders[] = | 
| +    "HTTP/1.1 400 Bad request\0" | 
| +    "Content-type: application/protobuf\0" | 
| +    "\0"; | 
| + | 
| // Helper callback for jobs that should fail with a network |error|. | 
| net::URLRequestJob* ErrorJobCallback(int error, | 
| net::URLRequest* request, | 
| @@ -43,11 +53,7 @@ net::URLRequestJob* ErrorJobCallback(int error, | 
| net::URLRequestJob* BadRequestJobCallback( | 
| net::URLRequest* request, | 
| net::NetworkDelegate* network_delegate) { | 
| -  static const char kBadHeaders[] = | 
| -      "HTTP/1.1 400 Bad request\0" | 
| -      "Content-type: application/protobuf\0" | 
| -      "\0"; | 
| -  std::string headers(kBadHeaders, arraysize(kBadHeaders)); | 
| +  const std::string headers(kBadHeaders, arraysize(kBadHeaders)); | 
| return new net::URLRequestTestJob( | 
| request, network_delegate, headers, std::string(), true); | 
| } | 
| @@ -67,7 +73,7 @@ net::URLRequestJob* FileJobCallback(const base::FilePath& file_path, | 
| // Parses the upload data in |request| into |request_msg|, and validates the | 
| // request. The query string in the URL must contain the |expected_type| for | 
| // the "request" parameter. Returns true if all checks succeeded, and the | 
| -// request data has been parsed into |request_msg|. | 
| +// request data has been parsed into |request_msg| if it's not null. | 
| bool ValidRequest(net::URLRequest* request, | 
| const std::string& expected_type, | 
| em::DeviceManagementRequest* request_msg) { | 
| @@ -91,7 +97,7 @@ bool ValidRequest(net::URLRequest* request, | 
| if (!reader) | 
| return false; | 
| std::string data(reader->bytes(), reader->length()); | 
| -  if (!request_msg->ParseFromString(data)) | 
| +  if (request_msg && !request_msg->ParseFromString(data)) | 
| return false; | 
|  | 
| return true; | 
| @@ -115,7 +121,8 @@ net::URLRequestJob* RegisterJobCallback( | 
| request_msg.has_policy_request() || | 
| request_msg.has_device_status_report_request() || | 
| request_msg.has_session_status_report_request() || | 
| -      request_msg.has_auto_enrollment_request()) { | 
| +      request_msg.has_auto_enrollment_request() || | 
| +      request_msg.has_remote_command_request()) { | 
| return BadRequestJobCallback(request, network_delegate); | 
| } | 
|  | 
| @@ -140,11 +147,53 @@ net::URLRequestJob* RegisterJobCallback( | 
| std::string data; | 
| response.SerializeToString(&data); | 
|  | 
| -  static const char kGoodHeaders[] = | 
| -      "HTTP/1.1 200 OK\0" | 
| -      "Content-type: application/protobuf\0" | 
| -      "\0"; | 
| -  std::string headers(kGoodHeaders, arraysize(kGoodHeaders)); | 
| +  const std::string headers(kGoodHeaders, arraysize(kGoodHeaders)); | 
| +  return new net::URLRequestTestJob(request, network_delegate, headers, data, | 
| +                                    true); | 
| +} | 
| + | 
| +net::URLRequestJob* FetchRemoteCommandsJobCallback( | 
| +    TestingRemoteCommandsServer* server, | 
| +    size_t expected_command_results, | 
| +    size_t expected_fetched_commands, | 
| +    net::URLRequest* request, | 
| +    net::NetworkDelegate* network_delegate) { | 
| +  em::DeviceManagementRequest request_msg; | 
| +  if (!ValidRequest(request, "remote_commands", &request_msg)) | 
| +    return BadRequestJobCallback(request, network_delegate); | 
| + | 
| +  if (!request_msg.has_remote_command_request()) | 
| +    return BadRequestJobCallback(request, network_delegate); | 
| + | 
| +  const em::DeviceRemoteCommandRequest& remote_command_request = | 
| +      request_msg.remote_command_request(); | 
| +  if (!remote_command_request.has_last_command_unique_id()) | 
| +    return BadRequestJobCallback(request, network_delegate); | 
| + | 
| +  std::vector<em::RemoteCommandResult> previous_results( | 
| +      remote_command_request.command_results().begin(), | 
| +      remote_command_request.command_results().end()); | 
| + | 
| +  // Verify the number of results for previous commands. | 
| +  DCHECK_EQ(expected_command_results, previous_results.size()); | 
| + | 
| +  // Interact with TestingRemoteCommandsServer to actually fetch commands, | 
| +  // and verify the number of fetched commands. | 
| +  const std::vector<em::RemoteCommand> fetched_commands = server->FetchCommands( | 
| +      remote_command_request.last_command_unique_id(), previous_results); | 
| +  DCHECK_EQ(expected_fetched_commands, fetched_commands.size()); | 
| + | 
| +  // Generating response. | 
| +  em::DeviceManagementResponse response; | 
| +  em::DeviceRemoteCommandResponse* remote_command_response = | 
| +      response.mutable_remote_command_response(); | 
| + | 
| +  for (const auto& fetched_command : fetched_commands) | 
| +    *remote_command_response->add_commands() = fetched_command; | 
| +  std::string data; | 
| +  response.SerializeToString(&data); | 
| + | 
| +  const std::string headers(kGoodHeaders, arraysize(kGoodHeaders)); | 
| return new net::URLRequestTestJob( | 
| request, network_delegate, headers, data, true); | 
| } | 
| @@ -172,11 +221,14 @@ class TestRequestInterceptor::Delegate : public net::URLRequestInterceptor { | 
| void GetPendingSize(size_t* pending_size) const; | 
| void AddRequestServicedCallback(const base::Closure& callback); | 
| void PushJobCallback(const JobCallback& callback); | 
| +  void AddIgnoredRequestType(const std::string& ignored_type); | 
|  | 
| private: | 
| static void InvokeRequestServicedCallbacks( | 
| scoped_ptr<std::vector<base::Closure>> callbacks); | 
|  | 
| +  std::vector<std::string> ignored_types_; | 
| + | 
| const std::string hostname_; | 
| scoped_refptr<base::SequencedTaskRunner> io_task_runner_; | 
|  | 
| @@ -213,6 +265,13 @@ net::URLRequestJob* TestRequestInterceptor::Delegate::MaybeInterceptRequest( | 
| return BadRequestJobCallback(request, network_delegate); | 
| } | 
|  | 
| +  // If the request is explicitly ignored, don't handle this request by | 
| +  // sending back an bad request response. | 
| +  for (const std::string& ignored_type : ignored_types_) { | 
| +    if (ValidRequest(request, ignored_type, nullptr)) | 
| +      return BadRequestJobCallback(request, network_delegate); | 
| +  } | 
| + | 
| // Invoke any callbacks that are waiting for the next request to be serviced | 
| // after this job is serviced. | 
| if (!request_serviced_callbacks_.empty()) { | 
| @@ -247,6 +306,13 @@ void TestRequestInterceptor::Delegate::PushJobCallback( | 
| pending_job_callbacks_.push(callback); | 
| } | 
|  | 
| +void TestRequestInterceptor::Delegate::AddIgnoredRequestType( | 
| +    const std::string& ignored_type) { | 
| +  CHECK(io_task_runner_->RunsTasksOnCurrentThread()); | 
| + | 
| +  ignored_types_.push_back(ignored_type); | 
| +} | 
| + | 
| // static | 
| void TestRequestInterceptor::Delegate::InvokeRequestServicedCallbacks( | 
| scoped_ptr<std::vector<base::Closure>> callbacks) { | 
| @@ -301,6 +367,12 @@ void TestRequestInterceptor::PushJobCallback(const JobCallback& callback) { | 
| callback)); | 
| } | 
|  | 
| +void TestRequestInterceptor::AddIgnoredRequestType( | 
| +    const std::string& ignored_type) { | 
| +  PostToIOAndWait(base::Bind(&Delegate::AddIgnoredRequestType, | 
| +                             base::Unretained(delegate_), ignored_type)); | 
| +} | 
| + | 
| // static | 
| TestRequestInterceptor::JobCallback TestRequestInterceptor::ErrorJob( | 
| int error) { | 
| @@ -325,6 +397,16 @@ TestRequestInterceptor::JobCallback TestRequestInterceptor::FileJob( | 
| return base::Bind(&FileJobCallback, file_path); | 
| } | 
|  | 
| +// static | 
| +TestRequestInterceptor::JobCallback | 
| +TestRequestInterceptor::FetchRemoteCommandsJob( | 
| +    TestingRemoteCommandsServer* server, | 
| +    size_t expected_command_results, | 
| +    size_t expected_fetched_commands) { | 
| +  return base::Bind(&FetchRemoteCommandsJobCallback, server, | 
| +                    expected_command_results, expected_fetched_commands); | 
| +} | 
| + | 
| void TestRequestInterceptor::PostToIOAndWait(const base::Closure& task) { | 
| io_task_runner_->PostTask(FROM_HERE, task); | 
| base::RunLoop run_loop; | 
|  |