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/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/path_service.h"
12 #include "base/prefs/pref_member.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/test/test_file_util.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/browser/download/chrome_download_manager_delegate.h"
17 #include "chrome/browser/download/download_history.h"
18 #include "chrome/browser/download/download_prefs.h"
19 #include "chrome/browser/download/download_service.h"
20 #include "chrome/browser/download/download_service_factory.h"
21 #include "chrome/browser/download/save_package_file_picker.h"
22 #include "chrome/browser/history/download_row.h"
23 #include "chrome/browser/net/url_request_mock_util.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_commands.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/common/chrome_paths.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/common/url_constants.h"
33 #include "chrome/test/base/in_process_browser_test.h"
34 #include "chrome/test/base/ui_test_utils.h"
35 #include "content/public/browser/download_item.h"
36 #include "content/public/browser/download_manager.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/browser/notification_types.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/test/test_utils.h"
41 #include "content/test/net/url_request_mock_http_job.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43
44 using content::BrowserContext;
45 using content::BrowserThread;
46 using content::DownloadItem;
47 using content::DownloadManager;
48 using content::URLRequestMockHTTPJob;
49 using content::WebContents;
50
51 namespace {
52
53 // Waits for an item record in the downloads database to match |filter|. See
54 // DownloadStoredProperly() below for an example filter.
55 class DownloadPersistedObserver : public DownloadHistory::Observer {
56 public:
57 typedef base::Callback<bool(
58 DownloadItem* item,
59 const history::DownloadRow&)> PersistedFilter;
60
DownloadPersistedObserver(Profile * profile,const PersistedFilter & filter)61 DownloadPersistedObserver(Profile* profile, const PersistedFilter& filter)
62 : profile_(profile),
63 filter_(filter),
64 waiting_(false),
65 persisted_(false) {
66 DownloadServiceFactory::GetForBrowserContext(profile_)->
67 GetDownloadHistory()->AddObserver(this);
68 }
69
~DownloadPersistedObserver()70 virtual ~DownloadPersistedObserver() {
71 DownloadService* service = DownloadServiceFactory::GetForBrowserContext(
72 profile_);
73 if (service && service->GetDownloadHistory())
74 service->GetDownloadHistory()->RemoveObserver(this);
75 }
76
WaitForPersisted()77 bool WaitForPersisted() {
78 if (persisted_)
79 return true;
80 waiting_ = true;
81 content::RunMessageLoop();
82 waiting_ = false;
83 return persisted_;
84 }
85
OnDownloadStored(DownloadItem * item,const history::DownloadRow & info)86 virtual void OnDownloadStored(DownloadItem* item,
87 const history::DownloadRow& info) OVERRIDE {
88 persisted_ = persisted_ || filter_.Run(item, info);
89 if (persisted_ && waiting_)
90 base::MessageLoopForUI::current()->Quit();
91 }
92
93 private:
94 Profile* profile_;
95 DownloadItem* item_;
96 PersistedFilter filter_;
97 bool waiting_;
98 bool persisted_;
99
100 DISALLOW_COPY_AND_ASSIGN(DownloadPersistedObserver);
101 };
102
103 // Waits for an item record to be removed from the downloads database.
104 class DownloadRemovedObserver : public DownloadPersistedObserver {
105 public:
DownloadRemovedObserver(Profile * profile,int32 download_id)106 DownloadRemovedObserver(Profile* profile, int32 download_id)
107 : DownloadPersistedObserver(profile, PersistedFilter()),
108 removed_(false),
109 waiting_(false),
110 download_id_(download_id) {
111 }
~DownloadRemovedObserver()112 virtual ~DownloadRemovedObserver() {}
113
WaitForRemoved()114 bool WaitForRemoved() {
115 if (removed_)
116 return true;
117 waiting_ = true;
118 content::RunMessageLoop();
119 waiting_ = false;
120 return removed_;
121 }
122
OnDownloadStored(DownloadItem * item,const history::DownloadRow & info)123 virtual void OnDownloadStored(DownloadItem* item,
124 const history::DownloadRow& info) OVERRIDE {
125 }
126
OnDownloadsRemoved(const DownloadHistory::IdSet & ids)127 virtual void OnDownloadsRemoved(const DownloadHistory::IdSet& ids) OVERRIDE {
128 removed_ = ids.find(download_id_) != ids.end();
129 if (removed_ && waiting_)
130 base::MessageLoopForUI::current()->Quit();
131 }
132
133 private:
134 bool removed_;
135 bool waiting_;
136 int32 download_id_;
137
138 DISALLOW_COPY_AND_ASSIGN(DownloadRemovedObserver);
139 };
140
DownloadStoredProperly(const GURL & expected_url,const base::FilePath & expected_path,int64 num_files,DownloadItem::DownloadState expected_state,DownloadItem * item,const history::DownloadRow & info)141 bool DownloadStoredProperly(
142 const GURL& expected_url,
143 const base::FilePath& expected_path,
144 int64 num_files,
145 DownloadItem::DownloadState expected_state,
146 DownloadItem* item,
147 const history::DownloadRow& info) {
148 // This function may be called multiple times for a given test. Returning
149 // false doesn't necessarily mean that the test has failed or will fail, it
150 // might just mean that the test hasn't passed yet.
151 if (info.target_path != expected_path) {
152 VLOG(20) << __FUNCTION__ << " " << info.target_path.value()
153 << " != " << expected_path.value();
154 return false;
155 }
156 if (info.url_chain.size() != 1u) {
157 VLOG(20) << __FUNCTION__ << " " << info.url_chain.size()
158 << " != 1";
159 return false;
160 }
161 if (info.url_chain[0] != expected_url) {
162 VLOG(20) << __FUNCTION__ << " " << info.url_chain[0].spec()
163 << " != " << expected_url.spec();
164 return false;
165 }
166 if ((num_files >= 0) && (info.received_bytes != num_files)) {
167 VLOG(20) << __FUNCTION__ << " " << num_files
168 << " != " << info.received_bytes;
169 return false;
170 }
171 if (info.state != expected_state) {
172 VLOG(20) << __FUNCTION__ << " " << info.state
173 << " != " << expected_state;
174 return false;
175 }
176 return true;
177 }
178
179 const base::FilePath::CharType kTestDir[] = FILE_PATH_LITERAL("save_page");
180
181 static const char kAppendedExtension[] =
182 #if defined(OS_WIN)
183 ".htm";
184 #else
185 ".html";
186 #endif
187
188 // Loosely based on logic in DownloadTestObserver.
189 class DownloadItemCreatedObserver : public DownloadManager::Observer {
190 public:
DownloadItemCreatedObserver(DownloadManager * manager)191 explicit DownloadItemCreatedObserver(DownloadManager* manager)
192 : waiting_(false), manager_(manager) {
193 manager->AddObserver(this);
194 }
195
~DownloadItemCreatedObserver()196 virtual ~DownloadItemCreatedObserver() {
197 if (manager_)
198 manager_->RemoveObserver(this);
199 }
200
201 // Wait for the first download item created after object creation.
202 // Note that this class provides no protection against the download
203 // being destroyed between creation and return of WaitForNewDownloadItem();
204 // the caller must guarantee that in some other fashion.
WaitForDownloadItem(std::vector<DownloadItem * > * items_seen)205 void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) {
206 if (!manager_) {
207 // The manager went away before we were asked to wait; return
208 // what we have, even if it's null.
209 *items_seen = items_seen_;
210 return;
211 }
212
213 if (items_seen_.empty()) {
214 waiting_ = true;
215 content::RunMessageLoop();
216 waiting_ = false;
217 }
218
219 *items_seen = items_seen_;
220 return;
221 }
222
223 private:
224 // DownloadManager::Observer
OnDownloadCreated(DownloadManager * manager,DownloadItem * item)225 virtual void OnDownloadCreated(
226 DownloadManager* manager, DownloadItem* item) OVERRIDE {
227 DCHECK_EQ(manager, manager_);
228 items_seen_.push_back(item);
229
230 if (waiting_)
231 base::MessageLoopForUI::current()->Quit();
232 }
233
ManagerGoingDown(DownloadManager * manager)234 virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
235 manager_->RemoveObserver(this);
236 manager_ = NULL;
237 if (waiting_)
238 base::MessageLoopForUI::current()->Quit();
239 }
240
241 bool waiting_;
242 DownloadManager* manager_;
243 std::vector<DownloadItem*> items_seen_;
244
245 DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver);
246 };
247
248 class SavePackageFinishedObserver : public content::DownloadManager::Observer {
249 public:
SavePackageFinishedObserver(content::DownloadManager * manager,const base::Closure & callback)250 SavePackageFinishedObserver(content::DownloadManager* manager,
251 const base::Closure& callback)
252 : download_manager_(manager),
253 callback_(callback) {
254 download_manager_->AddObserver(this);
255 }
256
~SavePackageFinishedObserver()257 virtual ~SavePackageFinishedObserver() {
258 if (download_manager_)
259 download_manager_->RemoveObserver(this);
260 }
261
262 // DownloadManager::Observer:
OnSavePackageSuccessfullyFinished(content::DownloadManager * manager,content::DownloadItem * item)263 virtual void OnSavePackageSuccessfullyFinished(
264 content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE {
265 callback_.Run();
266 }
ManagerGoingDown(content::DownloadManager * manager)267 virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE {
268 download_manager_->RemoveObserver(this);
269 download_manager_ = NULL;
270 }
271
272 private:
273 content::DownloadManager* download_manager_;
274 base::Closure callback_;
275
276 DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
277 };
278
279 class SavePageBrowserTest : public InProcessBrowserTest {
280 public:
SavePageBrowserTest()281 SavePageBrowserTest() {}
282 virtual ~SavePageBrowserTest();
283
284 protected:
SetUp()285 virtual void SetUp() OVERRIDE {
286 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
287 ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
288 InProcessBrowserTest::SetUp();
289 }
290
SetUpOnMainThread()291 virtual void SetUpOnMainThread() OVERRIDE {
292 browser()->profile()->GetPrefs()->SetFilePath(
293 prefs::kDownloadDefaultDirectory, save_dir_.path());
294 browser()->profile()->GetPrefs()->SetFilePath(
295 prefs::kSaveFileDefaultDirectory, save_dir_.path());
296 BrowserThread::PostTask(
297 BrowserThread::IO, FROM_HERE,
298 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
299 }
300
NavigateToMockURL(const std::string & prefix)301 GURL NavigateToMockURL(const std::string& prefix) {
302 GURL url = URLRequestMockHTTPJob::GetMockUrl(
303 base::FilePath(kTestDir).AppendASCII(prefix + ".htm"));
304 ui_test_utils::NavigateToURL(browser(), url);
305 return url;
306 }
307
308 // Returns full paths of destination file and directory.
GetDestinationPaths(const std::string & prefix,base::FilePath * full_file_name,base::FilePath * dir)309 void GetDestinationPaths(const std::string& prefix,
310 base::FilePath* full_file_name,
311 base::FilePath* dir) {
312 *full_file_name = save_dir_.path().AppendASCII(prefix + ".htm");
313 *dir = save_dir_.path().AppendASCII(prefix + "_files");
314 }
315
GetCurrentTab(Browser * browser) const316 WebContents* GetCurrentTab(Browser* browser) const {
317 WebContents* current_tab =
318 browser->tab_strip_model()->GetActiveWebContents();
319 EXPECT_TRUE(current_tab);
320 return current_tab;
321 }
322
323 // Returns true if and when there was a single download created, and its url
324 // is |expected_url|.
VerifySavePackageExpectations(Browser * browser,const GURL & expected_url) const325 bool VerifySavePackageExpectations(
326 Browser* browser,
327 const GURL& expected_url) const {
328 // Generally, there should only be one download item created
329 // in all of these tests. If it's already here, grab it; if not,
330 // wait for it to show up.
331 std::vector<DownloadItem*> items;
332 DownloadManager* manager(
333 BrowserContext::GetDownloadManager(browser->profile()));
334 manager->GetAllDownloads(&items);
335 if (items.size() == 0u) {
336 DownloadItemCreatedObserver(manager).WaitForDownloadItem(&items);
337 }
338
339 EXPECT_EQ(1u, items.size());
340 if (1u != items.size())
341 return false;
342 DownloadItem* download_item(items[0]);
343
344 return (expected_url == download_item->GetOriginalUrl());
345 }
346
347 // Note on synchronization:
348 //
349 // For each Save Page As operation, we create a corresponding shell
350 // DownloadItem to display progress to the user. That DownloadItem goes
351 // through its own state transitions, including being persisted out to the
352 // history database, and the download shelf is not shown until after the
353 // persistence occurs. Save Package completion (and marking the DownloadItem
354 // as completed) occurs asynchronously from persistence. Thus if we want to
355 // examine either UI state or DB state, we need to wait until both the save
356 // package operation is complete and the relevant download item has been
357 // persisted.
358
GetDownloadManager() const359 DownloadManager* GetDownloadManager() const {
360 DownloadManager* download_manager =
361 BrowserContext::GetDownloadManager(browser()->profile());
362 EXPECT_TRUE(download_manager);
363 return download_manager;
364 }
365
366 // Path to directory containing test data.
367 base::FilePath test_dir_;
368
369 // Temporary directory we will save pages to.
370 base::ScopedTempDir save_dir_;
371
372 private:
373 DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest);
374 };
375
~SavePageBrowserTest()376 SavePageBrowserTest::~SavePageBrowserTest() {
377 }
378
379 // Disabled on Windows due to flakiness. http://crbug.com/162323
380 #if defined(OS_WIN)
381 #define MAYBE_SaveHTMLOnly DISABLED_SaveHTMLOnly
382 #else
383 #define MAYBE_SaveHTMLOnly SaveHTMLOnly
384 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_SaveHTMLOnly)385 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnly) {
386 GURL url = NavigateToMockURL("a");
387
388 base::FilePath full_file_name, dir;
389 GetDestinationPaths("a", &full_file_name, &dir);
390 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
391 &DownloadStoredProperly, url, full_file_name, 1,
392 DownloadItem::COMPLETE));
393 scoped_refptr<content::MessageLoopRunner> loop_runner(
394 new content::MessageLoopRunner);
395 SavePackageFinishedObserver observer(
396 content::BrowserContext::GetDownloadManager(browser()->profile()),
397 loop_runner->QuitClosure());
398 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
399 content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
400 loop_runner->Run();
401 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
402 persisted.WaitForPersisted();
403 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
404 EXPECT_TRUE(base::PathExists(full_file_name));
405 EXPECT_FALSE(base::PathExists(dir));
406 EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
407 kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
408 }
409
410 // http://crbug.com/162323
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,DISABLED_SaveHTMLOnlyCancel)411 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) {
412 GURL url = NavigateToMockURL("a");
413 DownloadManager* manager(GetDownloadManager());
414 std::vector<DownloadItem*> downloads;
415 manager->GetAllDownloads(&downloads);
416 ASSERT_EQ(0u, downloads.size());
417
418 base::FilePath full_file_name, dir;
419 GetDestinationPaths("a", &full_file_name, &dir);
420 DownloadItemCreatedObserver creation_observer(manager);
421 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
422 &DownloadStoredProperly, url, full_file_name, -1,
423 DownloadItem::CANCELLED));
424 // -1 to disable number of files check; we don't update after cancel, and
425 // we don't know when the single file completed in relationship to
426 // the cancel.
427
428 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
429 content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
430 std::vector<DownloadItem*> items;
431 creation_observer.WaitForDownloadItem(&items);
432 ASSERT_EQ(1UL, items.size());
433 ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec());
434 items[0]->Cancel(true);
435 // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package.
436 // Currently it's ignored.
437
438 persisted.WaitForPersisted();
439
440 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
441
442 // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished
443 // notification, then expect the contents of the downloaded file.
444 }
445
446 class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
447 public:
DelayingDownloadManagerDelegate(Profile * profile)448 explicit DelayingDownloadManagerDelegate(Profile* profile)
449 : ChromeDownloadManagerDelegate(profile) {
450 }
~DelayingDownloadManagerDelegate()451 virtual ~DelayingDownloadManagerDelegate() {}
452
ShouldCompleteDownload(content::DownloadItem * item,const base::Closure & user_complete_callback)453 virtual bool ShouldCompleteDownload(
454 content::DownloadItem* item,
455 const base::Closure& user_complete_callback) OVERRIDE {
456 return false;
457 }
458
459 private:
460 DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate);
461 };
462
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,SaveHTMLOnlyTabDestroy)463 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) {
464 GURL url = NavigateToMockURL("a");
465 scoped_ptr<DelayingDownloadManagerDelegate> delaying_delegate(
466 new DelayingDownloadManagerDelegate(browser()->profile()));
467 delaying_delegate->GetDownloadIdReceiverCallback().Run(
468 content::DownloadItem::kInvalidId + 1);
469 DownloadServiceFactory::GetForBrowserContext(browser()->profile())->
470 SetDownloadManagerDelegateForTesting(
471 delaying_delegate.PassAs<ChromeDownloadManagerDelegate>());
472 DownloadManager* manager(GetDownloadManager());
473 std::vector<DownloadItem*> downloads;
474 manager->GetAllDownloads(&downloads);
475 ASSERT_EQ(0u, downloads.size());
476
477 base::FilePath full_file_name, dir;
478 GetDestinationPaths("a", &full_file_name, &dir);
479 DownloadItemCreatedObserver creation_observer(manager);
480 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
481 content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
482 std::vector<DownloadItem*> items;
483 creation_observer.WaitForDownloadItem(&items);
484 ASSERT_TRUE(items.size() == 1);
485
486 // Close the tab; does this cancel the download?
487 GetCurrentTab(browser())->Close();
488 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
489
490 EXPECT_FALSE(base::PathExists(full_file_name));
491 EXPECT_FALSE(base::PathExists(dir));
492 }
493
494 // Disabled on Windows due to flakiness. http://crbug.com/162323
495 #if defined(OS_WIN)
496 #define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly
497 #else
498 #define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly
499 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_SaveViewSourceHTMLOnly)500 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) {
501 base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
502 GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
503 base::FilePath(kTestDir).Append(file_name));
504 GURL actual_page_url = URLRequestMockHTTPJob::GetMockUrl(
505 base::FilePath(kTestDir).Append(file_name));
506 ui_test_utils::NavigateToURL(browser(), view_source_url);
507
508 base::FilePath full_file_name, dir;
509 GetDestinationPaths("a", &full_file_name, &dir);
510 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
511 &DownloadStoredProperly, actual_page_url, full_file_name, 1,
512 DownloadItem::COMPLETE));
513 scoped_refptr<content::MessageLoopRunner> loop_runner(
514 new content::MessageLoopRunner);
515 SavePackageFinishedObserver observer(
516 content::BrowserContext::GetDownloadManager(browser()->profile()),
517 loop_runner->QuitClosure());
518 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
519 content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
520 loop_runner->Run();
521 ASSERT_TRUE(VerifySavePackageExpectations(browser(), actual_page_url));
522 persisted.WaitForPersisted();
523
524 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
525
526 EXPECT_TRUE(base::PathExists(full_file_name));
527 EXPECT_FALSE(base::PathExists(dir));
528 EXPECT_TRUE(base::ContentsEqual(
529 test_dir_.Append(base::FilePath(kTestDir)).Append(file_name),
530 full_file_name));
531 }
532
533 // Disabled on Windows due to flakiness. http://crbug.com/162323
534 #if defined(OS_WIN)
535 #define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML
536 #else
537 #define MAYBE_SaveCompleteHTML SaveCompleteHTML
538 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_SaveCompleteHTML)539 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) {
540 GURL url = NavigateToMockURL("b");
541
542 base::FilePath full_file_name, dir;
543 GetDestinationPaths("b", &full_file_name, &dir);
544 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
545 &DownloadStoredProperly, url, full_file_name, 3,
546 DownloadItem::COMPLETE));
547 scoped_refptr<content::MessageLoopRunner> loop_runner(
548 new content::MessageLoopRunner);
549 SavePackageFinishedObserver observer(
550 content::BrowserContext::GetDownloadManager(browser()->profile()),
551 loop_runner->QuitClosure());
552 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
553 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
554 loop_runner->Run();
555 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
556 persisted.WaitForPersisted();
557
558 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
559
560 EXPECT_TRUE(base::PathExists(full_file_name));
561 EXPECT_TRUE(base::PathExists(dir));
562 EXPECT_TRUE(base::TextContentsEqual(
563 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
564 full_file_name));
565 EXPECT_TRUE(base::ContentsEqual(
566 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
567 dir.AppendASCII("1.png")));
568 EXPECT_TRUE(base::ContentsEqual(
569 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
570 dir.AppendASCII("1.css")));
571 }
572
573 // Invoke a save page during the initial navigation.
574 // (Regression test for http://crbug.com/156538).
575 // Disabled on Windows due to flakiness. http://crbug.com/162323
576 #if defined(OS_WIN)
577 #define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito
578 #else
579 #define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito
580 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_SaveDuringInitialNavigationIncognito)581 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
582 MAYBE_SaveDuringInitialNavigationIncognito) {
583 // Open an Incognito window.
584 Browser* incognito = CreateIncognitoBrowser(); // Waits.
585 ASSERT_TRUE(incognito);
586
587 // Create a download item creation waiter on that window.
588 DownloadItemCreatedObserver creation_observer(
589 BrowserContext::GetDownloadManager(incognito->profile()));
590
591 // Navigate, unblocking with new tab.
592 GURL url = URLRequestMockHTTPJob::GetMockUrl(
593 base::FilePath(kTestDir).AppendASCII("b.htm"));
594 NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB,
595 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
596
597 // Save the page before completion.
598 base::FilePath full_file_name, dir;
599 GetDestinationPaths("b", &full_file_name, &dir);
600 scoped_refptr<content::MessageLoopRunner> loop_runner(
601 new content::MessageLoopRunner);
602 SavePackageFinishedObserver observer(
603 content::BrowserContext::GetDownloadManager(incognito->profile()),
604 loop_runner->QuitClosure());
605 ASSERT_TRUE(GetCurrentTab(incognito)->SavePage(
606 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
607
608 loop_runner->Run();
609 ASSERT_TRUE(VerifySavePackageExpectations(incognito, url));
610
611 // Confirm download shelf is visible.
612 EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible());
613
614 // We can't check more than this because SavePackage is racing with
615 // the page load. If the page load won the race, then SavePackage
616 // might have completed. If the page load lost the race, then
617 // SavePackage will cancel because there aren't any resources to
618 // save.
619 }
620
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,NoSave)621 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
622 ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL));
623 EXPECT_FALSE(chrome::CanSavePage(browser()));
624 }
625
626 // Disabled on Windows due to flakiness. http://crbug.com/162323
627 #if defined(OS_WIN)
628 #define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle
629 #else
630 #define MAYBE_FileNameFromPageTitle FileNameFromPageTitle
631 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_FileNameFromPageTitle)632 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_FileNameFromPageTitle) {
633 GURL url = NavigateToMockURL("b");
634
635 base::FilePath full_file_name = save_dir_.path().AppendASCII(
636 std::string("Test page for saving page feature") + kAppendedExtension);
637 base::FilePath dir = save_dir_.path().AppendASCII(
638 "Test page for saving page feature_files");
639 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
640 &DownloadStoredProperly, url, full_file_name, 3,
641 DownloadItem::COMPLETE));
642 scoped_refptr<content::MessageLoopRunner> loop_runner(
643 new content::MessageLoopRunner);
644 SavePackageFinishedObserver observer(
645 content::BrowserContext::GetDownloadManager(browser()->profile()),
646 loop_runner->QuitClosure());
647 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
648 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
649
650 loop_runner->Run();
651 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
652 persisted.WaitForPersisted();
653
654 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
655
656 EXPECT_TRUE(base::PathExists(full_file_name));
657 EXPECT_TRUE(base::PathExists(dir));
658 EXPECT_TRUE(base::TextContentsEqual(
659 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved2.htm"),
660 full_file_name));
661 EXPECT_TRUE(base::ContentsEqual(
662 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
663 dir.AppendASCII("1.png")));
664 EXPECT_TRUE(base::ContentsEqual(
665 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
666 dir.AppendASCII("1.css")));
667 }
668
669 // Disabled on Windows due to flakiness. http://crbug.com/162323
670 #if defined(OS_WIN)
671 #define MAYBE_RemoveFromList DISABLED_RemoveFromList
672 #else
673 #define MAYBE_RemoveFromList RemoveFromList
674 #endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,MAYBE_RemoveFromList)675 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) {
676 GURL url = NavigateToMockURL("a");
677
678 base::FilePath full_file_name, dir;
679 GetDestinationPaths("a", &full_file_name, &dir);
680 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
681 &DownloadStoredProperly, url, full_file_name, 1,
682 DownloadItem::COMPLETE));
683 scoped_refptr<content::MessageLoopRunner> loop_runner(
684 new content::MessageLoopRunner);
685 SavePackageFinishedObserver observer(
686 content::BrowserContext::GetDownloadManager(browser()->profile()),
687 loop_runner->QuitClosure());
688 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
689 content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
690
691 loop_runner->Run();
692 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
693 persisted.WaitForPersisted();
694
695 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
696
697 DownloadManager* manager(GetDownloadManager());
698 std::vector<DownloadItem*> downloads;
699 manager->GetAllDownloads(&downloads);
700 ASSERT_EQ(1UL, downloads.size());
701 DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId());
702
703 EXPECT_EQ(manager->RemoveAllDownloads(), 1);
704
705 removed.WaitForRemoved();
706
707 EXPECT_TRUE(base::PathExists(full_file_name));
708 EXPECT_FALSE(base::PathExists(dir));
709 EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
710 kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
711 }
712
713 // This tests that a webpage with the title "test.exe" is saved as
714 // "test.exe.htm".
715 // We probably don't care to handle this on Linux or Mac.
716 #if defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,CleanFilenameFromPageTitle)717 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) {
718 const base::FilePath file_name(FILE_PATH_LITERAL("c.htm"));
719 base::FilePath download_dir =
720 DownloadPrefs::FromDownloadManager(GetDownloadManager())->
721 DownloadPath();
722 base::FilePath full_file_name =
723 download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension);
724 base::FilePath dir = download_dir.AppendASCII("test.exe_files");
725
726 EXPECT_FALSE(base::PathExists(full_file_name));
727 GURL url = URLRequestMockHTTPJob::GetMockUrl(
728 base::FilePath(kTestDir).Append(file_name));
729 ui_test_utils::NavigateToURL(browser(), url);
730
731 SavePackageFilePicker::SetShouldPromptUser(false);
732 scoped_refptr<content::MessageLoopRunner> loop_runner(
733 new content::MessageLoopRunner);
734 SavePackageFinishedObserver observer(
735 content::BrowserContext::GetDownloadManager(browser()->profile()),
736 loop_runner->QuitClosure());
737 chrome::SavePage(browser());
738 loop_runner->Run();
739
740 EXPECT_TRUE(base::PathExists(full_file_name));
741
742 EXPECT_TRUE(file_util::DieFileDie(full_file_name, false));
743 EXPECT_TRUE(file_util::DieFileDie(dir, true));
744 }
745 #endif
746
747 class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest {
748 public:
SavePageAsMHTMLBrowserTest()749 SavePageAsMHTMLBrowserTest() {}
750 virtual ~SavePageAsMHTMLBrowserTest();
SetUpCommandLine(CommandLine * command_line)751 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
752 command_line->AppendSwitch(switches::kSavePageAsMHTML);
753 }
754
755 private:
756 DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest);
757 };
758
~SavePageAsMHTMLBrowserTest()759 SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() {
760 }
761
IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest,SavePageAsMHTML)762 IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) {
763 static const int64 kFileSizeMin = 2758;
764 GURL url = NavigateToMockURL("b");
765 base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
766 GetDownloadManager())->DownloadPath();
767 base::FilePath full_file_name = download_dir.AppendASCII(std::string(
768 "Test page for saving page feature.mhtml"));
769 SavePackageFilePicker::SetShouldPromptUser(false);
770 DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
771 &DownloadStoredProperly, url, full_file_name, -1,
772 DownloadItem::COMPLETE));
773 scoped_refptr<content::MessageLoopRunner> loop_runner(
774 new content::MessageLoopRunner);
775 SavePackageFinishedObserver observer(
776 content::BrowserContext::GetDownloadManager(browser()->profile()),
777 loop_runner->QuitClosure());
778 chrome::SavePage(browser());
779 loop_runner->Run();
780 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
781 persisted.WaitForPersisted();
782
783 ASSERT_TRUE(base::PathExists(full_file_name));
784 int64 actual_file_size = -1;
785 EXPECT_TRUE(base::GetFileSize(full_file_name, &actual_file_size));
786 EXPECT_LE(kFileSizeMin, actual_file_size);
787 }
788
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,SavePageBrowserTest_NonMHTML)789 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) {
790 SavePackageFilePicker::SetShouldPromptUser(false);
791 GURL url("data:text/plain,foo");
792 ui_test_utils::NavigateToURL(browser(), url);
793 scoped_refptr<content::MessageLoopRunner> loop_runner(
794 new content::MessageLoopRunner);
795 SavePackageFinishedObserver observer(
796 content::BrowserContext::GetDownloadManager(browser()->profile()),
797 loop_runner->QuitClosure());
798 chrome::SavePage(browser());
799 loop_runner->Run();
800 base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
801 GetDownloadManager())->DownloadPath();
802 base::FilePath filename = download_dir.AppendASCII("dataurl.txt");
803 ASSERT_TRUE(base::PathExists(filename));
804 std::string contents;
805 EXPECT_TRUE(base::ReadFileToString(filename, &contents));
806 EXPECT_EQ("foo", contents);
807 }
808
809 } // namespace
810
811