search_provider_unittest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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.
4
5#include "base/string_util.h"
6#include "base/time.h"
7#include "base/utf_string_conversions.h"
8#include "build/build_config.h"
9#include "chrome/browser/autocomplete/autocomplete_match.h"
10#include "chrome/browser/autocomplete/search_provider.h"
11#include "chrome/browser/browser_thread.h"
12#include "chrome/browser/history/history.h"
13#include "chrome/browser/search_engines/template_url.h"
14#include "chrome/browser/search_engines/template_url_model.h"
15#include "chrome/common/net/test_url_fetcher_factory.h"
16#include "chrome/test/testing_profile.h"
17#include "net/url_request/url_request_status.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20// The following environment is configured for these tests:
21// . The TemplateURL default_t_url_ is set as the default provider.
22// . The TemplateURL keyword_t_url_ is added to the TemplateURLModel. This
23//   TemplateURL has a valid suggest and search URL.
24// . The URL created by using the search term term1_ with default_t_url_ is
25//   added to history.
26// . The URL created by using the search term keyword_term_ with keyword_t_url_
27//   is added to history.
28// . test_factory_ is set as the URLFetcher::Factory.
29class SearchProviderTest : public testing::Test,
30                           public AutocompleteProvider::ACProviderListener {
31 public:
32  SearchProviderTest()
33      : default_t_url_(NULL),
34        term1_(UTF8ToUTF16("term1")),
35        keyword_t_url_(NULL),
36        keyword_term_(UTF8ToUTF16("keyword")),
37        io_thread_(BrowserThread::IO),
38        quit_when_done_(false) {
39    io_thread_.Start();
40  }
41
42  // See description above class for what this registers.
43  virtual void SetUp();
44
45  virtual void TearDown();
46
47 protected:
48  // Returns an AutocompleteMatch in provider_'s set of matches that matches
49  // |url|. If there is no matching URL, an empty match is returned.
50  AutocompleteMatch FindMatchWithDestination(const GURL& url);
51
52  // ACProviderListener method. If we're waiting for the provider to finish,
53  // this exits the message loop.
54  virtual void OnProviderUpdate(bool updated_matches);
55
56  // Runs a nested message loop until provider_ is done. The message loop is
57  // exited by way of OnProviderUPdate.
58  void RunTillProviderDone();
59
60  // Invokes Start on provider_, then runs all pending tasks.
61  void QueryForInput(const string16& text,
62                     bool prevent_inline_autocomplete);
63
64  // See description above class for details of these fields.
65  TemplateURL* default_t_url_;
66  const string16 term1_;
67  GURL term1_url_;
68  TemplateURL* keyword_t_url_;
69  const string16 keyword_term_;
70  GURL keyword_url_;
71
72  MessageLoopForUI message_loop_;
73  BrowserThread io_thread_;
74
75  // URLFetcher::Factory implementation registered.
76  TestURLFetcherFactory test_factory_;
77
78  // Profile we use.
79  TestingProfile profile_;
80
81  // The provider.
82  scoped_refptr<SearchProvider> provider_;
83
84  // If true, OnProviderUpdate exits out of the current message loop.
85  bool quit_when_done_;
86
87  DISALLOW_COPY_AND_ASSIGN(SearchProviderTest);
88};
89
90void SearchProviderTest::SetUp() {
91  SearchProvider::set_query_suggest_immediately(true);
92
93  // We need both the history service and template url model loaded.
94  profile_.CreateHistoryService(true, false);
95  profile_.CreateTemplateURLModel();
96
97  TemplateURLModel* turl_model = profile_.GetTemplateURLModel();
98
99  // Reset the default TemplateURL.
100  default_t_url_ = new TemplateURL();
101  default_t_url_->SetURL("http://defaultturl/{searchTerms}", 0, 0);
102  default_t_url_->SetSuggestionsURL("http://defaultturl2/{searchTerms}", 0, 0);
103  turl_model->Add(default_t_url_);
104  turl_model->SetDefaultSearchProvider(default_t_url_);
105  TemplateURLID default_provider_id = default_t_url_->id();
106  ASSERT_NE(0, default_provider_id);
107
108  // Add url1, with search term term1_.
109  HistoryService* history =
110      profile_.GetHistoryService(Profile::EXPLICIT_ACCESS);
111  term1_url_ = GURL(default_t_url_->url()->ReplaceSearchTerms(
112      *default_t_url_, UTF16ToWide(term1_), 0, std::wstring()));
113  history->AddPageWithDetails(term1_url_, string16(), 1, 1,
114                              base::Time::Now(), false,
115                              history::SOURCE_BROWSED);
116  history->SetKeywordSearchTermsForURL(term1_url_, default_t_url_->id(),
117                                       term1_);
118
119  // Create another TemplateURL.
120  keyword_t_url_ = new TemplateURL();
121  keyword_t_url_->set_keyword(L"k");
122  keyword_t_url_->SetURL("http://keyword/{searchTerms}", 0, 0);
123  keyword_t_url_->SetSuggestionsURL("http://suggest_keyword/{searchTerms}", 0,
124                                    0);
125  profile_.GetTemplateURLModel()->Add(keyword_t_url_);
126  ASSERT_NE(0, keyword_t_url_->id());
127
128  // Add a page and search term for keyword_t_url_.
129  keyword_url_ = GURL(keyword_t_url_->url()->ReplaceSearchTerms(
130      *keyword_t_url_, UTF16ToWide(keyword_term_), 0, std::wstring()));
131  history->AddPageWithDetails(keyword_url_, string16(), 1, 1,
132                              base::Time::Now(), false,
133                              history::SOURCE_BROWSED);
134  history->SetKeywordSearchTermsForURL(keyword_url_, keyword_t_url_->id(),
135                                       keyword_term_);
136
137  // Keywords are updated by the InMemoryHistoryBackend only after the message
138  // has been processed on the history thread. Block until history processes all
139  // requests to ensure the InMemoryDatabase is the state we expect it.
140  profile_.BlockUntilHistoryProcessesPendingRequests();
141
142  provider_ = new SearchProvider(this, &profile_);
143
144  URLFetcher::set_factory(&test_factory_);
145}
146
147void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
148  if (quit_when_done_ && provider_->done()) {
149    quit_when_done_ = false;
150    message_loop_.Quit();
151  }
152}
153
154void SearchProviderTest::RunTillProviderDone() {
155  if (provider_->done())
156    return;
157
158  quit_when_done_ = true;
159#if defined(OS_MACOSX)
160  message_loop_.Run();
161#else
162  message_loop_.Run(NULL);
163#endif
164}
165
166void SearchProviderTest::QueryForInput(const string16& text,
167                                       bool prevent_inline_autocomplete) {
168  // Start a query.
169  AutocompleteInput input(UTF16ToWide(text), std::wstring(),
170                          prevent_inline_autocomplete, false, true, false);
171  provider_->Start(input, false);
172
173  // RunAllPending so that the task scheduled by SearchProvider to create the
174  // URLFetchers runs.
175  message_loop_.RunAllPending();
176}
177
178void SearchProviderTest::TearDown() {
179  message_loop_.RunAllPending();
180
181  URLFetcher::set_factory(NULL);
182
183  // Shutdown the provider before the profile.
184  provider_ = NULL;
185}
186
187AutocompleteMatch SearchProviderTest::FindMatchWithDestination(
188    const GURL& url) {
189  for (ACMatches::const_iterator i = provider_->matches().begin();
190       i != provider_->matches().end(); ++i) {
191    if (i->destination_url == url)
192      return *i;
193  }
194  return AutocompleteMatch(NULL, 1, false, AutocompleteMatch::HISTORY_URL);
195}
196
197// Tests -----------------------------------------------------------------------
198
199// Make sure we query history for the default provider and a URLFetcher is
200// created for the default provider suggest results.
201TEST_F(SearchProviderTest, QueryDefaultProvider) {
202  string16 term = term1_.substr(0, term1_.size() - 1);
203  QueryForInput(term, false);
204
205  // Make sure the default providers suggest service was queried.
206  TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
207      SearchProvider::kDefaultProviderURLFetcherID);
208  ASSERT_TRUE(fetcher);
209
210  // And the URL matches what we expected.
211  GURL expected_url = GURL(default_t_url_->suggestions_url()->
212      ReplaceSearchTerms(*default_t_url_, UTF16ToWide(term),
213      0, std::wstring()));
214  ASSERT_TRUE(fetcher->original_url() == expected_url);
215
216  // Tell the SearchProvider the suggest query is done.
217  fetcher->delegate()->OnURLFetchComplete(
218      fetcher, GURL(), URLRequestStatus(), 200, ResponseCookies(),
219      std::string());
220  fetcher = NULL;
221
222  // Run till the history results complete.
223  RunTillProviderDone();
224
225  // The SearchProvider is done. Make sure it has a result for the history
226  // term term1.
227  AutocompleteMatch match = FindMatchWithDestination(term1_url_);
228  ASSERT_TRUE(!match.destination_url.is_empty());
229}
230
231TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
232  string16 term = term1_.substr(0, term1_.size() - 1);
233  QueryForInput(term, true);
234
235  ASSERT_FALSE(provider_->matches().empty());
236  ASSERT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
237            provider_->matches()[0].type);
238}
239
240// Issues a query that matches the registered keyword and makes sure history
241// is queried as well as URLFetchers getting created.
242TEST_F(SearchProviderTest, QueryKeywordProvider) {
243  string16 term = keyword_term_.substr(0, keyword_term_.size() - 1);
244  QueryForInput(WideToUTF16(keyword_t_url_->keyword()) +
245                UTF8ToUTF16(" ") + term, false);
246
247  // Make sure the default providers suggest service was queried.
248  TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID(
249      SearchProvider::kDefaultProviderURLFetcherID);
250  ASSERT_TRUE(default_fetcher);
251
252  // Tell the SearchProvider the default suggest query is done.
253  default_fetcher->delegate()->OnURLFetchComplete(
254      default_fetcher, GURL(), URLRequestStatus(), 200, ResponseCookies(),
255      std::string());
256  default_fetcher = NULL;
257
258  // Make sure the keyword providers suggest service was queried.
259  TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
260      SearchProvider::kKeywordProviderURLFetcherID);
261  ASSERT_TRUE(keyword_fetcher);
262
263  // And the URL matches what we expected.
264  GURL expected_url = GURL(keyword_t_url_->suggestions_url()->
265      ReplaceSearchTerms(*keyword_t_url_, UTF16ToWide(term), 0,
266      std::wstring()));
267  ASSERT_TRUE(keyword_fetcher->original_url() == expected_url);
268
269  // Tell the SearchProvider the keyword suggest query is done.
270  keyword_fetcher->delegate()->OnURLFetchComplete(
271      keyword_fetcher, GURL(), URLRequestStatus(), 200, ResponseCookies(),
272      std::string());
273  keyword_fetcher = NULL;
274
275  // Run till the history results complete.
276  RunTillProviderDone();
277
278  // The SearchProvider is done. Make sure it has a result for the history
279  // term keyword.
280  AutocompleteMatch match = FindMatchWithDestination(keyword_url_);
281  ASSERT_TRUE(!match.destination_url.is_empty());
282
283  // The match should have a TemplateURL.
284  EXPECT_TRUE(match.template_url);
285
286  // The fill into edit should contain the keyword.
287  EXPECT_EQ(keyword_t_url_->keyword() + L" " + UTF16ToWide(keyword_term_),
288            match.fill_into_edit);
289}
290
291TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) {
292  // None of the following input strings should be sent to the suggest server,
293  // because they may contain private data.
294  const char* inputs[] = {
295    "username:password",
296    "http://username:password",
297    "https://username:password",
298    "username:password@hostname",
299    "http://username:password@hostname/",
300    "file://filename",
301    "data://data",
302    "unknownscheme:anything",
303    "http://hostname/?query=q",
304    "http://hostname/path#ref",
305    "https://hostname/path",
306  };
307
308  for (size_t i = 0; i < arraysize(inputs); ++i) {
309    QueryForInput(ASCIIToUTF16(inputs[i]), false);
310    // Make sure the default providers suggest service was not queried.
311    ASSERT_TRUE(test_factory_.GetFetcherByID(
312        SearchProvider::kDefaultProviderURLFetcherID) == NULL);
313    // Run till the history results complete.
314    RunTillProviderDone();
315  }
316}
317