blob: 5cca8cbf2b72e17f55aac453769772f03f89ae18 [file] [log] [blame]
// Copyright 2015 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/history/core/test/fake_web_history_service.h"
#include <stdint.h>
#include <algorithm>
#include <memory>
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "components/sync/protocol/history_status.pb.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace history {
// FakeRequest -----------------------------------------------------------------
namespace {
// TODO(msramek): Find a way to keep these URLs in sync with what is used
// in WebHistoryService.
const char kLookupUrl[] = "https://history.google.com/history/api/lookup";
const char kDeleteUrl[] = "https://history.google.com/history/api/delete";
const char kChromeClient[] = "chrome";
const char kWebAndAppClient[] = "web_app";
const char kSyncServerHost[] = "clients4.google.com";
} // namespace
class FakeWebHistoryService::FakeRequest : public WebHistoryService::Request {
public:
FakeRequest(FakeWebHistoryService* service,
const GURL& url,
bool emulate_success,
int emulate_response_code,
const WebHistoryService::CompletionCallback& callback,
base::Time begin,
base::Time end,
int max_count);
// WebHistoryService::Request implementation.
bool IsPending() override;
int GetResponseCode() override;
const std::string& GetResponseBody() override;
void SetPostData(const std::string& post_data) override;
void SetPostDataAndType(const std::string& post_data,
const std::string& mime_type) override;
void SetUserAgent(const std::string& user_agent) override;
void Start() override;
private:
FakeWebHistoryService* service_;
GURL url_;
bool emulate_success_;
int emulate_response_code_;
const WebHistoryService::CompletionCallback& callback_;
base::Time begin_;
base::Time end_;
int max_count_;
bool is_pending_;
std::string response_body_;
DISALLOW_COPY_AND_ASSIGN(FakeRequest);
};
FakeWebHistoryService::FakeRequest::FakeRequest(
FakeWebHistoryService* service,
const GURL& url,
bool emulate_success,
int emulate_response_code,
const WebHistoryService::CompletionCallback& callback,
base::Time begin,
base::Time end,
int max_count)
: service_(service),
url_(url),
emulate_success_(emulate_success),
emulate_response_code_(emulate_response_code),
callback_(callback),
begin_(begin),
end_(end),
max_count_(max_count),
is_pending_(false) {}
bool FakeWebHistoryService::FakeRequest::IsPending() {
return is_pending_;
}
int FakeWebHistoryService::FakeRequest::GetResponseCode() {
return emulate_response_code_;
}
const std::string& FakeWebHistoryService::FakeRequest::GetResponseBody() {
std::string client;
net::GetValueForKeyInQuery(url_, "client", &client);
GURL::Replacements remove_query;
remove_query.ClearQuery();
GURL base_url = url_.ReplaceComponents(remove_query);
if (base_url == kLookupUrl && client == kChromeClient) {
// History query.
response_body_ = "{ \"event\": [";
bool more_results_left;
auto visits = service_->GetVisitsBetween(begin_, end_, max_count_,
&more_results_left);
std::vector<std::string> results;
for (const FakeWebHistoryService::Visit& visit : visits) {
std::string unix_time = std::to_string(
(visit.second - base::Time::UnixEpoch()).InMicroseconds());
results.push_back(
base::StringPrintf("{\"result\":[{\"id\":[{\"timestamp_usec\":\"%s\"}"
"],\"url\":\"%s\"}]}",
unix_time.c_str(), visit.first.c_str()));
}
response_body_ += base::JoinString(results, ",");
response_body_ +=
base::StringPrintf("], \"continuation_token\":\"%s\" }",
(more_results_left ? "more_results_left" : ""));
} else if (base_url == kDeleteUrl && client == kChromeClient) {
// Deletion query.
response_body_ = "{ \"just needs to be\" : \"a valid JSON.\" }";
} else if (base_url == kLookupUrl && client == kWebAndAppClient) {
// Web and app activity query.
response_body_ = base::StringPrintf(
"{ \"history_recording_enabled\": %s }",
service_->IsWebAndAppActivityEnabled() ? "true" : "false");
} else if (url_.host() == kSyncServerHost) {
// Other forms of browsing history query.
std::unique_ptr<sync_pb::HistoryStatusResponse> history_status(
new sync_pb::HistoryStatusResponse());
history_status->set_has_derived_data(
service_->AreOtherFormsOfBrowsingHistoryPresent());
history_status->SerializeToString(&response_body_);
}
return response_body_;
}
void FakeWebHistoryService::FakeRequest::SetPostData(
const std::string& post_data) {
// Unused.
}
void FakeWebHistoryService::FakeRequest::SetPostDataAndType(
const std::string& post_data,
const std::string& mime_type) {
// Unused.
}
void FakeWebHistoryService::FakeRequest::SetUserAgent(
const std::string& user_agent) {
// Unused.
}
void FakeWebHistoryService::FakeRequest::Start() {
is_pending_ = true;
callback_.Run(this, emulate_success_);
}
// FakeWebHistoryService -------------------------------------------------------
FakeWebHistoryService::FakeWebHistoryService()
// NOTE: Simply pass null object for IdentityManager. WebHistoryService's
// only usage of this object is to fetch access tokens via RequestImpl, and
// FakeWebHistoryService deliberately replaces this flow with
// FakeWebHistoryService::FakeRequest.
: history::WebHistoryService(nullptr, nullptr),
emulate_success_(true),
emulate_response_code_(net::HTTP_OK),
web_and_app_activity_enabled_(false),
other_forms_of_browsing_history_present_(false) {}
FakeWebHistoryService::~FakeWebHistoryService() {
}
void FakeWebHistoryService::SetupFakeResponse(
bool emulate_success, int emulate_response_code) {
emulate_success_ = emulate_success;
emulate_response_code_ = emulate_response_code;
}
void FakeWebHistoryService::AddSyncedVisit(
std::string url, base::Time timestamp) {
visits_.push_back(make_pair(url, timestamp));
}
void FakeWebHistoryService::ClearSyncedVisits() {
visits_.clear();
}
std::vector<FakeWebHistoryService::Visit>
FakeWebHistoryService::GetVisitsBetween(base::Time begin,
base::Time end,
size_t count,
bool* more_results_left) {
// Make sure that |visits_| is sorted in reverse chronological order before we
// return anything. This means that the most recent results are returned
// first.
std::sort(visits_.begin(), visits_.end(),
[](const Visit& lhs, const Visit rhs) -> bool {
return lhs.second > rhs.second;
});
*more_results_left = false;
std::vector<Visit> result;
for (const Visit& visit : visits_) {
// |begin| is inclusive, |end| is exclusive.
if (visit.second >= begin && visit.second < end) {
// We found another valid result, but cannot return it because we've
// reached max count.
if (count > 0 && result.size() >= count) {
*more_results_left = true;
break;
}
result.push_back(visit);
}
}
return result;
}
base::Time FakeWebHistoryService::GetTimeForKeyInQuery(
const GURL& url, const std::string& key) {
std::string value;
if (!net::GetValueForKeyInQuery(url, key, &value))
return base::Time();
int64_t us;
if (!base::StringToInt64(value, &us))
return base::Time();
return base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(us);
}
FakeWebHistoryService::Request* FakeWebHistoryService::CreateRequest(
const GURL& url,
const CompletionCallback& callback,
const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
// Find the time range endpoints in the URL.
base::Time begin = GetTimeForKeyInQuery(url, "min");
base::Time end = GetTimeForKeyInQuery(url, "max");
if (end.is_null())
end = base::Time::Max();
int max_count = 0;
std::string max_count_str;
if (net::GetValueForKeyInQuery(url, "num", &max_count_str))
base::StringToInt(max_count_str, &max_count);
return new FakeRequest(this, url, emulate_success_, emulate_response_code_,
callback, begin, end, max_count);
}
bool FakeWebHistoryService::IsWebAndAppActivityEnabled() {
return web_and_app_activity_enabled_;
}
void FakeWebHistoryService::SetWebAndAppActivityEnabled(bool enabled) {
web_and_app_activity_enabled_ = enabled;
}
bool FakeWebHistoryService::AreOtherFormsOfBrowsingHistoryPresent() {
return other_forms_of_browsing_history_present_;
}
void FakeWebHistoryService::SetOtherFormsOfBrowsingHistoryPresent(
bool present) {
other_forms_of_browsing_history_present_ = present;
}
} // namespace history