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
22 using base::ASCIIToUTF16;
23
24 // Basic set-up for TemplateURLFetcher tests.
25 class TemplateURLFetcherTest : public testing::Test {
26 public:
27 TemplateURLFetcherTest();
28
SetUp()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
TearDown()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
test_util()60 TemplateURLServiceTestUtil* test_util() { return &test_util_; }
template_url_fetcher()61 TemplateURLFetcher* template_url_fetcher() {
62 return template_url_fetcher_.get();
63 }
last_callback_template_url() const64 const TemplateURL* last_callback_template_url() const {
65 return last_callback_template_url_.get();
66 }
callbacks_destroyed() const67 int callbacks_destroyed() const { return callbacks_destroyed_; }
add_provider_called() const68 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
TemplateURLFetcherTest()93 TemplateURLFetcherTest::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
DestroyedCallback()104 void TemplateURLFetcherTest::DestroyedCallback() {
105 callbacks_destroyed_++;
106 if (waiting_for_download_)
107 base::MessageLoop::current()->Quit();
108 }
109
ConfirmAddSearchProvider(base::ScopedClosureRunner * callback_destruction_notifier,scoped_ptr<TemplateURL> template_url)110 void 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
StartDownload(const base::string16 & keyword,const std::string & osdd_file_name,TemplateURLFetcher::ProviderType provider_type,bool check_that_file_exists)117 void 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
WaitForDownloadToFinish()148 void 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
TEST_F(TemplateURLFetcherTest,BasicAutodetectedTest)155 TEST_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
TEST_F(TemplateURLFetcherTest,DuplicatesThrownAway)180 TEST_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
TEST_F(TemplateURLFetcherTest,BasicExplicitTest)221 TEST_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
TEST_F(TemplateURLFetcherTest,AutodetectedBeforeLoadTest)246 TEST_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
TEST_F(TemplateURLFetcherTest,ExplicitBeforeLoadTest)257 TEST_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
TEST_F(TemplateURLFetcherTest,DuplicateKeywordsTest)280 TEST_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
TEST_F(TemplateURLFetcherTest,DuplicateDownloadTest)300 TEST_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