download_test_observer.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Copyright (c) 2012 The Chromium Authors. All rights reserved.
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Use of this source code is governed by a BSD-style license that can be
361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// found in the LICENSE file.
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#include "content/public/test/download_test_observer.h"
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <vector>
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/bind.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/logging.h"
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/message_loop.h"
1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "base/stl_util.h"
1361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "base/threading/sequenced_worker_pool.h"
1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "content/public/browser/browser_thread.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/public/browser/download_url_parameters.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "content/public/test/test_utils.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "testing/gtest/include/gtest/gtest.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace content {
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace {
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// These functions take scoped_refptr's to DownloadManager because they
2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// are posted to message queues, and hence may execute arbitrarily after
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// their actual posting.  Once posted, there is no connection between
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// these routines and the DownloadTestObserver class from which
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// they came, so the DownloadTestObserver's reference to the
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// DownloadManager cannot be counted on to keep the DownloadManager around.
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Fake user click on "Accept".
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid AcceptDangerousDownload(scoped_refptr<DownloadManager> download_manager,
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                             int32 download_id) {
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  DownloadItem* download = download_manager->GetDownload(download_id);
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (download && (download->GetState() == DownloadItem::IN_PROGRESS))
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    download->DangerousDownloadValidated();
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Fake user click on "Deny".
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DenyDangerousDownload(scoped_refptr<DownloadManager> download_manager,
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                           int32 download_id) {
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  DownloadItem* download = download_manager->GetDownload(download_id);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (download && (download->GetState() == DownloadItem::IN_PROGRESS)) {
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    download->Cancel(true);
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    download->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}  // namespace
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtDownloadUpdatedObserver::DownloadUpdatedObserver(
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    DownloadItem* item, DownloadUpdatedObserver::EventFilter filter)
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    : item_(item),
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      filter_(filter),
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      waiting_(false),
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      event_seen_(false) {
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  item->AddObserver(this);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtDownloadUpdatedObserver::~DownloadUpdatedObserver() {
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (item_)
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    item_->RemoveObserver(this);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbool DownloadUpdatedObserver::WaitForEvent() {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (item_ && filter_.Run(item_))
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    event_seen_ = true;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (event_seen_)
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return true;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  waiting_ = true;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  RunMessageLoop();
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  waiting_ = false;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return event_seen_;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadUpdatedObserver::OnDownloadUpdated(DownloadItem* item) {
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  DCHECK_EQ(item_, item);
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt  if (filter_.Run(item_))
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    event_seen_ = true;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (waiting_ && event_seen_)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    MessageLoopForUI::current()->Quit();
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadUpdatedObserver::OnDownloadDestroyed(DownloadItem* item) {
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  DCHECK_EQ(item_, item);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  item_->RemoveObserver(this);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  item_ = NULL;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (waiting_)
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    MessageLoopForUI::current()->Quit();
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtDownloadTestObserver::DownloadTestObserver(
9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    DownloadManager* download_manager,
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    size_t wait_count,
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    DangerousDownloadAction dangerous_download_action)
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    : download_manager_(download_manager),
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      wait_count_(wait_count),
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      finished_downloads_at_construction_(0),
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      waiting_(false),
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      dangerous_download_action_(dangerous_download_action) {
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtDownloadTestObserver::~DownloadTestObserver() {
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (DownloadSet::iterator it = downloads_observed_.begin();
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       it != downloads_observed_.end(); ++it)
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    (*it)->RemoveObserver(this);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  download_manager_->RemoveObserver(this);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadTestObserver::Init() {
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  download_manager_->AddObserver(this);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  std::vector<DownloadItem*> downloads;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  download_manager_->GetAllDownloads(&downloads);
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  for (std::vector<DownloadItem*>::iterator it = downloads.begin();
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt       it != downloads.end(); ++it) {
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    OnDownloadCreated(download_manager_, *it);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  finished_downloads_at_construction_ = finished_downloads_.size();
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  states_observed_.clear();
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadTestObserver::WaitForFinished() {
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (!IsFinished()) {
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    waiting_ = true;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    RunMessageLoop();
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    waiting_ = false;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbool DownloadTestObserver::IsFinished() const {
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  return (finished_downloads_.size() - finished_downloads_at_construction_ >=
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt          wait_count_);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadTestObserver::OnDownloadCreated(
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    DownloadManager* manager,
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    DownloadItem* item) {
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  // NOTE: This method is called both by DownloadManager when a download is
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  // created as well as in DownloadTestObserver::Init() for downloads that
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  // existed before |this| was created.
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  OnDownloadUpdated(item);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  DownloadSet::const_iterator finished_it(finished_downloads_.find(item));
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  // If it isn't finished, start observing it.
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (finished_it == finished_downloads_.end()) {
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    item->AddObserver(this);
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    downloads_observed_.insert(item);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  }
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadTestObserver::OnDownloadDestroyed(DownloadItem* download) {
15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt  // Stop observing.  Do not do anything with it, as it is about to be gone.
15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt  DownloadSet::iterator it = downloads_observed_.find(download);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  ASSERT_TRUE(it != downloads_observed_.end());
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  downloads_observed_.erase(it);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  download->RemoveObserver(this);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid DownloadTestObserver::OnDownloadUpdated(DownloadItem* download) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  // Real UI code gets the user's response after returning from the observer.
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt  if (download->IsDangerous() &&
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt      !ContainsKey(dangerous_downloads_seen_, download->GetId())) {
163    dangerous_downloads_seen_.insert(download->GetId());
164
165    // Calling DangerousDownloadValidated() at this point will
166    // cause the download to be completed twice.  Do what the real UI
167    // code does: make the call as a delayed task.
168    switch (dangerous_download_action_) {
169      case ON_DANGEROUS_DOWNLOAD_ACCEPT:
170        // Fake user click on "Accept".  Delay the actual click, as the
171        // real UI would.
172        BrowserThread::PostTask(
173            BrowserThread::UI, FROM_HERE,
174            base::Bind(&AcceptDangerousDownload, download_manager_,
175                       download->GetId()));
176        break;
177
178      case ON_DANGEROUS_DOWNLOAD_DENY:
179        // Fake a user click on "Deny".  Delay the actual click, as the
180        // real UI would.
181        BrowserThread::PostTask(
182            BrowserThread::UI, FROM_HERE,
183            base::Bind(&DenyDangerousDownload, download_manager_,
184                       download->GetId()));
185        break;
186
187      case ON_DANGEROUS_DOWNLOAD_FAIL:
188        ADD_FAILURE() << "Unexpected dangerous download item.";
189        break;
190
191      case ON_DANGEROUS_DOWNLOAD_IGNORE:
192        break;
193
194      default:
195        NOTREACHED();
196    }
197  }
198
199  if (IsDownloadInFinalState(download))
200    DownloadInFinalState(download);
201}
202
203size_t DownloadTestObserver::NumDangerousDownloadsSeen() const {
204  return dangerous_downloads_seen_.size();
205}
206
207size_t DownloadTestObserver::NumDownloadsSeenInState(
208    DownloadItem::DownloadState state) const {
209  StateMap::const_iterator it = states_observed_.find(state);
210
211  if (it == states_observed_.end())
212    return 0;
213
214  return it->second;
215}
216
217void DownloadTestObserver::DownloadInFinalState(DownloadItem* download) {
218  if (finished_downloads_.find(download) != finished_downloads_.end()) {
219    // We've already seen the final state on this download.
220    return;
221  }
222
223  // Record the transition.
224  finished_downloads_.insert(download);
225
226  // Record the state.
227  states_observed_[download->GetState()]++;  // Initializes to 0 the first time.
228
229  SignalIfFinished();
230}
231
232void DownloadTestObserver::SignalIfFinished() {
233  if (waiting_ && IsFinished())
234    MessageLoopForUI::current()->Quit();
235}
236
237DownloadTestObserverTerminal::DownloadTestObserverTerminal(
238    DownloadManager* download_manager,
239    size_t wait_count,
240    DangerousDownloadAction dangerous_download_action)
241        : DownloadTestObserver(download_manager,
242                               wait_count,
243                               dangerous_download_action) {
244  // You can't rely on overriden virtual functions in a base class constructor;
245  // the virtual function table hasn't been set up yet.  So, we have to do any
246  // work that depends on those functions in the derived class constructor
247  // instead.  In this case, it's because of |IsDownloadInFinalState()|.
248  Init();
249}
250
251DownloadTestObserverTerminal::~DownloadTestObserverTerminal() {
252}
253
254
255bool DownloadTestObserverTerminal::IsDownloadInFinalState(
256    DownloadItem* download) {
257  return (download->GetState() != DownloadItem::IN_PROGRESS);
258}
259
260DownloadTestObserverInProgress::DownloadTestObserverInProgress(
261    DownloadManager* download_manager,
262    size_t wait_count)
263        : DownloadTestObserver(download_manager,
264                               wait_count,
265                               ON_DANGEROUS_DOWNLOAD_ACCEPT) {
266  // You can't override virtual functions in a base class constructor; the
267  // virtual function table hasn't been set up yet.  So, we have to do any
268  // work that depends on those functions in the derived class constructor
269  // instead.  In this case, it's because of |IsDownloadInFinalState()|.
270  Init();
271}
272
273DownloadTestObserverInProgress::~DownloadTestObserverInProgress() {
274}
275
276
277bool DownloadTestObserverInProgress::IsDownloadInFinalState(
278    DownloadItem* download) {
279  return (download->GetState() == DownloadItem::IN_PROGRESS) &&
280      !download->GetTargetFilePath().empty();
281}
282
283DownloadTestFlushObserver::DownloadTestFlushObserver(
284    DownloadManager* download_manager)
285    : download_manager_(download_manager),
286      waiting_for_zero_inprogress_(true) {}
287
288void DownloadTestFlushObserver::WaitForFlush() {
289  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290  download_manager_->AddObserver(this);
291  // The wait condition may have been met before WaitForFlush() was called.
292  CheckDownloadsInProgress(true);
293  BrowserThread::GetBlockingPool()->FlushForTesting();
294  RunMessageLoop();
295}
296
297void DownloadTestFlushObserver::OnDownloadCreated(
298    DownloadManager* manager,
299    DownloadItem* item) {
300  CheckDownloadsInProgress(true);
301}
302
303void DownloadTestFlushObserver::OnDownloadDestroyed(DownloadItem* download) {
304  // Stop observing.  Do not do anything with it, as it is about to be gone.
305  DownloadSet::iterator it = downloads_observed_.find(download);
306  ASSERT_TRUE(it != downloads_observed_.end());
307  downloads_observed_.erase(it);
308  download->RemoveObserver(this);
309}
310
311void DownloadTestFlushObserver::OnDownloadUpdated(DownloadItem* download) {
312  // No change in DownloadItem set on manager.
313  CheckDownloadsInProgress(false);
314}
315
316DownloadTestFlushObserver::~DownloadTestFlushObserver() {
317  download_manager_->RemoveObserver(this);
318  for (DownloadSet::iterator it = downloads_observed_.begin();
319       it != downloads_observed_.end(); ++it) {
320    (*it)->RemoveObserver(this);
321  }
322}
323
324// If we're waiting for that flush point, check the number
325// of downloads in the IN_PROGRESS state and take appropriate
326// action.  If requested, also observes all downloads while iterating.
327void DownloadTestFlushObserver::CheckDownloadsInProgress(
328    bool observe_downloads) {
329  if (waiting_for_zero_inprogress_) {
330    int count = 0;
331
332    std::vector<DownloadItem*> downloads;
333    download_manager_->GetAllDownloads(&downloads);
334    for (std::vector<DownloadItem*>::iterator it = downloads.begin();
335         it != downloads.end(); ++it) {
336      if ((*it)->GetState() == DownloadItem::IN_PROGRESS)
337        count++;
338      if (observe_downloads) {
339        if (downloads_observed_.find(*it) == downloads_observed_.end()) {
340          (*it)->AddObserver(this);
341          downloads_observed_.insert(*it);
342        }
343        // Download items are forever, and we don't want to make
344        // assumptions about future state transitions, so once we
345        // start observing them, we don't stop until destruction.
346      }
347    }
348
349    if (count == 0) {
350      waiting_for_zero_inprogress_ = false;
351      // Stop observing DownloadItems.  We maintain the observation
352      // of DownloadManager so that we don't have to independently track
353      // whether we are observing it for conditional destruction.
354      for (DownloadSet::iterator it = downloads_observed_.begin();
355           it != downloads_observed_.end(); ++it) {
356        (*it)->RemoveObserver(this);
357      }
358      downloads_observed_.clear();
359
360      // Trigger next step.  We need to go past the IO thread twice, as
361      // there's a self-task posting in the IO thread cancel path.
362      BrowserThread::PostTask(
363          BrowserThread::FILE, FROM_HERE,
364          base::Bind(&DownloadTestFlushObserver::PingFileThread, this, 2));
365    }
366  }
367}
368
369void DownloadTestFlushObserver::PingFileThread(int cycle) {
370  BrowserThread::PostTask(
371      BrowserThread::IO, FROM_HERE,
372      base::Bind(&DownloadTestFlushObserver::PingIOThread, this, cycle));
373}
374
375void DownloadTestFlushObserver::PingIOThread(int cycle) {
376  if (--cycle) {
377    BrowserThread::PostTask(
378        BrowserThread::UI, FROM_HERE,
379        base::Bind(&DownloadTestFlushObserver::PingFileThread, this, cycle));
380  } else {
381    BrowserThread::PostTask(
382        BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure());
383  }
384}
385
386DownloadTestItemCreationObserver::DownloadTestItemCreationObserver()
387    : download_id_(DownloadId::Invalid().local()),
388      error_(net::OK),
389      called_back_count_(0),
390      waiting_(false) {
391}
392
393DownloadTestItemCreationObserver::~DownloadTestItemCreationObserver() {
394}
395
396void DownloadTestItemCreationObserver::WaitForDownloadItemCreation() {
397  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
398
399  if (called_back_count_ == 0) {
400    waiting_ = true;
401    RunMessageLoop();
402    waiting_ = false;
403  }
404}
405
406void DownloadTestItemCreationObserver::DownloadItemCreationCallback(
407    DownloadItem* item,
408    net::Error error) {
409  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410
411  if (item)
412    download_id_ = item->GetId();
413  error_ = error;
414  ++called_back_count_;
415  DCHECK_EQ(1u, called_back_count_);
416
417  if (waiting_)
418    MessageLoopForUI::current()->Quit();
419}
420
421const DownloadUrlParameters::OnStartedCallback
422    DownloadTestItemCreationObserver::callback() {
423  return base::Bind(
424      &DownloadTestItemCreationObserver::DownloadItemCreationCallback, this);
425}
426
427}  // namespace content
428