Chromium Code Reviews| Index: chrome/browser/download/save_page_browsertest.cc |
| diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc |
| index bbf65f77c2940b27a49c788b5638a4ae0699ffc0..670af92968ceac7efccbe793ad565783907831fc 100644 |
| --- a/chrome/browser/download/save_page_browsertest.cc |
| +++ b/chrome/browser/download/save_page_browsertest.cc |
| @@ -64,13 +64,16 @@ static const char* kAppendedExtension = |
| ".html"; |
| #endif |
| +void NullFunction() { |
| +} |
| + |
| } // namespace |
| // Loosely based on logic in DownloadTestObserver. |
| class DownloadItemCreatedObserver : public DownloadManager::Observer { |
| public: |
| explicit DownloadItemCreatedObserver(DownloadManager* manager) |
| - : waiting_(false), manager_(manager), created_item_(NULL) { |
| + : waiting_(false), manager_(manager) { |
| manager->AddObserver(this); |
| } |
| @@ -83,34 +86,37 @@ class DownloadItemCreatedObserver : public DownloadManager::Observer { |
| // Note that this class provides no protection against the download |
| // being destroyed between creation and return of WaitForNewDownloadItem(); |
| // the caller must guarantee that in some other fashion. |
| - DownloadItem* WaitForNewDownloadItem() { |
| + void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) { |
| if (!manager_) { |
| // The manager went away before we were asked to wait; return |
| // what we have, even if it's null. |
| - return created_item_; |
| + *items_seen = items_seen_; |
| + return; |
| } |
| - if (!created_item_) { |
| + if (items_seen_.empty()) { |
| waiting_ = true; |
| content::RunMessageLoop(); |
| waiting_ = false; |
| } |
| - return created_item_; |
| + |
| + *items_seen = items_seen_; |
| + return; |
| } |
| private: |
| // DownloadManager::Observer |
| - void OnDownloadCreated(DownloadManager* manager, DownloadItem* item) { |
| + virtual void OnDownloadCreated( |
| + DownloadManager* manager, DownloadItem* item) OVERRIDE { |
| DCHECK_EQ(manager, manager_); |
| - if (!created_item_) |
| - created_item_ = item; |
| + items_seen_.push_back(item); |
| if (waiting_) |
| MessageLoopForUI::current()->Quit(); |
| } |
| - void ManagerGoingDownload(DownloadManager* manager) { |
| + virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE { |
| manager_->RemoveObserver(this); |
| manager_ = NULL; |
| if (waiting_) |
| @@ -119,11 +125,65 @@ class DownloadItemCreatedObserver : public DownloadManager::Observer { |
| bool waiting_; |
| DownloadManager* manager_; |
| - DownloadItem* created_item_; |
| + std::vector<DownloadItem*> items_seen_; |
| DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver); |
| }; |
| +class DownloadPersistedObserver : public DownloadItem::Observer { |
| + public: |
| + explicit DownloadPersistedObserver(DownloadItem* item) |
| + : waiting_(false), item_(item) { |
| + item->AddObserver(this); |
| + } |
| + |
| + ~DownloadPersistedObserver() { |
| + if (item_) |
| + item_->RemoveObserver(this); |
| + } |
| + |
| + // Wait for download item to get the persisted bit set. |
| + // Note that this class provides no protection against the download |
| + // being destroyed between creation and return of WaitForPersisted(); |
| + // the caller must guarantee that in some other fashion. |
| + void WaitForPersisted() { |
| + // In combination with OnDownloadDestroyed() below, verify the |
| + // above interface contract. |
| + DCHECK(item_); |
| + |
| + if (item_->IsPersisted()) |
| + return; |
| + |
| + waiting_ = true; |
| + content::RunMessageLoop(); |
| + waiting_ = false; |
| + |
| + return; |
| + } |
| + |
| + private: |
| + // DownloadItem::Observer |
| + virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE { |
| + DCHECK_EQ(item, item_); |
| + |
| + if (waiting_ && item->IsPersisted()) |
| + MessageLoopForUI::current()->Quit(); |
| + } |
| + |
| + virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE { |
| + if (item != item_) |
| + return; |
| + |
| + item_->RemoveObserver(this); |
| + item_ = NULL; |
| + } |
| + |
| + bool waiting_; |
| + DownloadItem* item_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DownloadPersistedObserver); |
| +}; |
| + |
| class SavePageBrowserTest : public InProcessBrowserTest { |
| public: |
| SavePageBrowserTest() {} |
| @@ -142,6 +202,8 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); |
| + item_creation_observer_.reset( |
| + new DownloadItemCreatedObserver(GetDownloadManager())); |
| } |
| GURL NavigateToMockURL(const std::string& prefix) { |
| @@ -165,12 +227,34 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
| return current_tab; |
| } |
| - |
| GURL WaitForSavePackageToFinish() const { |
| content::WindowedNotificationObserver observer( |
| content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| content::NotificationService::AllSources()); |
| observer.Wait(); |
| + |
| + // Generally, there should only be one download item created |
| + // in all of these tests. Wait for it, and wait for it to |
| + // be persisted. |
| + std::vector<DownloadItem*> items; |
| + item_creation_observer_->WaitForDownloadItem(&items); |
| + |
| + DCHECK_EQ(1u, items.size()); |
|
benjhayden
2012/09/10 14:39:58
CHECK instead of DCHECK?
Randy Smith (Not in Mondays)
2012/09/10 17:53:16
I think of both CHECKs and DCHECKs as being discou
|
| + DownloadItem* download_item(items[0]); |
| + |
| + // Note on synchronization: |
| + // |
| + // For each Save Page As operation, we create a corresponding shell |
| + // DownloadItem to display progress to the user. That DownloadItem |
| + // goes through its own state transitions, including being persisted |
| + // out to the history database, and the download shelf is not shown |
| + // until after the persistence occurs. Save Package completion (and |
| + // marking the DownloadItem as completed) occurs asynchronously from |
| + // persistence. Thus if we want to examine either UI state or DB |
| + // state, we need to wait until both the save package operation is |
| + // complete and the relevant download item has been persisted. |
| + DownloadPersistedObserver(download_item).WaitForPersisted(); |
| + |
| return content::Details<DownloadItem>(observer.details()).ptr()-> |
| GetOriginalUrl(); |
| } |
| @@ -209,11 +293,12 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
| DownloadPersistentStoreInfoMatch(const GURL& url, |
| const FilePath& path, |
| - int64 num_files) |
| + int64 num_files, |
| + DownloadItem::DownloadState state) |
| : url_(url), |
| path_(path), |
| - num_files_(num_files) { |
| - } |
| + num_files_(num_files), |
| + state_(state) {} |
| bool operator() (const DownloadPersistentStoreInfo& info) const { |
| return info.url == url_ && |
| @@ -223,22 +308,30 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
| ((num_files_ < 0) || |
| (info.received_bytes == num_files_)) && |
| info.total_bytes == 0 && |
| - info.state == DownloadItem::COMPLETE; |
| + info.state == state_; |
| } |
| GURL url_; |
| FilePath path_; |
| int64 num_files_; |
| + DownloadItem::DownloadState state_; |
| }; |
| void CheckDownloadHistory(const GURL& url, |
| const FilePath& path, |
| - int64 num_files) { |
| + int64 num_files, |
| + DownloadItem::DownloadState state) { |
| + // Make sure the relevant download item made it into the history. |
| + std::vector<DownloadItem*> downloads; |
| + GetDownloadManager()->SearchDownloads(string16(), &downloads); |
| + ASSERT_EQ(1u, downloads.size()); |
| + |
| QueryDownloadHistory(); |
| std::vector<DownloadPersistentStoreInfo>::iterator found = |
| std::find_if(history_entries_.begin(), history_entries_.end(), |
| - DownloadPersistentStoreInfoMatch(url, path, num_files)); |
| + DownloadPersistentStoreInfoMatch(url, path, num_files, |
| + state)); |
| if (found == history_entries_.end()) { |
| LOG(ERROR) << "Missing url=" << url.spec() |
| @@ -265,6 +358,8 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
| ScopedTempDir save_dir_; |
| private: |
| + scoped_ptr<DownloadItemCreatedObserver> item_creation_observer_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest); |
| }; |
| @@ -282,7 +377,8 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnly) { |
| EXPECT_EQ(url, WaitForSavePackageToFinish()); |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(url, full_file_name, 1); // a.htm is 1 file. |
| + // a.htm is 1 file. |
| + CheckDownloadHistory(url, full_file_name, 1, DownloadItem::COMPLETE); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| EXPECT_FALSE(file_util::PathExists(dir)); |
| @@ -303,15 +399,21 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyCancel) { |
| DownloadItemCreatedObserver creation_observer(manager); |
| ASSERT_TRUE(GetCurrentTab()->SavePage(full_file_name, dir, |
| content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); |
| - DownloadItem* item = creation_observer.WaitForNewDownloadItem(); |
| - item->Cancel(true); |
| + std::vector<DownloadItem*> items; |
| + creation_observer.WaitForDownloadItem(&items); |
| + ASSERT_TRUE(items.size() == 1); |
| + items[0]->Cancel(true); |
| // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package. |
| // Currently it's ignored. |
| EXPECT_EQ(url, WaitForSavePackageToFinish()); |
| + // -1 to disable number of files check; we don't update after cancel, and |
| + // we don't know when the single file completed in relationship to |
| + // the cancel. |
| + CheckDownloadHistory(url, full_file_name, -1, DownloadItem::CANCELLED); |
| + |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(url, full_file_name, 1); // a.htm is 1 file. |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| EXPECT_FALSE(file_util::PathExists(dir)); |
| @@ -334,11 +436,13 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyTabDestroy) { |
| DownloadItemCreatedObserver creation_observer(manager); |
| ASSERT_TRUE(GetCurrentTab()->SavePage(full_file_name, dir, |
| content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); |
| - DownloadItem* item = creation_observer.WaitForNewDownloadItem(); |
| + std::vector<DownloadItem*> items; |
| + creation_observer.WaitForDownloadItem(&items); |
| + ASSERT_TRUE(items.size() == 1); |
| // Close the tab; does this cancel the download? |
| GetCurrentTab()->Close(); |
| - EXPECT_TRUE(item->IsCancelled()); |
| + EXPECT_TRUE(items[0]->IsCancelled()); |
| EXPECT_FALSE(file_util::PathExists(full_file_name)); |
| EXPECT_FALSE(file_util::PathExists(dir)); |
| @@ -360,7 +464,9 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveViewSourceHTMLOnly) { |
| EXPECT_EQ(actual_page_url, WaitForSavePackageToFinish()); |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(actual_page_url, full_file_name, 1); // a.htm is 1 file. |
| + // a.htm is 1 file. |
| + CheckDownloadHistory(actual_page_url, full_file_name, 1, |
| + DownloadItem::COMPLETE); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| EXPECT_FALSE(file_util::PathExists(dir)); |
| @@ -380,7 +486,8 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveCompleteHTML) { |
| EXPECT_EQ(url, WaitForSavePackageToFinish()); |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(url, full_file_name, 3); // b.htm is 3 files. |
| + // b.htm is 3 files. |
| + CheckDownloadHistory(url, full_file_name, 3, DownloadItem::COMPLETE); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| EXPECT_TRUE(file_util::PathExists(dir)); |
| @@ -413,7 +520,8 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, FileNameFromPageTitle) { |
| EXPECT_EQ(url, WaitForSavePackageToFinish()); |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(url, full_file_name, 3); // b.htm is 3 files. |
| + // b.htm is 3 files. |
| + CheckDownloadHistory(url, full_file_name, 3, DownloadItem::COMPLETE); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| EXPECT_TRUE(file_util::PathExists(dir)); |
| @@ -439,14 +547,16 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, RemoveFromList) { |
| EXPECT_EQ(url, WaitForSavePackageToFinish()); |
| EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); |
| - CheckDownloadHistory(url, full_file_name, 1); // a.htm is 1 file. |
| + // a.htm is 1 file. |
| + CheckDownloadHistory(url, full_file_name, 1, DownloadItem::COMPLETE); |
| EXPECT_EQ(GetDownloadManager()->RemoveAllDownloads(), 1); |
| // Should not be in history. |
| QueryDownloadHistory(); |
| EXPECT_EQ(std::find_if(history_entries_.begin(), history_entries_.end(), |
| - DownloadPersistentStoreInfoMatch(url, full_file_name, 1)), |
| + DownloadPersistentStoreInfoMatch( |
| + url, full_file_name, 1, DownloadItem::COMPLETE)), |
| history_entries_.end()); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| @@ -520,7 +630,7 @@ IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) { |
| content::NotificationService::AllSources()); |
| chrome::SavePage(browser()); |
| observer.Wait(); |
| - CheckDownloadHistory(url, full_file_name, -1); |
| + CheckDownloadHistory(url, full_file_name, -1, DownloadItem::COMPLETE); |
| EXPECT_TRUE(file_util::PathExists(full_file_name)); |
| int64 actual_file_size = -1; |