Index: chrome/test/ui_test_utils.cc |
diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc |
index 60282bd5c6e7e970e63b17a169316c44ddf5d42f..ffe7a2ec51413410d89cc7b750ef99dbb478c4ea 100644 |
--- a/chrome/test/ui_test_utils.cc |
+++ b/chrome/test/ui_test_utils.cc |
@@ -10,6 +10,7 @@ |
#include "base/values.h" |
#include "chrome/browser/browser.h" |
#include "chrome/browser/dom_operation_notification_details.h" |
+#include "chrome/browser/download/download_manager.h" |
#include "chrome/browser/tab_contents/navigation_controller.h" |
#include "chrome/browser/tab_contents/tab_contents.h" |
#include "chrome/common/chrome_paths.h" |
@@ -98,6 +99,100 @@ class DOMOperationObserver : public NotificationObserver { |
DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver); |
}; |
+// DownloadsCompleteObserver waits for a given number of downloads to complete. |
+// Example usage: |
+// |
+// ui_test_utils::NavigateToURL(browser(), zip_url); |
+// DownloadsCompleteObserver wait_on_download( |
+// browser()->profile()->GetDownloadManager(), 1); |
+// /* |zip_url| download will be complete by this line. */ |
+// |
+class DownloadsCompleteObserver : public DownloadManager::Observer, |
+ public DownloadItem::Observer { |
+ public: |
+ explicit DownloadsCompleteObserver(DownloadManager* download_manager, |
+ size_t wait_count) |
+ : download_manager_(download_manager), |
+ wait_count_(wait_count), |
+ waiting_(false) { |
+ download_manager_->AddObserver(this); |
+ } |
+ |
+ // CheckAllDownloadsComplete will be called when the DownloadManager |
+ // fires it's ModelChanged() call, and also when incomplete downloads |
+ // fire their OnDownloadUpdated(). |
+ bool CheckAllDownloadsComplete() { |
+ if (downloads_.size() < wait_count_) |
+ return false; |
+ |
+ bool still_waiting = false; |
+ std::vector<DownloadItem*>::iterator it = downloads_.begin(); |
+ for (; it != downloads_.end(); ++it) { |
+ // We always remove ourselves as an observer, then re-add if the download |
+ // isn't complete. This is to avoid having to track which downloads we |
+ // are currently observing. Removing has no effect if we are not currently |
+ // an observer. |
+ (*it)->RemoveObserver(this); |
+ if ((*it)->state() != DownloadItem::COMPLETE) { |
+ (*it)->AddObserver(this); |
+ still_waiting = true; |
+ } |
+ } |
+ |
+ if (still_waiting) |
+ return false; |
+ |
+ download_manager_->RemoveObserver(this); |
+ // waiting_ will have been set if not all downloads were complete on first |
+ // pass below in SetDownloads(). |
+ if (waiting_) |
+ MessageLoopForUI::current()->Quit(); |
+ return true; |
+ } |
+ |
+ // DownloadItem::Observer |
+ virtual void OnDownloadUpdated(DownloadItem* download) { |
+ if (download->state() == DownloadItem::COMPLETE) { |
+ CheckAllDownloadsComplete(); |
+ } |
+ } |
+ |
+ virtual void OnDownloadOpened(DownloadItem* download) {} |
+ |
+ // DownloadManager::Observer |
+ virtual void ModelChanged() { |
+ download_manager_->GetDownloads(this, L""); |
+ } |
+ |
+ virtual void SetDownloads(std::vector<DownloadItem*>& downloads) { |
+ downloads_ = downloads; |
+ if (CheckAllDownloadsComplete()) |
+ return; |
+ |
+ if (!waiting_) { |
+ waiting_ = true; |
+ ui_test_utils::RunMessageLoop(); |
+ } |
+ } |
+ |
+ |
+ private: |
+ // The observed download manager. |
+ DownloadManager* download_manager_; |
+ |
+ // The current downloads being tracked. |
+ std::vector<DownloadItem*> downloads_; |
+ |
+ // The number of downloads to wait on completing. |
+ size_t wait_count_; |
+ |
+ // Whether an internal message loop has been started and must be quit upon |
+ // all downloads completing. |
+ bool waiting_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DownloadsCompleteObserver); |
+}; |
+ |
} // namespace |
void RunMessageLoop() { |
@@ -208,4 +303,8 @@ GURL GetTestUrl(const std::wstring& dir, const std::wstring file) { |
return net::FilePathToFileURL(path); |
} |
+void WaitForDownloadCount(DownloadManager* download_manager, size_t count) { |
+ DownloadsCompleteObserver download_observer(download_manager, count); |
+} |
+ |
} // namespace ui_test_utils |