blob: 773cc7793dac58f331be0e280ba648b187816da8 [file] [log] [blame]
// Copyright 2018 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 "components/journey/journey_info_fetcher.h"
#include <utility>
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
#include "net/http/http_util.h"
#include "services/data_decoder/public/cpp/testing_json_parser.h"
#include "services/identity/public/cpp/identity_test_environment.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace journey {
const char kEmail[] = "foo_email";
const char kJourneyServer[] =
"https://chrome-memex-dev.appspot.com/api/journey_from_pageload";
const char kEmptyErrorString[] = "";
const std::vector<int64_t> kTimestamps = {1532563271195406};
using MockFetchResponseAvailableCallback =
base::MockCallback<FetchResponseAvailableCallback>;
class JourneyInfoFetcherTest : public testing::Test {
protected:
JourneyInfoFetcherTest() {}
~JourneyInfoFetcherTest() override {}
void SetUp() override {
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
journey_info_fetcher_ = std::make_unique<JourneyInfoFetcher>(
identity_test_env_.identity_manager(), test_shared_loader_factory);
SignIn();
}
void TearDown() override {}
void SignIn() {
identity_test_env_.MakePrimaryAccountAvailable(kEmail);
identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
}
void SignOut() { identity_test_env_.ClearPrimaryAccount(); }
std::string GenerateJsonResponse(const std::vector<int64_t>& timestamps) {
int timestamps_size = timestamps.size();
std::string response_string = R"(
[
{
"status": "STATUS_OK",
"default_autotabs": {
"pageloads": [
{
"title": {
"weight": 1.0,
"title": "foo"
},
"url": "https://foo.com/",
"image": {
"snippet": "PRS_REPRESENTATIVE_IMAGE",
"confidence": 1.0,
"thumbnail_url": "https://foo-png"
},
"timestamp_us": "1532563271195406",
"is_pruned": false
}
],
"selection_type": "SELECTION_TYPE_LEAVES_AND_TAB_AND_TASK"
},
"journey_id": "3021296114337328326",
"source_page_timestamp_usec": [
)";
for (int i = 0; i < timestamps_size; i++) {
response_string += "\"" + base::NumberToString(timestamps[i]) + "\"";
if (i < timestamps_size - 1)
response_string += ", ";
}
response_string += R"(
]
}
]
)";
return response_string;
}
void SetFakeResponse(const GURL& request_url,
const std::string& response_data,
net::HttpStatusCode response_code,
net::Error error) {
network::ResourceResponseHead head;
std::string headers(base::StringPrintf(
"HTTP/1.1 %d %s\nContent-type: application/json\n\n",
static_cast<int>(response_code), GetHttpReasonPhrase(response_code)));
head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers));
head.mime_type = "application/json";
network::URLLoaderCompletionStatus status(error);
status.decoded_body_length = response_data.size();
test_url_loader_factory_.AddResponse(request_url, head, response_data,
status);
}
void SendAndAwaitResponse(std::vector<int64_t> timestamps) {
journey_info_fetcher()->FetchJourneyInfo(
timestamps, journey_info_available_callback().Get());
base::RunLoop().RunUntilIdle();
}
MockFetchResponseAvailableCallback& journey_info_available_callback() {
return mock_callback_;
}
JourneyInfoFetcher* journey_info_fetcher() {
return journey_info_fetcher_.get();
}
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
}
identity::IdentityTestEnvironment& identity_test_env() {
return identity_test_env_;
}
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
identity::IdentityTestEnvironment identity_test_env_;
MockFetchResponseAvailableCallback mock_callback_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<JourneyInfoFetcher> journey_info_fetcher_;
DISALLOW_COPY_AND_ASSIGN(JourneyInfoFetcherTest);
};
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfo) {
std::string json_response_string = GenerateJsonResponse(kTimestamps);
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(testing::NotNull(), kEmptyErrorString));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoOAuthError) {
identity_test_env().SetAutomaticIssueOfAccessTokens(false);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
journey_info_fetcher()->FetchJourneyInfo(
kTimestamps, journey_info_available_callback().Get());
identity_test_env().WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
base::RunLoop().RunUntilIdle();
}
#if !defined(OS_CHROMEOS)
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoUserNotSignedIn) {
SignOut();
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
#endif
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithNonParsableResponse) {
std::string json_response_string = "[";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithBadJSONResponse) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(testing::NotNull(), kEmptyErrorString));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoNetworkError) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::ERR_FAILED);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoHttpError) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string,
net::HTTP_BAD_REQUEST, net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
} // namespace journey