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