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