blob: df6249211fabaef679c13ef87995cc81a36e98f9 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ostream>
#include <vector>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/device_management_service.h"
#include "chrome/browser/policy/cloud/mock_device_management_service.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Mock;
using testing::_;
namespace em = enterprise_management;
namespace policy {
const char kServiceUrl[] = "https://example.com/management_service";
// Encoded empty response messages for testing the error code paths.
const char kResponseEmpty[] = "\x08\x00";
#define PROTO_STRING(name) (std::string(name, arraysize(name) - 1))
// Some helper constants.
const char kGaiaAuthToken[] = "gaia-auth-token";
const char kOAuthToken[] = "oauth-token";
const char kDMToken[] = "device-management-token";
const char kClientID[] = "device-id";
const char kRobotAuthCode[] = "robot-oauth-auth-code";
// Unit tests for the device management policy service. The tests are run
// against a TestURLFetcherFactory that is used to short-circuit the request
// without calling into the actual network stack.
class DeviceManagementServiceTestBase : public testing::Test {
protected:
DeviceManagementServiceTestBase() {
request_context_ =
new net::TestURLRequestContextGetter(loop_.message_loop_proxy());
ResetService();
InitializeService();
}
~DeviceManagementServiceTestBase() {
service_.reset();
base::RunLoop().RunUntilIdle();
}
void ResetService() {
scoped_ptr<DeviceManagementService::Configuration> configuration(
new MockDeviceManagementServiceConfiguration(kServiceUrl));
service_.reset(
new DeviceManagementService(configuration.Pass(), request_context_));
}
void InitializeService() {
service_->ScheduleInitialization(0);
base::RunLoop().RunUntilIdle();
}
net::TestURLFetcher* GetFetcher() {
return factory_.GetFetcherByID(DeviceManagementService::kURLFetcherID);
}
DeviceManagementRequestJob* StartRegistrationJob() {
DeviceManagementRequestJob* job =
service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION);
job->SetGaiaToken(kGaiaAuthToken);
job->SetOAuthToken(kOAuthToken);
job->SetClientID(kClientID);
job->GetRequest()->mutable_register_request();
job->SetRetryCallback(base::Bind(
&DeviceManagementServiceTestBase::OnJobRetry, base::Unretained(this)));
job->Start(base::Bind(&DeviceManagementServiceTestBase::OnJobDone,
base::Unretained(this)));
return job;
}
DeviceManagementRequestJob* StartApiAuthCodeFetchJob() {
DeviceManagementRequestJob* job = service_->CreateJob(
DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH);
job->SetGaiaToken(kGaiaAuthToken);
job->SetOAuthToken(kOAuthToken);
job->SetClientID(kClientID);
job->GetRequest()->mutable_service_api_access_request();
job->SetRetryCallback(base::Bind(
&DeviceManagementServiceTestBase::OnJobRetry, base::Unretained(this)));
job->Start(base::Bind(&DeviceManagementServiceTestBase::OnJobDone,
base::Unretained(this)));
return job;
}
DeviceManagementRequestJob* StartUnregistrationJob() {
DeviceManagementRequestJob* job =
service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION);
job->SetDMToken(kDMToken);
job->SetClientID(kClientID);
job->GetRequest()->mutable_unregister_request();
job->SetRetryCallback(base::Bind(
&DeviceManagementServiceTestBase::OnJobRetry, base::Unretained(this)));
job->Start(base::Bind(&DeviceManagementServiceTestBase::OnJobDone,
base::Unretained(this)));
return job;
}
DeviceManagementRequestJob* StartPolicyFetchJob() {
DeviceManagementRequestJob* job =
service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH);
job->SetGaiaToken(kGaiaAuthToken);
job->SetOAuthToken(kOAuthToken);
job->SetClientID(kClientID);
em::PolicyFetchRequest* fetch_request =
job->GetRequest()->mutable_policy_request()->add_request();
fetch_request->set_policy_type(dm_protocol::kChromeUserPolicyType);
job->SetRetryCallback(base::Bind(
&DeviceManagementServiceTestBase::OnJobRetry, base::Unretained(this)));
job->Start(base::Bind(&DeviceManagementServiceTestBase::OnJobDone,
base::Unretained(this)));
return job;
}
DeviceManagementRequestJob* StartAutoEnrollmentJob() {
DeviceManagementRequestJob* job =
service_->CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT);
job->SetClientID(kClientID);
em::DeviceAutoEnrollmentRequest* request =
job->GetRequest()->mutable_auto_enrollment_request();
request->set_modulus(1);
request->set_remainder(0);
job->SetRetryCallback(base::Bind(
&DeviceManagementServiceTestBase::OnJobRetry, base::Unretained(this)));
job->Start(base::Bind(&DeviceManagementServiceTestBase::OnJobDone,
base::Unretained(this)));
return job;
}
void SendResponse(net::TestURLFetcher* fetcher,
const net::URLRequestStatus request_status,
int http_status,
const std::string& response) {
fetcher->set_url(GURL(kServiceUrl));
fetcher->set_status(request_status);
fetcher->set_response_code(http_status);
fetcher->SetResponseString(response);
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
MOCK_METHOD3(OnJobDone, void(DeviceManagementStatus, int,
const em::DeviceManagementResponse&));
MOCK_METHOD1(OnJobRetry, void(DeviceManagementRequestJob*));
base::MessageLoop loop_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
net::TestURLFetcherFactory factory_;
scoped_ptr<DeviceManagementService> service_;
};
struct FailedRequestParams {
FailedRequestParams(DeviceManagementStatus expected_status,
net::URLRequestStatus::Status request_status,
int http_status,
const std::string& response)
: expected_status_(expected_status),
request_status_(request_status, 0),
http_status_(http_status),
response_(response) {}
DeviceManagementStatus expected_status_;
net::URLRequestStatus request_status_;
int http_status_;
std::string response_;
};
void PrintTo(const FailedRequestParams& params, std::ostream* os) {
*os << "FailedRequestParams " << params.expected_status_
<< " " << params.request_status_.status()
<< " " << params.http_status_;
}
// A parameterized test case for erroneous response situations, they're mostly
// the same for all kinds of requests.
class DeviceManagementServiceFailedRequestTest
: public DeviceManagementServiceTestBase,
public testing::WithParamInterface<FailedRequestParams> {
};
TEST_P(DeviceManagementServiceFailedRequestTest, RegisterRequest) {
EXPECT_CALL(*this, OnJobDone(GetParam().expected_status_, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
SendResponse(fetcher, GetParam().request_status_, GetParam().http_status_,
GetParam().response_);
}
TEST_P(DeviceManagementServiceFailedRequestTest, ApiAuthCodeFetchRequest) {
EXPECT_CALL(*this, OnJobDone(GetParam().expected_status_, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(
StartApiAuthCodeFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
SendResponse(fetcher, GetParam().request_status_, GetParam().http_status_,
GetParam().response_);
}
TEST_P(DeviceManagementServiceFailedRequestTest, UnregisterRequest) {
EXPECT_CALL(*this, OnJobDone(GetParam().expected_status_, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartUnregistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
SendResponse(fetcher, GetParam().request_status_, GetParam().http_status_,
GetParam().response_);
}
TEST_P(DeviceManagementServiceFailedRequestTest, PolicyRequest) {
EXPECT_CALL(*this, OnJobDone(GetParam().expected_status_, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartPolicyFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
SendResponse(fetcher, GetParam().request_status_, GetParam().http_status_,
GetParam().response_);
}
TEST_P(DeviceManagementServiceFailedRequestTest, AutoEnrollmentRequest) {
EXPECT_CALL(*this, OnJobDone(GetParam().expected_status_, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartAutoEnrollmentJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
SendResponse(fetcher, GetParam().request_status_, GetParam().http_status_,
GetParam().response_);
}
INSTANTIATE_TEST_CASE_P(
DeviceManagementServiceFailedRequestTestInstance,
DeviceManagementServiceFailedRequestTest,
testing::Values(
FailedRequestParams(
DM_STATUS_REQUEST_FAILED,
net::URLRequestStatus::FAILED,
200,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_HTTP_STATUS_ERROR,
net::URLRequestStatus::SUCCESS,
666,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_RESPONSE_DECODING_ERROR,
net::URLRequestStatus::SUCCESS,
200,
PROTO_STRING("Not a protobuf.")),
FailedRequestParams(
DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED,
net::URLRequestStatus::SUCCESS,
403,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER,
net::URLRequestStatus::SUCCESS,
405,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_DEVICE_ID_CONFLICT,
net::URLRequestStatus::SUCCESS,
409,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_DEVICE_NOT_FOUND,
net::URLRequestStatus::SUCCESS,
410,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID,
net::URLRequestStatus::SUCCESS,
401,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_REQUEST_INVALID,
net::URLRequestStatus::SUCCESS,
400,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_TEMPORARY_UNAVAILABLE,
net::URLRequestStatus::SUCCESS,
404,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_ACTIVATION_PENDING,
net::URLRequestStatus::SUCCESS,
412,
PROTO_STRING(kResponseEmpty)),
FailedRequestParams(
DM_STATUS_SERVICE_MISSING_LICENSES,
net::URLRequestStatus::SUCCESS,
402,
PROTO_STRING(kResponseEmpty))));
// Simple query parameter parser for testing.
class QueryParams {
public:
explicit QueryParams(const std::string& query) {
base::SplitStringIntoKeyValuePairs(query, '=', '&', &params_);
}
bool Check(const std::string& name, const std::string& expected_value) {
bool found = false;
for (ParamMap::const_iterator i(params_.begin()); i != params_.end(); ++i) {
std::string unescaped_name(net::UnescapeURLComponent(
i->first,
net::UnescapeRule::NORMAL |
net::UnescapeRule::SPACES |
net::UnescapeRule::URL_SPECIAL_CHARS |
net::UnescapeRule::CONTROL_CHARS |
net::UnescapeRule::REPLACE_PLUS_WITH_SPACE));
if (unescaped_name == name) {
if (found)
return false;
found = true;
std::string unescaped_value(net::UnescapeURLComponent(
i->second,
net::UnescapeRule::NORMAL |
net::UnescapeRule::SPACES |
net::UnescapeRule::URL_SPECIAL_CHARS |
net::UnescapeRule::CONTROL_CHARS |
net::UnescapeRule::REPLACE_PLUS_WITH_SPACE));
if (unescaped_value != expected_value)
return false;
}
}
return found;
}
private:
typedef std::vector<std::pair<std::string, std::string> > ParamMap;
ParamMap params_;
};
class DeviceManagementServiceTest
: public DeviceManagementServiceTestBase {
protected:
void CheckURLAndQueryParams(const GURL& request_url,
const std::string& request_type,
const std::string& device_id) {
const GURL service_url(kServiceUrl);
EXPECT_EQ(service_url.scheme(), request_url.scheme());
EXPECT_EQ(service_url.host(), request_url.host());
EXPECT_EQ(service_url.port(), request_url.port());
EXPECT_EQ(service_url.path(), request_url.path());
QueryParams query_params(request_url.query());
EXPECT_TRUE(query_params.Check(dm_protocol::kParamRequest, request_type));
EXPECT_TRUE(query_params.Check(dm_protocol::kParamDeviceID, device_id));
EXPECT_TRUE(query_params.Check(dm_protocol::kParamDeviceType,
dm_protocol::kValueDeviceType));
EXPECT_TRUE(query_params.Check(dm_protocol::kParamAppType,
dm_protocol::kValueAppType));
}
};
MATCHER_P(MessageEquals, reference, "") {
std::string reference_data;
std::string arg_data;
return arg.SerializeToString(&arg_data) &&
reference.SerializeToString(&reference_data) &&
arg_data == reference_data;
}
TEST_F(DeviceManagementServiceTest, RegisterRequest) {
em::DeviceManagementResponse expected_response;
expected_response.mutable_register_response()->
set_device_management_token(kDMToken);
EXPECT_CALL(*this, OnJobDone(DM_STATUS_SUCCESS, _,
MessageEquals(expected_response)));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
CheckURLAndQueryParams(fetcher->GetOriginalURL(),
dm_protocol::kValueRequestRegister,
kClientID);
std::string expected_data;
ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
EXPECT_EQ(expected_data, fetcher->upload_data());
// Generate the response.
std::string response_data;
ASSERT_TRUE(expected_response.SerializeToString(&response_data));
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
SendResponse(fetcher, status, 200, response_data);
}
TEST_F(DeviceManagementServiceTest, ApiAuthCodeFetchRequest) {
em::DeviceManagementResponse expected_response;
expected_response.mutable_service_api_access_response()->set_auth_code(
kRobotAuthCode);
EXPECT_CALL(*this, OnJobDone(DM_STATUS_SUCCESS, _,
MessageEquals(expected_response)));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(
StartApiAuthCodeFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
CheckURLAndQueryParams(fetcher->GetOriginalURL(),
dm_protocol::kValueRequestApiAuthorization,
kClientID);
std::string expected_data;
ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
EXPECT_EQ(expected_data, fetcher->upload_data());
// Generate the response.
std::string response_data;
ASSERT_TRUE(expected_response.SerializeToString(&response_data));
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
SendResponse(fetcher, status, 200, response_data);
}
TEST_F(DeviceManagementServiceTest, UnregisterRequest) {
em::DeviceManagementResponse expected_response;
expected_response.mutable_unregister_response();
EXPECT_CALL(*this, OnJobDone(DM_STATUS_SUCCESS, _,
MessageEquals(expected_response)));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartUnregistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// Check the data the fetcher received.
const GURL& request_url(fetcher->GetOriginalURL());
const GURL service_url(kServiceUrl);
EXPECT_EQ(service_url.scheme(), request_url.scheme());
EXPECT_EQ(service_url.host(), request_url.host());
EXPECT_EQ(service_url.port(), request_url.port());
EXPECT_EQ(service_url.path(), request_url.path());
CheckURLAndQueryParams(fetcher->GetOriginalURL(),
dm_protocol::kValueRequestUnregister,
kClientID);
std::string expected_data;
ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
EXPECT_EQ(expected_data, fetcher->upload_data());
// Generate the response.
std::string response_data;
ASSERT_TRUE(expected_response.SerializeToString(&response_data));
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
SendResponse(fetcher, status, 200, response_data);
}
TEST_F(DeviceManagementServiceTest, CancelRegisterRequest) {
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// There shouldn't be any callbacks.
request_job.reset();
}
TEST_F(DeviceManagementServiceTest, CancelApiAuthCodeFetch) {
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(
StartApiAuthCodeFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// There shouldn't be any callbacks.
request_job.reset();
}
TEST_F(DeviceManagementServiceTest, CancelUnregisterRequest) {
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartUnregistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// There shouldn't be any callbacks.
request_job.reset();
}
TEST_F(DeviceManagementServiceTest, CancelPolicyRequest) {
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartPolicyFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// There shouldn't be any callbacks.
request_job.reset();
}
TEST_F(DeviceManagementServiceTest, JobQueueing) {
// Start with a non-initialized service.
ResetService();
em::DeviceManagementResponse expected_response;
expected_response.mutable_register_response()->
set_device_management_token(kDMToken);
EXPECT_CALL(*this, OnJobDone(DM_STATUS_SUCCESS, _,
MessageEquals(expected_response)));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
// Make a request. We should not see any fetchers being created.
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_FALSE(fetcher);
// Now initialize the service. That should start the job.
InitializeService();
fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
factory_.RemoveFetcherFromMap(DeviceManagementService::kURLFetcherID);
// Check that the request is processed as expected.
std::string response_data;
ASSERT_TRUE(expected_response.SerializeToString(&response_data));
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
SendResponse(fetcher, status, 200, response_data);
}
TEST_F(DeviceManagementServiceTest, CancelRequestAfterShutdown) {
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
scoped_ptr<DeviceManagementRequestJob> request_job(StartPolicyFetchJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
// Shutdown the service and cancel the job afterwards.
service_->Shutdown();
request_job.reset();
}
ACTION_P(ResetPointer, pointer) {
pointer->reset();
}
TEST_F(DeviceManagementServiceTest, CancelDuringCallback) {
// Make a request.
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_CALL(*this, OnJobDone(_, _, _))
.WillOnce(ResetPointer(&request_job));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
// Generate a callback.
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
SendResponse(fetcher, status, 500, std::string());
// Job should have been reset.
EXPECT_FALSE(request_job.get());
}
TEST_F(DeviceManagementServiceTest, RetryOnProxyError) {
// Make a request.
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_));
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0);
const GURL original_url(fetcher->GetOriginalURL());
const std::string upload_data(fetcher->upload_data());
// Generate a callback with a proxy failure.
net::URLRequestStatus status(net::URLRequestStatus::FAILED,
net::ERR_PROXY_CONNECTION_FAILED);
SendResponse(fetcher, status, 200, std::string());
// Verify that a new URLFetcher was started that bypasses the proxy.
fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_TRUE(fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY);
EXPECT_EQ(original_url, fetcher->GetOriginalURL());
EXPECT_EQ(upload_data, fetcher->upload_data());
}
TEST_F(DeviceManagementServiceTest, RetryOnBadResponseFromProxy) {
// Make a request.
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_));
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0);
const GURL original_url(fetcher->GetOriginalURL());
const std::string upload_data(fetcher->upload_data());
fetcher->set_was_fetched_via_proxy(true);
scoped_refptr<net::HttpResponseHeaders> headers;
headers = new net::HttpResponseHeaders(
"HTTP/1.1 200 OK\0Content-type: bad/type\0\0");
fetcher->set_response_headers(headers);
// Generate a callback with a valid http response, that was generated by
// a bad/wrong proxy.
net::URLRequestStatus status;
SendResponse(fetcher, status, 200, std::string());
// Verify that a new URLFetcher was started that bypasses the proxy.
fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0);
EXPECT_EQ(original_url, fetcher->GetOriginalURL());
EXPECT_EQ(upload_data, fetcher->upload_data());
}
TEST_F(DeviceManagementServiceTest, RetryOnNetworkChanges) {
// Make a request.
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_));
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
const GURL original_url(fetcher->GetOriginalURL());
const std::string original_upload_data(fetcher->upload_data());
// Make it fail with ERR_NETWORK_CHANGED.
fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_NETWORK_CHANGED));
fetcher->set_url(GURL(kServiceUrl));
fetcher->delegate()->OnURLFetchComplete(fetcher);
// Verify that a new URLFetcher was started that retries this job, after
// having called OnJobRetry.
Mock::VerifyAndClearExpectations(this);
fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_EQ(original_url, fetcher->GetOriginalURL());
EXPECT_EQ(original_upload_data, fetcher->upload_data());
EXPECT_EQ(net::URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
}
TEST_F(DeviceManagementServiceTest, RetryLimit) {
scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob());
// Simulate 3 failed network requests.
for (int i = 0; i < 3; ++i) {
// Make the current fetcher fail with ERR_NETWORK_CHANGED.
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_CALL(*this, OnJobDone(_, _, _)).Times(0);
EXPECT_CALL(*this, OnJobRetry(_));
fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_NETWORK_CHANGED));
fetcher->set_url(GURL(kServiceUrl));
fetcher->delegate()->OnURLFetchComplete(fetcher);
Mock::VerifyAndClearExpectations(this);
}
// At the next failure the DeviceManagementService should give up retrying and
// pass the error code to the job's owner.
net::TestURLFetcher* fetcher = GetFetcher();
ASSERT_TRUE(fetcher);
EXPECT_CALL(*this, OnJobDone(DM_STATUS_REQUEST_FAILED, _, _));
EXPECT_CALL(*this, OnJobRetry(_)).Times(0);
fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_NETWORK_CHANGED));
fetcher->set_url(GURL(kServiceUrl));
fetcher->delegate()->OnURLFetchComplete(fetcher);
Mock::VerifyAndClearExpectations(this);
}
} // namespace policy