blob: e2a8f8e7122b4bcf77bbe441f21d5f09021fb56b [file] [log] [blame]
// Copyright 2020 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/search/repeatable_queries/repeatable_queries_service.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/files/scoped_temp_dir.h"
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/test/test_bookmark_client.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/url_database.h"
#include "components/history/core/test/history_service_test_util.h"
#include "components/omnibox/browser/in_memory_url_index.h"
#include "components/omnibox/browser/in_memory_url_index_test_util.h"
#include "components/search/search.h"
#include "components/search/search_provider_observer.h"
#include "components/search_engines/search_engines_test_util.h"
#include "components/search_engines/template_url_service.h"
#include "components/signin/public/base/test_signin_client.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
using base::TimeDelta;
namespace {
std::string GoodServerResponse() {
return R"()]}'
[
"",
[
"server query 1",
"server query 2",
"server query 3"
],
[],
[],
{
"google:suggestdetail":[
{
"du":"/delete?server+query+1"
},
{
"du":"/delete?server+query+2"
},
{
"du":"/delete?server+query+3"
}
]
}
])";
}
std::string BadServerResponse1() {
return R"()]}'
[
"",
[
"server query 1",
"server query 2",
"server query 3"
],
[],
[],
{
}
])";
}
std::string BadServerResponse2() {
return R"()]}'
[
"",
[
"server query 1",
"server query 2",
"server query 3"
],
[],
[],
{
"google:suggestdetail":[
{
"du":"/delete?server+query+1"
},
{
"du":"/delete?server+query+2"
},
]
}
])";
}
// Used to populate the URLDatabase.
struct TestURLData {
const TemplateURL* search_provider;
std::string search_terms;
int age_in_seconds;
int visit_count = 1;
std::string title = "";
int typed_count = 1;
bool hidden = false;
};
} // namespace
class MockSearchProviderObserver : public SearchProviderObserver {
public:
MockSearchProviderObserver()
: SearchProviderObserver(/*template_url_service=*/nullptr,
base::DoNothing::Repeatedly()) {}
~MockSearchProviderObserver() override = default;
MOCK_METHOD0(is_google, bool());
};
class TestRepeatableQueriesService : public RepeatableQueriesService {
public:
TestRepeatableQueriesService(
signin::IdentityManager* identity_manager,
history::HistoryService* history_service,
TemplateURLService* template_url_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& request_initiator_url)
: RepeatableQueriesService(identity_manager,
history_service,
template_url_service,
std::move(url_loader_factory),
request_initiator_url) {}
~TestRepeatableQueriesService() override = default;
MockSearchProviderObserver* search_provider_observer() override {
return &search_provider_observer_;
}
void SearchProviderChanged() {
RepeatableQueriesService::SearchProviderChanged();
}
void SigninStatusChanged() {
RepeatableQueriesService::SigninStatusChanged();
}
void FlushForTesting(base::OnceClosure flushed) {
RepeatableQueriesService::FlushForTesting(std::move(flushed));
}
GURL GetQueryDestinationURL(const base::string16& query,
const TemplateURL* search_provider) {
return RepeatableQueriesService::GetQueryDestinationURL(query,
search_provider);
}
GURL GetQueryDeletionURL(const std::string& deletion_url) {
return RepeatableQueriesService::GetQueryDeletionURL(deletion_url);
}
GURL GetRequestURL() { return RepeatableQueriesService::GetRequestURL(); }
testing::NiceMock<MockSearchProviderObserver> search_provider_observer_;
};
class RepeatableQueriesServiceTest : public ::testing::Test,
public RepeatableQueriesServiceObserver {
public:
RepeatableQueriesServiceTest() = default;
~RepeatableQueriesServiceTest() override = default;
void SetUp() override {
bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
CHECK(history_dir_.CreateUniqueTempDir());
history_service_ = history::CreateHistoryService(
history_dir_.GetPath(), /*create_history_db=*/true);
in_memory_url_index_ = std::make_unique<InMemoryURLIndex>(
bookmark_model_.get(), history_service_.get(), nullptr,
history_dir_.GetPath(), SchemeSet());
in_memory_url_index_->Init();
template_url_service_ = std::make_unique<TemplateURLService>(nullptr, 0);
// Add the fallback default search provider to the TemplateURLService so
// that it gets a valid unique identifier. Make the newly added provider the
// user selected default search provider.
TemplateURL* default_provider = template_url_service_->Add(
std::make_unique<TemplateURL>(default_search_provider()->data()));
template_url_service_->SetUserSelectedDefaultSearchProvider(
default_provider);
// Verify that Google is the default search provider.
EXPECT_TRUE(
search::DefaultSearchProviderIsGoogle(template_url_service_.get()));
identity_env_ = std::make_unique<signin::IdentityTestEnvironment>(
&test_url_loader_factory_);
identity_env_->MakePrimaryAccountAvailable("example@gmail.com");
identity_env_->SetAutomaticIssueOfAccessTokens(true);
service_ = std::make_unique<TestRepeatableQueriesService>(
identity_env_->identity_manager(), history_service_.get(),
template_url_service_.get(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
GURL());
EXPECT_TRUE(service_->repeatable_queries().empty());
service_->AddObserver(this);
}
void TearDown() override {
// RepeatableQueriesService must be explicitly shut down so that its
// observers can unregister.
service_->Shutdown();
// InMemoryURLIndex must be explicitly shut down or it will DCHECK() in
// its destructor.
in_memory_url_index_->Shutdown();
WaitForRepeatableQueriesService();
WaitForHistoryService();
WaitForInMemoryURLIndex();
}
const TemplateURL* default_search_provider() {
return template_url_service_->GetDefaultSearchProvider();
}
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
}
TestRepeatableQueriesService* service() { return service_.get(); }
void set_service_is_done(bool is_done) { service_is_done_ = is_done; }
void SignIn() {
AccountInfo account_info =
identity_env_->MakeAccountAvailable("test@email.com");
identity_env_->SetCookieAccounts({{account_info.email, account_info.gaia}});
}
void SignOut() { identity_env_->SetCookieAccounts({}); }
GURL GetQueryDestinationURL(const std::string& query) {
return service_->GetQueryDestinationURL(base::ASCIIToUTF16(query),
default_search_provider());
}
void RefreshAndMaybeWaitForService() {
service_is_done_ = false;
service_->Refresh();
MaybeWaitForService();
}
void MaybeWaitForService() {
if (!service_is_done_) {
service_run_loop_ = std::make_unique<base::RunLoop>();
// Quits in OnRepeatableQueriesUpdated when the service is done.
service_run_loop_->Run();
}
}
// Fills the URLDatabase with search URLs created using the provided data.
void FillURLDatabase(const std::vector<TestURLData>& url_data_list) {
const Time now = Time::Now();
for (const auto& entry : url_data_list) {
TemplateURLRef::SearchTermsArgs search_terms_args(
base::UTF8ToUTF16(entry.search_terms));
const auto& search_terms_data =
template_url_service_->search_terms_data();
std::string search_url =
entry.search_provider->url_ref().ReplaceSearchTerms(
search_terms_args, search_terms_data);
history_service_->AddPageWithDetails(
GURL(search_url), base::UTF8ToUTF16(entry.title), entry.visit_count,
entry.typed_count, now - TimeDelta::FromSeconds(entry.age_in_seconds),
entry.hidden, history::SOURCE_BROWSED);
history_service_->SetKeywordSearchTermsForURL(
GURL(search_url), entry.search_provider->id(),
base::UTF8ToUTF16(entry.search_terms));
WaitForHistoryService();
}
}
// Waits for RepeatableQueriesService's async operations.
void WaitForRepeatableQueriesService() {
base::RunLoop run_loop;
service_->FlushForTesting(run_loop.QuitClosure());
run_loop.Run();
}
// Waits for history::HistoryService's async operations.
void WaitForHistoryService() {
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
}
// Waits for InMemoryURLIndex's async operations.
void WaitForInMemoryURLIndex() {
BlockUntilInMemoryURLIndexIsRefreshed(in_memory_url_index_.get());
}
private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::RunLoop> service_run_loop_;
std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
std::unique_ptr<history::HistoryService> history_service_;
std::unique_ptr<InMemoryURLIndex> in_memory_url_index_;
base::ScopedTempDir history_dir_;
std::unique_ptr<TemplateURLService> template_url_service_;
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<signin::IdentityTestEnvironment> identity_env_;
std::unique_ptr<TestRepeatableQueriesService> service_;
bool service_is_done_ = false;
// RepeatableQueriesServiceObserver
void OnRepeatableQueriesUpdated() override;
void OnRepeatableQueriesServiceShuttingDown() override;
};
void RepeatableQueriesServiceTest::OnRepeatableQueriesUpdated() {
service_is_done_ = true;
if (service_run_loop_) {
service_run_loop_->Quit();
}
}
void RepeatableQueriesServiceTest::OnRepeatableQueriesServiceShuttingDown() {
service_->RemoveObserver(this);
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn DISABLED_SignedIn
#else
#define MAYBE_SignedIn SignedIn
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedIn) {
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillOnce(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
// The first two server suggestions are kept as repeatable queries.
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn_BadResponse DISABLED_SignedIn_BadResponse
#else
#define MAYBE_SignedIn_BadResponse SignedIn_BadResponse
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedIn_BadResponse) {
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
BadServerResponse1());
// Request a refresh.
RefreshAndMaybeWaitForService();
// Cached data is cleared.
EXPECT_TRUE(service()->repeatable_queries().empty());
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
BadServerResponse2());
// Request a refresh.
RefreshAndMaybeWaitForService();
// Cached data is still empty.
EXPECT_TRUE(service()->repeatable_queries().empty());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn_ErrorResponse DISABLED_SignedIn_ErrorResponse
#else
#define MAYBE_SignedIn_ErrorResponse SignedIn_ErrorResponse
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedIn_ErrorResponse) {
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
test_url_loader_factory()->AddResponse(
service()->GetRequestURL(), network::mojom::URLResponseHead::New(),
std::string(), network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
// Request a refresh.
RefreshAndMaybeWaitForService();
// Cached data is kept.
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn_DefaultSearchProviderChanged \
DISABLED_SignedIn_DefaultSearchProviderChanged
#else
#define MAYBE_SignedIn_DefaultSearchProviderChanged \
SignedIn_DefaultSearchProviderChanged
#endif
TEST_F(RepeatableQueriesServiceTest,
MAYBE_SignedIn_DefaultSearchProviderChanged) {
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillOnce(testing::Return(true))
.WillOnce(testing::Return(false));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
set_service_is_done(false);
// Simulate DSP change. Requests a refresh.
service()->SearchProviderChanged();
MaybeWaitForService();
// Cached data is cleared.
EXPECT_TRUE(service()->repeatable_queries().empty());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn_SigninStatusChanged DISABLED_SignedIn_SigninStatusChanged
#else
#define MAYBE_SignedIn_SigninStatusChanged SignedIn_SigninStatusChanged
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedIn_SigninStatusChanged) {
base::HistogramTester histogram_tester;
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
int original_query_age =
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
FillURLDatabase({
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/0},
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/1},
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/original_query_age},
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/original_query_age},
});
set_service_is_done(false);
SignOut(); // Requests a refresh.
MaybeWaitForService();
// Cached data is updated to local results.
std::vector<RepeatableQuery> expected_local_queries{
{base::ASCIIToUTF16("more recent local query"),
GetQueryDestinationURL("more recent local query"), ""},
{base::ASCIIToUTF16("less recent local query"),
GetQueryDestinationURL("less recent local query"), ""}};
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
histogram_tester.ExpectTotalCount(
RepeatableQueriesService::kExtractionDurationHistogram, 1);
histogram_tester.ExpectTotalCount(
RepeatableQueriesService::kExtractedCountHistogram, 1);
histogram_tester.ExpectUniqueSample(
RepeatableQueriesService::kExtractedCountHistogram, 2, 1);
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedIn_Deletion DISABLED_SignedIn_Deletion
#else
#define MAYBE_SignedIn_Deletion SignedIn_Deletion
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedIn_Deletion) {
SignIn();
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
// Try to delete a query suggestion not provided by the service.
set_service_is_done(false);
service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
// No request to delete the suggestion was sent.
EXPECT_TRUE(test_url_loader_factory()->pending_requests()->empty());
MaybeWaitForService();
// Suggestions should not change.
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
// Delete the query suggestion provided by the service.
set_service_is_done(false);
service()->DeleteQueryWithDestinationURL(
GetQueryDestinationURL("server query 1"));
// A request to delete the suggestion was sent.
EXPECT_EQ(1u, test_url_loader_factory()->pending_requests()->size());
EXPECT_EQ(test_url_loader_factory()->GetPendingRequest(0)->request.url,
service()->GetQueryDeletionURL("/delete?server+query+1"));
MaybeWaitForService();
expected_server_queries = {{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"),
"/delete?server+query+2"}};
// The deleted suggestion is not offered anymore.
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
expected_server_queries = {
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"},
{base::ASCIIToUTF16("server query 3"),
GetQueryDestinationURL("server query 3"), "/delete?server+query+3"}};
// Request a refresh.
RefreshAndMaybeWaitForService();
// The deleted suggestion will not be offered again.
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
}
// TODO(crbug.com/1151909) Test fails on iOS simulators
#if defined(OS_IOS)
#define MAYBE_SignedOut_DefaultSearchProviderChanged \
DISABLED_SignedOut_DefaultSearchProviderChanged
#else
#define MAYBE_SignedOut_DefaultSearchProviderChanged \
SignedOut_DefaultSearchProviderChanged
#endif
TEST_F(RepeatableQueriesServiceTest,
MAYBE_SignedOut_DefaultSearchProviderChanged) {
int original_query_age =
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
FillURLDatabase({
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/0},
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/1},
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/original_query_age},
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/original_query_age},
});
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillOnce(testing::Return(true))
.WillOnce(testing::Return(false));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_local_queries{
{base::ASCIIToUTF16("more recent local query"),
GetQueryDestinationURL("more recent local query"), ""},
{base::ASCIIToUTF16("less recent local query"),
GetQueryDestinationURL("less recent local query"), ""}};
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
set_service_is_done(false);
// Simulate DSP change. Requests a refresh.
service()->SearchProviderChanged();
MaybeWaitForService();
// Cached data is cleared.
EXPECT_TRUE(service()->repeatable_queries().empty());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedOut_SigninStatusChanged \
DISABLED_SignedOut_SigninStatusChanged
#else
#define MAYBE_SignedOut_SigninStatusChanged SignedOut_SigninStatusChanged
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedOut_SigninStatusChanged) {
int original_query_age =
history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
FillURLDatabase({
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/0},
// Issued far enough from the original query; won't be ignored:
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/1},
{default_search_provider(), "less recent local query",
/*age_in_seconds=*/original_query_age},
{default_search_provider(), "more recent local query",
/*age_in_seconds=*/original_query_age},
});
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_local_queries{
{base::ASCIIToUTF16("more recent local query"),
GetQueryDestinationURL("more recent local query"), ""},
{base::ASCIIToUTF16("less recent local query"),
GetQueryDestinationURL("less recent local query"), ""}};
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
GoodServerResponse());
set_service_is_done(false);
SignIn(); // Requests a refresh.
MaybeWaitForService();
// Cached data is updated to server results.
std::vector<RepeatableQuery> expected_server_queries{
{base::ASCIIToUTF16("server query 1"),
GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
{base::ASCIIToUTF16("server query 2"),
GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
}
// TODO(crbug.com/1151909) Test fails on iOS
#if defined(OS_IOS)
#define MAYBE_SignedOut_Deletion DISABLED_SignedOut_Deletion
#else
#define MAYBE_SignedOut_Deletion SignedOut_Deletion
#endif
TEST_F(RepeatableQueriesServiceTest, MAYBE_SignedOut_Deletion) {
FillURLDatabase({{default_search_provider(), "local query 1",
/*age_in_seconds=*/1},
{default_search_provider(), "local query 2",
/*age_in_seconds=*/2},
{default_search_provider(), "local query 3",
/*age_in_seconds=*/3}});
EXPECT_CALL(*service()->search_provider_observer(), is_google())
.WillRepeatedly(testing::Return(true));
// Request a refresh.
RefreshAndMaybeWaitForService();
std::vector<RepeatableQuery> expected_local_queries{
{base::ASCIIToUTF16("local query 1"),
GetQueryDestinationURL("local query 1"), ""},
{base::ASCIIToUTF16("local query 2"),
GetQueryDestinationURL("local query 2"), ""}};
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
// Try to delete a query suggestion not provided by the service.
set_service_is_done(false);
service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
MaybeWaitForService();
// Suggestions should not change.
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
// Delete the query suggestion provided by the service.
set_service_is_done(false);
service()->DeleteQueryWithDestinationURL(
GetQueryDestinationURL("local query 1"));
MaybeWaitForService();
expected_local_queries = {{base::ASCIIToUTF16("local query 2"),
GetQueryDestinationURL("local query 2"), ""}};
// The deleted suggestion is not offered anymore.
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
// Make sure there is no pending deletion task.
WaitForRepeatableQueriesService();
// Request a refresh.
RefreshAndMaybeWaitForService();
expected_local_queries = {{base::ASCIIToUTF16("local query 2"),
GetQueryDestinationURL("local query 2"), ""},
{base::ASCIIToUTF16("local query 3"),
GetQueryDestinationURL("local query 3"), ""}};
// The deleted suggestion will not be offered again.
EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
}