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 |