OLD | NEW |
| (Empty) |
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/command_line.h" | |
6 #include "base/file_util.h" | |
7 #include "base/files/file_path.h" | |
8 #include "base/path_service.h" | |
9 #include "base/strings/string_split.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "base/threading/sequenced_worker_pool.h" | |
12 #include "chrome/browser/chrome_notification_types.h" | |
13 #include "chrome/browser/browser_process.h" | |
14 #include "chrome/browser/page_cycler/page_cycler.h" | |
15 #include "chrome/browser/profiles/profile.h" | |
16 #include "chrome/browser/profiles/profile_manager.h" | |
17 #include "chrome/browser/ui/browser_list.h" | |
18 #include "chrome/common/chrome_paths.h" | |
19 #include "chrome/common/chrome_switches.h" | |
20 #include "chrome/test/base/in_process_browser_test.h" | |
21 #include "chrome/test/base/testing_profile.h" | |
22 #include "chrome/test/base/ui_test_utils.h" | |
23 #include "content/public/browser/notification_observer.h" | |
24 #include "content/public/browser/notification_registrar.h" | |
25 #include "content/public/browser/notification_service.h" | |
26 #include "content/public/common/content_switches.h" | |
27 #include "content/public/common/url_constants.h" | |
28 #include "url/gurl.h" | |
29 | |
30 // TODO(kbr): remove: http://crbug.com/222296 | |
31 #if defined(OS_MACOSX) | |
32 #import "base/mac/mac_util.h" | |
33 #endif | |
34 | |
35 // Basic PageCyclerBrowserTest structure; used in testing most of PageCycler's | |
36 // functionality. | |
37 class PageCyclerBrowserTest : public content::NotificationObserver, | |
38 public InProcessBrowserTest { | |
39 public: | |
40 PageCyclerBrowserTest() : page_cycler_(NULL) { | |
41 } | |
42 | |
43 virtual ~PageCyclerBrowserTest() { | |
44 } | |
45 | |
46 // Initialize file paths within a temporary directory; this should be | |
47 // empty and nonexistent. | |
48 virtual void InitFilePaths(base::FilePath temp_path) { | |
49 temp_path_ = temp_path; | |
50 urls_file_ = temp_path.AppendASCII("urls_file"); | |
51 errors_file_ = temp_path.AppendASCII("errors"); | |
52 stats_file_ = temp_path.AppendASCII("stats"); | |
53 | |
54 ASSERT_FALSE(base::PathExists(urls_file_)); | |
55 ASSERT_FALSE(base::PathExists(errors_file_)); | |
56 ASSERT_FALSE(base::PathExists(stats_file_)); | |
57 } | |
58 | |
59 // Initialize a PageCycler using either the base fields, or using provided | |
60 // ones. | |
61 void InitPageCycler() { | |
62 page_cycler_ = new PageCycler(browser(), urls_file()); | |
63 page_cycler_->set_errors_file(errors_file()); | |
64 page_cycler_->set_stats_file(stats_file()); | |
65 } | |
66 | |
67 void InitPageCycler(base::FilePath urls_file, | |
68 base::FilePath errors_file, | |
69 base::FilePath stats_file) { | |
70 page_cycler_ = new PageCycler(browser(), urls_file); | |
71 page_cycler_->set_errors_file(errors_file); | |
72 page_cycler_->set_stats_file(stats_file); | |
73 } | |
74 | |
75 void RegisterForNotifications() { | |
76 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, | |
77 content::NotificationService::AllSources()); | |
78 } | |
79 | |
80 // Get a collection of basic urls which are stored in the test directory. | |
81 // NOTE: |test_server| must be started first! | |
82 std::vector<GURL> GetURLs() { | |
83 std::vector<GURL> urls; | |
84 urls.push_back(test_server()->GetURL("files/page_cycler/basic_html.html")); | |
85 urls.push_back(test_server()->GetURL("files/page_cycler/basic_js.html")); | |
86 urls.push_back(test_server()->GetURL("files/page_cycler/basic_css.html")); | |
87 return urls; | |
88 } | |
89 | |
90 // Read the errors file, and generate a vector of error strings. | |
91 std::vector<std::string> GetErrorsFromFile() { | |
92 std::string error_file_contents; | |
93 CHECK(file_util::ReadFileToString(errors_file_, | |
94 &error_file_contents)); | |
95 if (error_file_contents[error_file_contents.size() - 1] == '\n') | |
96 error_file_contents.resize(error_file_contents.size() - 1); | |
97 | |
98 std::vector<std::string> errors; | |
99 base::SplitString(error_file_contents, '\n', &errors); | |
100 | |
101 return errors; | |
102 } | |
103 | |
104 // Convert a vector of GURLs into a newline-separated string, ready to be | |
105 // written to the urls file for PageCycler to use. | |
106 std::string GetStringFromURLs(std::vector<GURL> urls) { | |
107 std::string urls_string; | |
108 for (std::vector<GURL>::const_iterator iter = urls.begin(); | |
109 iter != urls.end(); ++iter) | |
110 urls_string.append(iter->spec() + "\n"); | |
111 return urls_string; | |
112 } | |
113 | |
114 // content::NotificationObserver. | |
115 virtual void Observe(int type, | |
116 const content::NotificationSource& source, | |
117 const content::NotificationDetails& details) OVERRIDE { | |
118 switch (type) { | |
119 case chrome::NOTIFICATION_BROWSER_CLOSED: | |
120 base::MessageLoop::current()->PostTask( | |
121 FROM_HERE, base::MessageLoop::QuitClosure()); | |
122 break; | |
123 default: | |
124 NOTREACHED(); | |
125 break; | |
126 } | |
127 } | |
128 | |
129 base::FilePath urls_file() { return urls_file_; } | |
130 base::FilePath errors_file() { return errors_file_; } | |
131 base::FilePath stats_file() { return stats_file_; } | |
132 PageCycler* page_cycler() { return page_cycler_; } | |
133 | |
134 protected: | |
135 base::FilePath temp_path_; | |
136 base::FilePath urls_file_; | |
137 base::FilePath errors_file_; | |
138 base::FilePath stats_file_; | |
139 PageCycler* page_cycler_; | |
140 content::NotificationRegistrar registrar_; | |
141 }; | |
142 | |
143 // Structure used for testing PageCycler's ability to playback a series of | |
144 // URLs given a cache directory. | |
145 class PageCyclerCachedBrowserTest : public PageCyclerBrowserTest { | |
146 public: | |
147 // For a cached test, we use the provided user data directory from the test | |
148 // directory. | |
149 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
150 base::FilePath test_dir; | |
151 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | |
152 test_dir = test_dir.AppendASCII("page_cycler"); | |
153 | |
154 base::FilePath source_data_dir = test_dir.AppendASCII("cached_data_dir"); | |
155 CHECK(base::PathExists(source_data_dir)); | |
156 | |
157 CHECK(user_data_dir_.CreateUniqueTempDir()); | |
158 | |
159 base::FilePath dest_data_dir = | |
160 user_data_dir_.path().AppendASCII("cached_data_dir"); | |
161 CHECK(!base::PathExists(dest_data_dir)); | |
162 | |
163 CHECK(base::CopyDirectory(source_data_dir, user_data_dir_.path(), | |
164 true)); // recursive. | |
165 CHECK(base::PathExists(dest_data_dir)); | |
166 | |
167 command_line->AppendSwitchPath(switches::kUserDataDir, | |
168 dest_data_dir); | |
169 command_line->AppendSwitch(switches::kPlaybackMode); | |
170 } | |
171 | |
172 // Initialize the file paths to use the UserDataDir's urls file, instead | |
173 // of one to be written. | |
174 virtual void InitFilePaths(base::FilePath temp_path) OVERRIDE { | |
175 urls_file_ = user_data_dir_.path().AppendASCII("cached_data_dir") | |
176 .AppendASCII("urls"); | |
177 errors_file_ = temp_path.AppendASCII("errors"); | |
178 stats_file_ = temp_path.AppendASCII("stats"); | |
179 | |
180 ASSERT_TRUE(base::PathExists(urls_file_)); | |
181 ASSERT_FALSE(base::PathExists(errors_file_)); | |
182 ASSERT_FALSE(base::PathExists(stats_file_)); | |
183 } | |
184 | |
185 private: | |
186 // The directory storing the copy of the UserDataDir. | |
187 base::ScopedTempDir user_data_dir_; | |
188 }; | |
189 | |
190 // Sanity check; iterate through a series of URLs and make sure there are no | |
191 // errors. | |
192 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, BasicTest) { | |
193 base::ScopedTempDir temp; | |
194 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
195 | |
196 RegisterForNotifications(); | |
197 InitFilePaths(temp.path()); | |
198 | |
199 ASSERT_TRUE(test_server()->Start()); | |
200 | |
201 std::string urls_string = GetStringFromURLs(GetURLs());; | |
202 | |
203 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
204 urls_string.size())); | |
205 | |
206 InitPageCycler(); | |
207 page_cycler()->Run(); | |
208 | |
209 content::RunMessageLoop(); | |
210 ASSERT_FALSE(base::PathExists(errors_file())); | |
211 ASSERT_TRUE(base::PathExists(stats_file())); | |
212 } | |
213 | |
214 // Test to make sure that PageCycler will recognize unvisitable URLs, and will | |
215 // handle them appropriately. | |
216 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, UnvisitableURL) { | |
217 const size_t kNumErrors = 1; | |
218 const char kFakeURL[] = "http://www.pleasenoonehavethisurlanytimeinthenext" | |
219 "century.com/gibberish"; | |
220 base::ScopedTempDir temp; | |
221 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
222 | |
223 RegisterForNotifications(); | |
224 InitFilePaths(temp.path()); | |
225 | |
226 ASSERT_TRUE(test_server()->Start()); | |
227 | |
228 std::vector<GURL> urls = GetURLs(); | |
229 urls.push_back(GURL(kFakeURL)); | |
230 std::string urls_string = GetStringFromURLs(urls); | |
231 | |
232 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
233 urls_string.size())); | |
234 | |
235 InitPageCycler(); | |
236 page_cycler()->Run(); | |
237 | |
238 content::RunMessageLoop(); | |
239 ASSERT_TRUE(base::PathExists(errors_file())); | |
240 ASSERT_TRUE(base::PathExists(stats_file())); | |
241 | |
242 std::vector<std::string> errors = GetErrorsFromFile(); | |
243 | |
244 ASSERT_EQ(kNumErrors, errors.size()); | |
245 | |
246 // Check that each error message contains the fake URL (i.e., that it wasn't | |
247 // from a valid URL, and that the fake URL was caught each time). | |
248 ASSERT_NE(std::string::npos, errors[0].find(kFakeURL)); | |
249 } | |
250 | |
251 // Test that PageCycler will remove an invalid URL prior to running. | |
252 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, InvalidURL) { | |
253 const char kBadURL[] = "notarealurl"; | |
254 | |
255 base::ScopedTempDir temp; | |
256 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
257 | |
258 RegisterForNotifications(); | |
259 InitFilePaths(temp.path()); | |
260 | |
261 ASSERT_TRUE(test_server()->Start()); | |
262 | |
263 std::string urls_string = GetStringFromURLs(GetURLs()); | |
264 urls_string.append(kBadURL).append("\n"); | |
265 | |
266 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
267 urls_string.size())); | |
268 | |
269 InitPageCycler(); | |
270 page_cycler()->Run(); | |
271 | |
272 content::RunMessageLoop(); | |
273 ASSERT_TRUE(base::PathExists(errors_file())); | |
274 ASSERT_TRUE(base::PathExists(stats_file())); | |
275 | |
276 std::vector<std::string> errors = GetErrorsFromFile(); | |
277 ASSERT_EQ(1u, errors.size()); | |
278 | |
279 std::string expected_error = "Omitting invalid URL: "; | |
280 expected_error.append(kBadURL).append("."); | |
281 | |
282 ASSERT_FALSE(errors[0].compare(expected_error)); | |
283 } | |
284 | |
285 // Test that PageCycler will remove a Chrome Error URL prior to running. | |
286 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, ChromeErrorURL) { | |
287 base::ScopedTempDir temp; | |
288 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
289 | |
290 RegisterForNotifications(); | |
291 InitFilePaths(temp.path()); | |
292 | |
293 ASSERT_TRUE(test_server()->Start()); | |
294 | |
295 std::vector<GURL> urls = GetURLs(); | |
296 urls.push_back(GURL(content::kUnreachableWebDataURL)); | |
297 std::string urls_string = GetStringFromURLs(urls); | |
298 | |
299 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
300 urls_string.size())); | |
301 | |
302 InitPageCycler(); | |
303 page_cycler()->Run(); | |
304 | |
305 content::RunMessageLoop(); | |
306 ASSERT_TRUE(base::PathExists(errors_file())); | |
307 ASSERT_TRUE(base::PathExists(stats_file())); | |
308 | |
309 std::vector<std::string> errors = GetErrorsFromFile(); | |
310 ASSERT_EQ(1u, errors.size()); | |
311 | |
312 std::string expected_error = "Chrome error pages are not allowed as urls. " | |
313 "Omitting url: "; | |
314 expected_error.append(content::kUnreachableWebDataURL).append("."); | |
315 | |
316 ASSERT_FALSE(errors[0].compare(expected_error)); | |
317 } | |
318 | |
319 #if !defined(OS_CHROMEOS) | |
320 // TODO(rdevlin.cronin): Perhaps page cycler isn't completely implemented on | |
321 // ChromeOS? | |
322 | |
323 // Test that PageCycler will visit all the urls from a cache directory | |
324 // successfully while in playback mode. | |
325 // Disabled due to flaky timeouts. Tracking bugs include | |
326 // [ http://crbug.com/159026 ], [ http://crbug.com/131333 ], and | |
327 // [ http://crbug.com/222296 ]. | |
328 IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, DISABLED_PlaybackMode) { | |
329 #if defined(OS_MACOSX) | |
330 // TODO(kbr): re-enable: http://crbug.com/222296 | |
331 if (base::mac::IsOSMountainLionOrLater()) | |
332 return; | |
333 #endif | |
334 | |
335 base::ScopedTempDir temp; | |
336 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
337 | |
338 RegisterForNotifications(); | |
339 InitFilePaths(temp.path()); | |
340 | |
341 InitPageCycler(); | |
342 | |
343 page_cycler()->Run(); | |
344 | |
345 content::RunMessageLoop(); | |
346 ASSERT_TRUE(base::PathExists(stats_file())); | |
347 ASSERT_FALSE(base::PathExists(errors_file())); | |
348 } | |
349 #endif // !defined(OS_CHROMEOS) | |
350 | |
351 #if !defined(OS_CHROMEOS) | |
352 // TODO(rdevlin.cronin): Perhaps page cycler isn't completely implemented on | |
353 // ChromeOS? | |
354 | |
355 // Test that PageCycler will have a cache miss if a URL is missing from the | |
356 // cache directory while in playback mode. | |
357 // Bug 131333: This test fails on a XP debug bot since Build 17609. | |
358 #if (defined(OS_WIN) || defined(OS_MACOSX)) && !defined(NDEBUG) | |
359 #define MAYBE_URLNotInCache DISABLED_URLNotInCache | |
360 #else | |
361 #define MAYBE_URLNotInCache URLNotInCache | |
362 #endif | |
363 IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, MAYBE_URLNotInCache) { | |
364 const char kCacheMissURL[] = "http://www.images.google.com/"; | |
365 | |
366 base::ScopedTempDir temp; | |
367 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
368 | |
369 RegisterForNotifications(); | |
370 InitFilePaths(temp.path()); | |
371 | |
372 // Only use a single URL that is not in cache. That's sufficient for the test | |
373 // scenario, and makes things faster than needlessly cycling through all the | |
374 // other URLs. | |
375 | |
376 base::FilePath new_urls_file = temp.path().AppendASCII("urls"); | |
377 ASSERT_FALSE(base::PathExists(new_urls_file)); | |
378 | |
379 ASSERT_TRUE(file_util::WriteFile(new_urls_file, kCacheMissURL, | |
380 sizeof(kCacheMissURL))); | |
381 | |
382 InitPageCycler(new_urls_file, errors_file(), stats_file()); | |
383 page_cycler()->Run(); | |
384 | |
385 content::RunMessageLoop(); | |
386 ASSERT_TRUE(base::PathExists(errors_file())); | |
387 ASSERT_TRUE(base::PathExists(stats_file())); | |
388 | |
389 std::vector<std::string> errors = GetErrorsFromFile(); | |
390 ASSERT_EQ(1u, errors.size()); | |
391 | |
392 std::string expected_error; | |
393 expected_error.append("Failed to load the page at: ") | |
394 .append(kCacheMissURL) | |
395 .append(": The requested entry was not found in the cache."); | |
396 | |
397 ASSERT_FALSE(errors[0].compare(expected_error)); | |
398 } | |
399 #endif // !defined(OS_CHROMEOS) | |
OLD | NEW |