blob: 93d1fa1a67e68b3812d9650ae4198c6620d6ea7b [file] [log] [blame]
// Copyright 2014 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 "chromeos/services/device_sync/cryptauth_api_call_flow.h"
#include <memory>
#include "base/bind.h"
#include "base/macros.h"
#include "base/test/scoped_task_environment.h"
#include "chromeos/services/device_sync/network_request_error.h"
#include "net/base/net_errors.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace device_sync {
namespace {
const char kSerializedRequestProto[] = "serialized_request_proto";
const char kSerializedResponseProto[] = "result_proto";
const char kRequestUrl[] = "https://googleapis.com/cryptauth/test";
} // namespace
class DeviceSyncCryptAuthApiCallFlowTest : public testing::Test {
protected:
DeviceSyncCryptAuthApiCallFlowTest()
: shared_factory_(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_)) {
flow_.SetPartialNetworkTrafficAnnotation(
PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
}
void StartApiCallFlow() {
StartApiCallFlowWithRequest(kSerializedRequestProto);
}
void StartApiCallFlowWithRequest(const std::string& serialized_request) {
flow_.Start(GURL(kRequestUrl), shared_factory_, "access_token",
serialized_request,
base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnResult,
base::Unretained(this)),
base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnError,
base::Unretained(this)));
// A pending fetch for the API request should be created.
CheckCryptAuthHttpRequest(serialized_request);
}
void OnResult(const std::string& result) {
EXPECT_FALSE(result_ || network_error_);
result_.reset(new std::string(result));
}
void OnError(NetworkRequestError network_error) {
EXPECT_FALSE(result_ || network_error_);
network_error_.reset(new NetworkRequestError(network_error));
}
void CheckCryptAuthHttpRequest(const std::string& serialized_request) {
const std::vector<network::TestURLLoaderFactory::PendingRequest>& pending =
*test_url_loader_factory_.pending_requests();
ASSERT_EQ(1u, pending.size());
const network::ResourceRequest& request = pending[0].request;
EXPECT_EQ(GURL(kRequestUrl), request.url);
EXPECT_EQ(serialized_request, network::GetUploadData(request));
std::string content_type;
EXPECT_TRUE(request.headers.GetHeader(net::HttpRequestHeaders::kContentType,
&content_type));
EXPECT_EQ("application/x-protobuf", content_type);
}
// Responds to the current HTTP request. If the |error| is not |net::OK|, then
// the |response_code| and |response_string| arguments will be ignored.
void CompleteCurrentRequest(net::Error error,
int response_code,
const std::string& response_string) {
network::URLLoaderCompletionStatus completion_status(error);
network::ResourceResponseHead response_head;
std::string content;
if (error == net::OK) {
response_head = network::CreateResourceResponseHead(
static_cast<net::HttpStatusCode>(response_code));
content = response_string;
}
EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
GURL(kRequestUrl), completion_status, response_head, content));
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(result_ || network_error_);
}
std::unique_ptr<std::string> result_;
std::unique_ptr<NetworkRequestError> network_error_;
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
CryptAuthApiCallFlow flow_;
DISALLOW_COPY_AND_ASSIGN(DeviceSyncCryptAuthApiCallFlowTest);
};
TEST_F(DeviceSyncCryptAuthApiCallFlowTest, RequestSuccess) {
StartApiCallFlow();
CompleteCurrentRequest(net::OK, net::HTTP_OK, kSerializedResponseProto);
EXPECT_EQ(kSerializedResponseProto, *result_);
EXPECT_FALSE(network_error_);
}
TEST_F(DeviceSyncCryptAuthApiCallFlowTest, RequestFailure) {
StartApiCallFlow();
CompleteCurrentRequest(net::ERR_FAILED, 0, std::string());
EXPECT_FALSE(result_);
EXPECT_EQ(NetworkRequestError::kOffline, *network_error_);
}
TEST_F(DeviceSyncCryptAuthApiCallFlowTest, RequestStatus500) {
StartApiCallFlow();
CompleteCurrentRequest(net::OK, net::HTTP_INTERNAL_SERVER_ERROR,
"CryptAuth Meltdown.");
EXPECT_FALSE(result_);
EXPECT_EQ(NetworkRequestError::kInternalServerError, *network_error_);
}
// The empty string is a valid protocol buffer message serialization.
TEST_F(DeviceSyncCryptAuthApiCallFlowTest, RequestWithNoBody) {
StartApiCallFlowWithRequest(std::string());
CompleteCurrentRequest(net::OK, net::HTTP_OK, kSerializedResponseProto);
EXPECT_EQ(kSerializedResponseProto, *result_);
EXPECT_FALSE(network_error_);
}
// The empty string is a valid protocol buffer message serialization.
TEST_F(DeviceSyncCryptAuthApiCallFlowTest, ResponseWithNoBody) {
StartApiCallFlow();
CompleteCurrentRequest(net::OK, net::HTTP_OK, std::string());
EXPECT_EQ(std::string(), *result_);
EXPECT_FALSE(network_error_);
}
} // namespace device_sync
} // namespace chromeos