1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/autocomplete/zero_suggest_provider.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
12 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
13 #include "chrome/browser/search_engines/template_url_service_factory.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "components/metrics/proto/omnibox_event.pb.h"
17 #include "components/omnibox/autocomplete_provider_listener.h"
18 #include "components/omnibox/omnibox_field_trial.h"
19 #include "components/search_engines/template_url.h"
20 #include "components/search_engines/template_url_service.h"
21 #include "components/variations/entropy_provider.h"
22 #include "components/variations/variations_associated_data.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "net/url_request/test_url_fetcher_factory.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 class ZeroSuggestProviderTest
: public testing::Test
,
28 public AutocompleteProviderListener
{
30 ZeroSuggestProviderTest();
32 virtual void SetUp() OVERRIDE
;
33 virtual void TearDown() OVERRIDE
;
36 // AutocompleteProviderListener:
37 virtual void OnProviderUpdate(bool updated_matches
) OVERRIDE
;
39 void ResetFieldTrialList();
41 void CreatePersonalizedFieldTrial();
43 // Set up threads for testing; this needs to be instantiated before
45 content::TestBrowserThreadBundle thread_bundle_
;
47 // Needed for OmniboxFieldTrial::ActivateStaticTrials().
48 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
50 // URLFetcherFactory implementation registered.
51 net::TestURLFetcherFactory test_factory_
;
54 TestingProfile profile_
;
56 // ZeroSuggestProvider object under test.
57 scoped_refptr
<ZeroSuggestProvider
> provider_
;
59 // Default template URL.
60 TemplateURL
* default_t_url_
;
63 ZeroSuggestProviderTest::ZeroSuggestProviderTest() {
64 ResetFieldTrialList();
67 void ZeroSuggestProviderTest::SetUp() {
68 // Make sure that fetchers are automatically ungregistered upon destruction.
69 test_factory_
.set_remove_fetcher_on_delete(true);
70 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
71 &profile_
, &TemplateURLServiceFactory::BuildInstanceFor
);
72 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
73 &profile_
, &AutocompleteClassifierFactory::BuildInstanceFor
);
75 TemplateURLService
* turl_model
=
76 TemplateURLServiceFactory::GetForProfile(&profile_
);
80 data
.short_name
= base::ASCIIToUTF16("t");
81 data
.SetURL("https://www.google.com/?q={searchTerms}");
82 data
.suggestions_url
= "https://www.google.com/complete/?q={searchTerms}";
83 data
.instant_url
= "https://does/not/exist?strk=1";
84 data
.search_terms_replacement_key
= "strk";
85 default_t_url_
= new TemplateURL(data
);
86 turl_model
->Add(default_t_url_
);
87 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
89 provider_
= ZeroSuggestProvider::Create(this, turl_model
, &profile_
);
92 void ZeroSuggestProviderTest::TearDown() {
93 // Shutdown the provider before the profile.
97 void ZeroSuggestProviderTest::OnProviderUpdate(bool updated_matches
) {
100 void ZeroSuggestProviderTest::ResetFieldTrialList() {
101 // Destroy the existing FieldTrialList before creating a new one to avoid
103 field_trial_list_
.reset();
104 field_trial_list_
.reset(new base::FieldTrialList(
105 new metrics::SHA1EntropyProvider("foo")));
106 variations::testing::ClearAllVariationParams();
109 void ZeroSuggestProviderTest::CreatePersonalizedFieldTrial() {
110 std::map
<std::string
, std::string
> params
;
111 params
[std::string(OmniboxFieldTrial::kZeroSuggestRule
)] = "true";
112 params
[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule
)] =
114 variations::AssociateVariationParams(
115 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
);
116 base::FieldTrialList::CreateFieldTrial(
117 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
120 TEST_F(ZeroSuggestProviderTest
, TestPsuggestZeroSuggestCachingFirstRun
) {
121 CreatePersonalizedFieldTrial();
123 // Ensure the cache is empty.
124 PrefService
* prefs
= profile_
.GetPrefs();
125 prefs
->SetString(prefs::kZeroSuggestCachedResults
, std::string());
127 std::string
url("http://www.cnn.com");
128 AutocompleteInput
input(base::ASCIIToUTF16(url
), base::string16::npos
,
129 base::string16(), GURL(url
),
130 metrics::OmniboxEventProto::INVALID_SPEC
, true, false,
132 ChromeAutocompleteSchemeClassifier(&profile_
));
134 provider_
->Start(input
, false);
136 EXPECT_TRUE(prefs
->GetString(prefs::kZeroSuggestCachedResults
).empty());
137 EXPECT_TRUE(provider_
->matches().empty());
139 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(1);
140 ASSERT_TRUE(fetcher
);
141 fetcher
->set_response_code(200);
142 std::string
json_response("[\"\",[\"search1\", \"search2\", \"search3\"],"
143 "[],[],{\"google:suggestrelevance\":[602, 601, 600],"
144 "\"google:verbatimrelevance\":1300}]");
145 fetcher
->SetResponseString(json_response
);
146 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
148 base::RunLoop().RunUntilIdle();
150 EXPECT_EQ(4U, provider_
->matches().size()); // 3 results + verbatim
151 EXPECT_EQ(json_response
, prefs
->GetString(prefs::kZeroSuggestCachedResults
));
154 TEST_F(ZeroSuggestProviderTest
, TestPsuggestZeroSuggestHasCachedResults
) {
155 CreatePersonalizedFieldTrial();
157 std::string
url("http://www.cnn.com");
158 AutocompleteInput
input(base::ASCIIToUTF16(url
), base::string16::npos
,
159 base::string16(), GURL(url
),
160 metrics::OmniboxEventProto::INVALID_SPEC
, true, false,
162 ChromeAutocompleteSchemeClassifier(&profile_
));
164 // Set up the pref to cache the response from the previous run.
165 std::string
json_response("[\"\",[\"search1\", \"search2\", \"search3\"],"
166 "[],[],{\"google:suggestrelevance\":[602, 601, 600],"
167 "\"google:verbatimrelevance\":1300}]");
168 PrefService
* prefs
= profile_
.GetPrefs();
169 prefs
->SetString(prefs::kZeroSuggestCachedResults
, json_response
);
171 provider_
->Start(input
, false);
173 // Expect that matches get populated synchronously out of the cache.
174 ASSERT_EQ(4U, provider_
->matches().size());
175 EXPECT_EQ(base::ASCIIToUTF16("search1"), provider_
->matches()[1].contents
);
176 EXPECT_EQ(base::ASCIIToUTF16("search2"), provider_
->matches()[2].contents
);
177 EXPECT_EQ(base::ASCIIToUTF16("search3"), provider_
->matches()[3].contents
);
179 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(1);
180 ASSERT_TRUE(fetcher
);
181 fetcher
->set_response_code(200);
182 std::string
json_response2("[\"\",[\"search4\", \"search5\", \"search6\"],"
183 "[],[],{\"google:suggestrelevance\":[602, 601, 600],"
184 "\"google:verbatimrelevance\":1300}]");
185 fetcher
->SetResponseString(json_response2
);
186 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
188 base::RunLoop().RunUntilIdle();
190 // Expect the same 4 results after the response has been handled.
191 ASSERT_EQ(4U, provider_
->matches().size());
192 EXPECT_EQ(base::ASCIIToUTF16("search1"), provider_
->matches()[1].contents
);
193 EXPECT_EQ(base::ASCIIToUTF16("search2"), provider_
->matches()[2].contents
);
194 EXPECT_EQ(base::ASCIIToUTF16("search3"), provider_
->matches()[3].contents
);
196 // Expect the new results have been stored.
197 EXPECT_EQ(json_response2
,
198 prefs
->GetString(prefs::kZeroSuggestCachedResults
));
201 TEST_F(ZeroSuggestProviderTest
, TestPsuggestZeroSuggestReceivedEmptyResults
) {
202 CreatePersonalizedFieldTrial();
204 std::string
url("http://www.cnn.com");
205 AutocompleteInput
input(base::ASCIIToUTF16(url
), base::string16::npos
,
206 base::string16(), GURL(url
),
207 metrics::OmniboxEventProto::INVALID_SPEC
, true, false,
209 ChromeAutocompleteSchemeClassifier(&profile_
));
211 // Set up the pref to cache the response from the previous run.
212 std::string
json_response("[\"\",[\"search1\", \"search2\", \"search3\"],"
213 "[],[],{\"google:suggestrelevance\":[602, 601, 600],"
214 "\"google:verbatimrelevance\":1300}]");
215 PrefService
* prefs
= profile_
.GetPrefs();
216 prefs
->SetString(prefs::kZeroSuggestCachedResults
, json_response
);
218 provider_
->Start(input
, false);
220 // Expect that matches get populated synchronously out of the cache.
221 ASSERT_EQ(4U, provider_
->matches().size());
222 EXPECT_EQ(base::ASCIIToUTF16("search1"), provider_
->matches()[1].contents
);
223 EXPECT_EQ(base::ASCIIToUTF16("search2"), provider_
->matches()[2].contents
);
224 EXPECT_EQ(base::ASCIIToUTF16("search3"), provider_
->matches()[3].contents
);
226 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(1);
227 ASSERT_TRUE(fetcher
);
228 fetcher
->set_response_code(200);
229 std::string
empty_response("[\"\",[],[],[],{}]");
230 fetcher
->SetResponseString(empty_response
);
231 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
233 base::RunLoop().RunUntilIdle();
235 // Expect that the matches have been cleared.
236 ASSERT_TRUE(provider_
->matches().empty());
238 // Expect the new results have been stored.
239 EXPECT_EQ(empty_response
,
240 prefs
->GetString(prefs::kZeroSuggestCachedResults
));