Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 <vector> | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "base/stl_util.h" | |
| 10 #include "base/task.h" | |
| 11 #include "chrome/browser/download/download_test_observer.h" | |
| 12 #include "chrome/test/base/ui_test_utils.h" | |
| 13 #include "content/browser/browser_thread.h" | |
| 14 | |
| 15 // Fake user click on "Accept". | |
| 16 void AcceptDangerousDownload(scoped_refptr<DownloadManager> download_manager, | |
|
achuithb
2011/10/13 23:05:08
scoped_refptr because this function can get called
Randy Smith (Not in Mondays)
2011/10/14 00:37:41
Done.
achuithb
2011/10/14 19:22:10
SGTM.
| |
| 17 int32 download_id) { | |
| 18 DownloadItem* download = download_manager->GetDownloadItem(download_id); | |
| 19 download->DangerousDownloadValidated(); | |
| 20 } | |
| 21 | |
| 22 // Fake user click on "Deny". | |
| 23 void DenyDangerousDownload(scoped_refptr<DownloadManager> download_manager, | |
| 24 int32 download_id) { | |
| 25 DownloadItem* download = download_manager->GetDownloadItem(download_id); | |
| 26 ASSERT_TRUE(download->IsPartialDownload()); | |
| 27 download->Cancel(true); | |
| 28 download->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); | |
| 29 } | |
| 30 | |
| 31 DownloadTestObserver::DownloadTestObserver( | |
| 32 DownloadManager* download_manager, | |
| 33 size_t wait_count, | |
| 34 DownloadItem::DownloadState download_finished_state, | |
| 35 bool finish_on_select_file, | |
| 36 DangerousDownloadAction dangerous_download_action) | |
| 37 : download_manager_(download_manager), | |
| 38 wait_count_(wait_count), | |
| 39 finished_downloads_at_construction_(0), | |
| 40 waiting_(false), | |
| 41 download_finished_state_(download_finished_state), | |
| 42 finish_on_select_file_(finish_on_select_file), | |
| 43 select_file_dialog_seen_(false), | |
| 44 dangerous_download_action_(dangerous_download_action) { | |
| 45 download_manager_->AddObserver(this); // Will call initial ModelChanged(). | |
| 46 finished_downloads_at_construction_ = finished_downloads_.size(); | |
| 47 EXPECT_NE(DownloadItem::REMOVING, download_finished_state) | |
| 48 << "Waiting for REMOVING is not supported. Try COMPLETE."; | |
| 49 } | |
| 50 | |
| 51 DownloadTestObserver::~DownloadTestObserver() { | |
| 52 std::set<DownloadItem*>::iterator it = downloads_observed_.begin(); | |
| 53 for (; it != downloads_observed_.end(); ++it) | |
| 54 (*it)->RemoveObserver(this); | |
| 55 | |
| 56 download_manager_->RemoveObserver(this); | |
| 57 } | |
| 58 | |
| 59 void DownloadTestObserver::WaitForFinished() { | |
| 60 if (!IsFinished()) { | |
| 61 waiting_ = true; | |
| 62 ui_test_utils::RunMessageLoop(); | |
| 63 waiting_ = false; | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 bool DownloadTestObserver::IsFinished() { | |
| 68 if (finished_downloads_.size() - finished_downloads_at_construction_ | |
| 69 >= wait_count_) | |
|
achuithb
2011/10/13 23:05:08
>= should be on previous line.
Randy Smith (Not in Mondays)
2011/10/14 00:37:41
Done.
| |
| 70 return true; | |
| 71 return (finish_on_select_file_ && select_file_dialog_seen_); | |
| 72 } | |
| 73 | |
| 74 void DownloadTestObserver::OnDownloadUpdated(DownloadItem* download) { | |
| 75 // The REMOVING state indicates that the download is being destroyed. | |
| 76 // Stop observing. Do not do anything with it, as it is about to be gone. | |
| 77 if (download->state() == DownloadItem::REMOVING) { | |
| 78 std::set<DownloadItem*>::iterator it = downloads_observed_.find(download); | |
| 79 ASSERT_TRUE(it != downloads_observed_.end()); | |
| 80 downloads_observed_.erase(it); | |
| 81 download->RemoveObserver(this); | |
| 82 return; | |
| 83 } | |
| 84 | |
| 85 // Real UI code gets the user's response after returning from the observer. | |
| 86 if (download->safety_state() == DownloadItem::DANGEROUS && | |
| 87 !ContainsKey(dangerous_downloads_seen_, download->id())) { | |
| 88 dangerous_downloads_seen_.insert(download->id()); | |
| 89 | |
| 90 // Calling DangerousDownloadValidated() at this point will | |
| 91 // cause the download to be completed twice. Do what the real UI | |
| 92 // code does: make the call as a delayed task. | |
| 93 switch (dangerous_download_action_) { | |
| 94 case ON_DANGEROUS_DOWNLOAD_ACCEPT: | |
| 95 // Fake user click on "Accept". Delay the actual click, as the | |
| 96 // real UI would. | |
| 97 BrowserThread::PostTask( | |
| 98 BrowserThread::UI, FROM_HERE, | |
| 99 NewRunnableFunction( | |
| 100 &AcceptDangerousDownload, | |
| 101 download_manager_, | |
| 102 download->id())); | |
| 103 break; | |
| 104 | |
| 105 case ON_DANGEROUS_DOWNLOAD_DENY: | |
| 106 // Fake a user click on "Deny". Delay the actual click, as the | |
| 107 // real UI would. | |
| 108 BrowserThread::PostTask( | |
| 109 BrowserThread::UI, FROM_HERE, | |
| 110 NewRunnableFunction( | |
| 111 &DenyDangerousDownload, | |
| 112 download_manager_, | |
| 113 download->id())); | |
| 114 break; | |
| 115 | |
| 116 case ON_DANGEROUS_DOWNLOAD_FAIL: | |
| 117 ADD_FAILURE() << "Unexpected dangerous download item."; | |
| 118 break; | |
| 119 | |
| 120 default: | |
| 121 NOTREACHED(); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 if (download->state() == download_finished_state_) { | |
| 126 DownloadInFinalState(download); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 void DownloadTestObserver::ModelChanged() { | |
| 131 // Regenerate DownloadItem observers. If there are any download items | |
| 132 // in our final state, note them in |finished_downloads_| | |
| 133 // (done by |OnDownloadUpdated()|). | |
| 134 std::vector<DownloadItem*> downloads; | |
| 135 download_manager_->GetAllDownloads(FilePath(), &downloads); | |
| 136 | |
| 137 std::vector<DownloadItem*>::iterator it = downloads.begin(); | |
| 138 for (; it != downloads.end(); ++it) { | |
| 139 OnDownloadUpdated(*it); // Safe to call multiple times; checks state. | |
| 140 | |
| 141 std::set<DownloadItem*>::const_iterator | |
| 142 finished_it(finished_downloads_.find(*it)); | |
| 143 std::set<DownloadItem*>::iterator | |
| 144 observed_it(downloads_observed_.find(*it)); | |
| 145 | |
| 146 // If it isn't finished and we're aren't observing it, start. | |
| 147 if (finished_it == finished_downloads_.end() && | |
| 148 observed_it == downloads_observed_.end()) { | |
| 149 (*it)->AddObserver(this); | |
| 150 downloads_observed_.insert(*it); | |
| 151 continue; | |
| 152 } | |
| 153 | |
| 154 // If it is finished and we are observing it, stop. | |
| 155 if (finished_it != finished_downloads_.end() && | |
| 156 observed_it != downloads_observed_.end()) { | |
| 157 (*it)->RemoveObserver(this); | |
| 158 downloads_observed_.erase(observed_it); | |
| 159 continue; | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void DownloadTestObserver::SelectFileDialogDisplayed(int32 /* id */) { | |
| 165 select_file_dialog_seen_ = true; | |
| 166 SignalIfFinished(); | |
| 167 } | |
| 168 | |
| 169 size_t DownloadTestObserver::NumDangerousDownloadsSeen() const { | |
| 170 return dangerous_downloads_seen_.size(); | |
| 171 } | |
| 172 | |
| 173 void DownloadTestObserver::DownloadInFinalState(DownloadItem* download) { | |
| 174 if (finished_downloads_.find(download) != finished_downloads_.end()) { | |
| 175 // We've already seen terminal state on this download. | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 // Record the transition. | |
| 180 finished_downloads_.insert(download); | |
| 181 | |
| 182 SignalIfFinished(); | |
| 183 } | |
| 184 | |
| 185 void DownloadTestObserver::SignalIfFinished() { | |
| 186 if (waiting_ && IsFinished()) | |
| 187 MessageLoopForUI::current()->Quit(); | |
| 188 } | |
| 189 | |
| 190 DownloadTestFlushObserver::DownloadTestFlushObserver( | |
| 191 DownloadManager* download_manager) | |
| 192 : download_manager_(download_manager), | |
| 193 waiting_for_zero_inprogress_(true) {} | |
| 194 | |
| 195 void DownloadTestFlushObserver::WaitForFlush() { | |
| 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 197 download_manager_->AddObserver(this); | |
| 198 ui_test_utils::RunMessageLoop(); | |
| 199 } | |
| 200 | |
| 201 void DownloadTestFlushObserver::ModelChanged() { | |
| 202 // Model has changed, so there may be more DownloadItems to observe. | |
| 203 CheckDownloadsInProgress(true); | |
| 204 } | |
| 205 | |
| 206 void DownloadTestFlushObserver::OnDownloadUpdated(DownloadItem* download) { | |
| 207 // The REMOVING state indicates that the download is being destroyed. | |
| 208 // Stop observing. Do not do anything with it, as it is about to be gone. | |
| 209 if (download->state() == DownloadItem::REMOVING) { | |
| 210 std::set<DownloadItem*>::iterator it = downloads_observed_.find(download); | |
| 211 ASSERT_TRUE(it != downloads_observed_.end()); | |
| 212 downloads_observed_.erase(it); | |
| 213 download->RemoveObserver(this); | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 // No change in DownloadItem set on manager. | |
| 218 CheckDownloadsInProgress(false); | |
| 219 } | |
| 220 | |
| 221 DownloadTestFlushObserver::~DownloadTestFlushObserver() { | |
| 222 download_manager_->RemoveObserver(this); | |
| 223 for (std::set<DownloadItem*>::iterator it = downloads_observed_.begin(); | |
| 224 it != downloads_observed_.end(); ++it) { | |
| 225 (*it)->RemoveObserver(this); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 // If we're waiting for that flush point, check the number | |
| 230 // of downloads in the IN_PROGRESS state and take appropriate | |
| 231 // action. If requested, also observes all downloads while iterating. | |
| 232 void DownloadTestFlushObserver::CheckDownloadsInProgress( | |
| 233 bool observe_downloads) { | |
| 234 if (waiting_for_zero_inprogress_) { | |
| 235 int count = 0; | |
| 236 | |
| 237 std::vector<DownloadItem*> downloads; | |
| 238 download_manager_->SearchDownloads(string16(), &downloads); | |
| 239 std::vector<DownloadItem*>::iterator it = downloads.begin(); | |
|
achuithb
2011/10/13 23:05:08
You do this in a few other places; I think it's a
Randy Smith (Not in Mondays)
2011/10/14 00:37:41
Huh. Interesting. I agree with you--I wonder why
| |
| 240 for (; it != downloads.end(); ++it) { | |
| 241 if ((*it)->state() == DownloadItem::IN_PROGRESS) | |
| 242 count++; | |
| 243 if (observe_downloads) { | |
| 244 if (downloads_observed_.find(*it) == downloads_observed_.end()) { | |
| 245 (*it)->AddObserver(this); | |
| 246 downloads_observed_.insert(*it); | |
| 247 } | |
| 248 // Download items are forever, and we don't want to make | |
| 249 // assumptions about future state transitions, so once we | |
| 250 // start observing them, we don't stop until destruction. | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 if (count == 0) { | |
| 255 waiting_for_zero_inprogress_ = false; | |
| 256 // Stop observing DownloadItems. We maintain the observation | |
| 257 // of DownloadManager so that we don't have to independently track | |
| 258 // whether we are observing it for conditional destruction. | |
| 259 for (std::set<DownloadItem*>::iterator it = downloads_observed_.begin(); | |
| 260 it != downloads_observed_.end(); ++it) { | |
| 261 (*it)->RemoveObserver(this); | |
| 262 } | |
| 263 downloads_observed_.clear(); | |
| 264 | |
| 265 // Trigger next step. We need to go past the IO thread twice, as | |
| 266 // there's a self-task posting in the IO thread cancel path. | |
| 267 BrowserThread::PostTask( | |
| 268 BrowserThread::FILE, FROM_HERE, | |
| 269 NewRunnableMethod(this, | |
| 270 &DownloadTestFlushObserver::PingFileThread, 2)); | |
| 271 } | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 void DownloadTestFlushObserver::PingFileThread(int cycle) { | |
| 276 BrowserThread::PostTask( | |
| 277 BrowserThread::IO, FROM_HERE, | |
| 278 NewRunnableMethod(this, &DownloadTestFlushObserver::PingIOThread, | |
| 279 cycle)); | |
| 280 } | |
| 281 | |
| 282 void DownloadTestFlushObserver::PingIOThread(int cycle) { | |
| 283 if (--cycle) { | |
| 284 BrowserThread::PostTask( | |
| 285 BrowserThread::UI, FROM_HERE, | |
| 286 NewRunnableMethod(this, &DownloadTestFlushObserver::PingFileThread, | |
| 287 cycle)); | |
| 288 } else { | |
| 289 BrowserThread::PostTask( | |
| 290 BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask()); | |
| 291 } | |
| 292 } | |
| OLD | NEW |