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..9befc69dd1e63d4cdf5b239525a12cf2f674b54f 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,14 +227,39 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
return current_tab; |
} |
- |
- GURL WaitForSavePackageToFinish() const { |
+ bool WaitForSavePackageToFinish(GURL* url_at_finish) const { |
content::WindowedNotificationObserver observer( |
content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
content::NotificationService::AllSources()); |
observer.Wait(); |
- return content::Details<DownloadItem>(observer.details()).ptr()-> |
+ |
+ // 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); |
+ |
+ EXPECT_EQ(1u, items.size()); |
+ if (1u != items.size()) |
+ return false; |
+ 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(); |
+ |
+ *url_at_finish = content::Details<DownloadItem>(observer.details()).ptr()-> |
GetOriginalUrl(); |
+ return true; |
} |
DownloadManager* GetDownloadManager() const { |
@@ -209,11 +296,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 +311,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 +361,8 @@ class SavePageBrowserTest : public InProcessBrowserTest { |
ScopedTempDir save_dir_; |
private: |
+ scoped_ptr<DownloadItemCreatedObserver> item_creation_observer_; |
+ |
DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest); |
}; |
@@ -279,10 +377,13 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnly) { |
ASSERT_TRUE(GetCurrentTab()->SavePage(full_file_name, dir, |
content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); |
- EXPECT_EQ(url, WaitForSavePackageToFinish()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(url, output_url); |
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 +404,23 @@ 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()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(url, output_url); |
+ |
+ // -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 +443,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)); |
@@ -357,10 +468,14 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveViewSourceHTMLOnly) { |
ASSERT_TRUE(GetCurrentTab()->SavePage(full_file_name, dir, |
content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); |
- EXPECT_EQ(actual_page_url, WaitForSavePackageToFinish()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(actual_page_url, output_url); |
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)); |
@@ -377,10 +492,13 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveCompleteHTML) { |
ASSERT_TRUE(GetCurrentTab()->SavePage( |
full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); |
- EXPECT_EQ(url, WaitForSavePackageToFinish()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(url, output_url); |
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)); |
@@ -410,10 +528,13 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, FileNameFromPageTitle) { |
ASSERT_TRUE(GetCurrentTab()->SavePage( |
full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); |
- EXPECT_EQ(url, WaitForSavePackageToFinish()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(url, output_url); |
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)); |
@@ -436,17 +557,21 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, RemoveFromList) { |
ASSERT_TRUE(GetCurrentTab()->SavePage(full_file_name, dir, |
content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); |
- EXPECT_EQ(url, WaitForSavePackageToFinish()); |
+ GURL output_url; |
+ ASSERT_TRUE(WaitForSavePackageToFinish(&output_url)); |
+ EXPECT_EQ(url, output_url); |
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 +645,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; |