1// Copyright (c) 2012 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/callback_helpers.h" 6#include "base/files/file_util.h" 7#include "base/memory/scoped_ptr.h" 8#include "base/message_loop/message_loop.h" 9#include "base/path_service.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/browser/search_engines/template_url_service_test_util.h" 12#include "chrome/common/chrome_paths.h" 13#include "chrome/test/base/testing_profile.h" 14#include "components/search_engines/template_url.h" 15#include "components/search_engines/template_url_fetcher.h" 16#include "components/search_engines/template_url_service.h" 17#include "content/public/test/test_browser_thread_bundle.h" 18#include "net/test/embedded_test_server/embedded_test_server.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "url/gurl.h" 21 22using base::ASCIIToUTF16; 23 24// Basic set-up for TemplateURLFetcher tests. 25class TemplateURLFetcherTest : public testing::Test { 26 public: 27 TemplateURLFetcherTest(); 28 29 virtual void SetUp() OVERRIDE { 30 TestingProfile* profile = test_util_.profile(); 31 ASSERT_TRUE(profile->GetRequestContext()); 32 template_url_fetcher_.reset(new TemplateURLFetcher( 33 test_util_.model(), profile->GetRequestContext())); 34 35 ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady()); 36 } 37 38 virtual void TearDown() OVERRIDE { 39 ASSERT_TRUE(test_server_.ShutdownAndWaitUntilComplete()); 40 } 41 42 // Called when the callback is destroyed. 43 void DestroyedCallback(); 44 45 // TemplateURLFetcherCallbacks implementation. (Although not derived from 46 // this class, this method handles those calls for the test.) 47 void ConfirmAddSearchProvider( 48 base::ScopedClosureRunner* callback_destruction_notifier, 49 scoped_ptr<TemplateURL> template_url); 50 51 // Schedules the download of the url. 52 void StartDownload(const base::string16& keyword, 53 const std::string& osdd_file_name, 54 TemplateURLFetcher::ProviderType provider_type, 55 bool check_that_file_exists); 56 57 // Waits for any downloads to finish. 58 void WaitForDownloadToFinish(); 59 60 TemplateURLServiceTestUtil* test_util() { return &test_util_; } 61 TemplateURLFetcher* template_url_fetcher() { 62 return template_url_fetcher_.get(); 63 } 64 const TemplateURL* last_callback_template_url() const { 65 return last_callback_template_url_.get(); 66 } 67 int callbacks_destroyed() const { return callbacks_destroyed_; } 68 int add_provider_called() const { return add_provider_called_; } 69 70 private: 71 content::TestBrowserThreadBundle thread_bundle_; // To set up BrowserThreads. 72 TemplateURLServiceTestUtil test_util_; 73 scoped_ptr<TemplateURLFetcher> template_url_fetcher_; 74 net::test_server::EmbeddedTestServer test_server_; 75 76 // The last TemplateURL to come from a callback. 77 scoped_ptr<TemplateURL> last_callback_template_url_; 78 79 // How many TemplateURLFetcherTestCallbacks have been destructed. 80 int callbacks_destroyed_; 81 82 // How many times ConfirmAddSearchProvider has been called. 83 int add_provider_called_; 84 85 // Is the code in WaitForDownloadToFinish in a message loop waiting for a 86 // callback to finish? 87 bool waiting_for_download_; 88 89 private: 90 DISALLOW_COPY_AND_ASSIGN(TemplateURLFetcherTest); 91}; 92 93TemplateURLFetcherTest::TemplateURLFetcherTest() 94 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 95 callbacks_destroyed_(0), 96 add_provider_called_(0), 97 waiting_for_download_(false) { 98 base::FilePath src_dir; 99 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); 100 test_server_.ServeFilesFromDirectory( 101 src_dir.AppendASCII("chrome/test/data")); 102} 103 104void TemplateURLFetcherTest::DestroyedCallback() { 105 callbacks_destroyed_++; 106 if (waiting_for_download_) 107 base::MessageLoop::current()->Quit(); 108} 109 110void TemplateURLFetcherTest::ConfirmAddSearchProvider( 111 base::ScopedClosureRunner* callback_destruction_notifier, 112 scoped_ptr<TemplateURL> template_url) { 113 last_callback_template_url_ = template_url.Pass(); 114 add_provider_called_++; 115} 116 117void TemplateURLFetcherTest::StartDownload( 118 const base::string16& keyword, 119 const std::string& osdd_file_name, 120 TemplateURLFetcher::ProviderType provider_type, 121 bool check_that_file_exists) { 122 123 if (check_that_file_exists) { 124 base::FilePath osdd_full_path; 125 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &osdd_full_path)); 126 osdd_full_path = osdd_full_path.AppendASCII(osdd_file_name); 127 ASSERT_TRUE(base::PathExists(osdd_full_path)); 128 ASSERT_FALSE(base::DirectoryExists(osdd_full_path)); 129 } 130 131 // Start the fetch. 132 GURL osdd_url = test_server_.GetURL("/" + osdd_file_name); 133 GURL favicon_url; 134 base::ScopedClosureRunner* callback_destruction_notifier = 135 new base::ScopedClosureRunner( 136 base::Bind(&TemplateURLFetcherTest::DestroyedCallback, 137 base::Unretained(this))); 138 139 template_url_fetcher_->ScheduleDownload( 140 keyword, osdd_url, favicon_url, 141 TemplateURLFetcher::URLFetcherCustomizeCallback(), 142 base::Bind(&TemplateURLFetcherTest::ConfirmAddSearchProvider, 143 base::Unretained(this), 144 base::Owned(callback_destruction_notifier)), 145 provider_type); 146} 147 148void TemplateURLFetcherTest::WaitForDownloadToFinish() { 149 ASSERT_FALSE(waiting_for_download_); 150 waiting_for_download_ = true; 151 base::MessageLoop::current()->Run(); 152 waiting_for_download_ = false; 153} 154 155TEST_F(TemplateURLFetcherTest, BasicAutodetectedTest) { 156 base::string16 keyword(ASCIIToUTF16("test")); 157 158 test_util()->ChangeModelToLoadState(); 159 ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 160 161 std::string osdd_file_name("simple_open_search.xml"); 162 StartDownload(keyword, osdd_file_name, 163 TemplateURLFetcher::AUTODETECTED_PROVIDER, true); 164 ASSERT_EQ(0, add_provider_called()); 165 ASSERT_EQ(0, callbacks_destroyed()); 166 167 WaitForDownloadToFinish(); 168 ASSERT_EQ(0, add_provider_called()); 169 ASSERT_EQ(1, callbacks_destroyed()); 170 171 const TemplateURL* t_url = test_util()->model()->GetTemplateURLForKeyword( 172 keyword); 173 ASSERT_TRUE(t_url); 174 EXPECT_EQ(ASCIIToUTF16("http://example.com/%s/other_stuff"), 175 t_url->url_ref().DisplayURL( 176 test_util()->model()->search_terms_data())); 177 EXPECT_TRUE(t_url->safe_for_autoreplace()); 178} 179 180TEST_F(TemplateURLFetcherTest, DuplicatesThrownAway) { 181 base::string16 keyword(ASCIIToUTF16("test")); 182 183 test_util()->ChangeModelToLoadState(); 184 ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 185 186 std::string osdd_file_name("simple_open_search.xml"); 187 StartDownload(keyword, osdd_file_name, 188 TemplateURLFetcher::AUTODETECTED_PROVIDER, true); 189 ASSERT_EQ(0, add_provider_called()); 190 ASSERT_EQ(0, callbacks_destroyed()); 191 192 struct { 193 std::string description; 194 std::string osdd_file_name; 195 base::string16 keyword; 196 TemplateURLFetcher::ProviderType provider_type; 197 } test_cases[] = { 198 { "Duplicate osdd url with autodetected provider.", osdd_file_name, 199 keyword + ASCIIToUTF16("1"), 200 TemplateURLFetcher::AUTODETECTED_PROVIDER }, 201 { "Duplicate keyword with autodetected provider.", osdd_file_name + "1", 202 keyword, TemplateURLFetcher::AUTODETECTED_PROVIDER }, 203 { "Duplicate osdd url with explicit provider.", osdd_file_name, 204 base::string16(), TemplateURLFetcher::EXPLICIT_PROVIDER }, 205 }; 206 207 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 208 StartDownload(test_cases[i].keyword, test_cases[i].osdd_file_name, 209 test_cases[i].provider_type, false); 210 ASSERT_EQ(1, template_url_fetcher()->requests_count()) 211 << test_cases[i].description; 212 ASSERT_EQ(i + 1, static_cast<size_t>(callbacks_destroyed())); 213 } 214 215 WaitForDownloadToFinish(); 216 ASSERT_EQ(1 + ARRAYSIZE_UNSAFE(test_cases), 217 static_cast<size_t>(callbacks_destroyed())); 218 ASSERT_EQ(0, add_provider_called()); 219} 220 221TEST_F(TemplateURLFetcherTest, BasicExplicitTest) { 222 base::string16 keyword(ASCIIToUTF16("test")); 223 224 test_util()->ChangeModelToLoadState(); 225 ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 226 227 std::string osdd_file_name("simple_open_search.xml"); 228 StartDownload(keyword, osdd_file_name, 229 TemplateURLFetcher::EXPLICIT_PROVIDER, true); 230 ASSERT_EQ(0, add_provider_called()); 231 ASSERT_EQ(0, callbacks_destroyed()); 232 233 WaitForDownloadToFinish(); 234 ASSERT_EQ(1, add_provider_called()); 235 ASSERT_EQ(1, callbacks_destroyed()); 236 237 ASSERT_TRUE(last_callback_template_url()); 238 EXPECT_EQ(ASCIIToUTF16("http://example.com/%s/other_stuff"), 239 last_callback_template_url()->url_ref().DisplayURL( 240 test_util()->model()->search_terms_data())); 241 EXPECT_EQ(ASCIIToUTF16("example.com"), 242 last_callback_template_url()->keyword()); 243 EXPECT_FALSE(last_callback_template_url()->safe_for_autoreplace()); 244} 245 246TEST_F(TemplateURLFetcherTest, AutodetectedBeforeLoadTest) { 247 base::string16 keyword(ASCIIToUTF16("test")); 248 ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 249 250 std::string osdd_file_name("simple_open_search.xml"); 251 StartDownload(keyword, osdd_file_name, 252 TemplateURLFetcher::AUTODETECTED_PROVIDER, true); 253 ASSERT_EQ(0, add_provider_called()); 254 ASSERT_EQ(1, callbacks_destroyed()); 255} 256 257TEST_F(TemplateURLFetcherTest, ExplicitBeforeLoadTest) { 258 base::string16 keyword(ASCIIToUTF16("test")); 259 ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 260 261 std::string osdd_file_name("simple_open_search.xml"); 262 StartDownload(keyword, osdd_file_name, 263 TemplateURLFetcher::EXPLICIT_PROVIDER, true); 264 ASSERT_EQ(0, add_provider_called()); 265 ASSERT_EQ(0, callbacks_destroyed()); 266 267 WaitForDownloadToFinish(); 268 ASSERT_EQ(1, add_provider_called()); 269 ASSERT_EQ(1, callbacks_destroyed()); 270 271 ASSERT_TRUE(last_callback_template_url()); 272 EXPECT_EQ(ASCIIToUTF16("http://example.com/%s/other_stuff"), 273 last_callback_template_url()->url_ref().DisplayURL( 274 test_util()->model()->search_terms_data())); 275 EXPECT_EQ(ASCIIToUTF16("example.com"), 276 last_callback_template_url()->keyword()); 277 EXPECT_FALSE(last_callback_template_url()->safe_for_autoreplace()); 278} 279 280TEST_F(TemplateURLFetcherTest, DuplicateKeywordsTest) { 281 base::string16 keyword(ASCIIToUTF16("test")); 282 TemplateURLData data; 283 data.short_name = keyword; 284 data.SetKeyword(keyword); 285 data.SetURL("http://example.com/"); 286 test_util()->model()->Add(new TemplateURL(data)); 287 test_util()->ChangeModelToLoadState(); 288 289 ASSERT_TRUE(test_util()->model()->GetTemplateURLForKeyword(keyword)); 290 291 // This should bail because the keyword already exists. 292 std::string osdd_file_name("simple_open_search.xml"); 293 StartDownload(keyword, osdd_file_name, 294 TemplateURLFetcher::AUTODETECTED_PROVIDER, true); 295 ASSERT_EQ(0, add_provider_called()); 296 ASSERT_EQ(1, callbacks_destroyed()); 297 ASSERT_FALSE(last_callback_template_url()); 298} 299 300TEST_F(TemplateURLFetcherTest, DuplicateDownloadTest) { 301 base::string16 keyword(ASCIIToUTF16("test")); 302 std::string osdd_file_name("simple_open_search.xml"); 303 StartDownload(keyword, osdd_file_name, 304 TemplateURLFetcher::EXPLICIT_PROVIDER, true); 305 ASSERT_EQ(0, add_provider_called()); 306 ASSERT_EQ(0, callbacks_destroyed()); 307 308 // This should bail because the keyword already has a pending download. 309 StartDownload(keyword, osdd_file_name, 310 TemplateURLFetcher::EXPLICIT_PROVIDER, true); 311 ASSERT_EQ(0, add_provider_called()); 312 ASSERT_EQ(1, callbacks_destroyed()); 313 314 WaitForDownloadToFinish(); 315 ASSERT_EQ(1, add_provider_called()); 316 ASSERT_EQ(2, callbacks_destroyed()); 317 ASSERT_TRUE(last_callback_template_url()); 318} 319