Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: chrome/browser/download/download_test_observer.cc

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

Powered by Google App Engine
This is Rietveld 408576698