download_test_observer.h revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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#ifndef CONTENT_TEST_DOWNLOAD_TEST_OBSERVER_H_ 6#define CONTENT_TEST_DOWNLOAD_TEST_OBSERVER_H_ 7 8#include <set> 9#include <vector> 10 11#include "base/basictypes.h" 12#include "base/callback_forward.h" 13#include "base/memory/ref_counted.h" 14#include "content/public/browser/download_item.h" 15#include "content/public/browser/download_manager.h" 16#include "content/public/browser/download_url_parameters.h" 17#include "net/base/net_errors.h" 18 19namespace content { 20 21// Detects an arbitrary change on a download item. 22// TODO: Rewrite other observers to use this (or be replaced by it). 23class DownloadUpdatedObserver : public DownloadItem::Observer { 24 public: 25 typedef base::Callback<bool(DownloadItem*)> EventFilter; 26 27 // The filter passed may be called multiple times, even after it 28 // returns true. 29 DownloadUpdatedObserver(DownloadItem* item, EventFilter filter); 30 virtual ~DownloadUpdatedObserver(); 31 32 // Returns when either the event has been seen (at least once since 33 // object construction) or the item is destroyed. Return value indicates 34 // if the wait ended because the item was seen (true) or the object 35 // destroyed (false). 36 bool WaitForEvent(); 37 38 private: 39 // DownloadItem::Observer 40 virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE; 41 virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE; 42 43 DownloadItem* item_; 44 EventFilter filter_; 45 bool waiting_; 46 bool event_seen_; 47 48 DISALLOW_COPY_AND_ASSIGN(DownloadUpdatedObserver); 49}; 50 51// Detects changes to the downloads after construction. 52// Finishes when one of the following happens: 53// - A specified number of downloads change to a terminal state (defined 54// in derived classes). 55// - Specific events, such as a select file dialog. 56// Callers may either probe for the finished state, or wait on it. 57// 58// TODO(rdsmith): Detect manager going down, remove pointer to 59// DownloadManager, transition to finished. (For right now we 60// just use a scoped_refptr<> to keep it around, but that may cause 61// timeouts on waiting if a DownloadManager::Shutdown() occurs which 62// cancels our in-progress downloads.) 63class DownloadTestObserver : public DownloadManager::Observer, 64 public DownloadItem::Observer { 65 public: 66 // Action an observer should take if a dangerous download is encountered. 67 enum DangerousDownloadAction { 68 ON_DANGEROUS_DOWNLOAD_ACCEPT, // Accept the download 69 ON_DANGEROUS_DOWNLOAD_DENY, // Deny the download 70 ON_DANGEROUS_DOWNLOAD_FAIL, // Fail if a dangerous download is seen 71 ON_DANGEROUS_DOWNLOAD_IGNORE // Make it the callers problem. 72 }; 73 74 // Create an object that will be considered finished when |wait_count| 75 // download items have entered a terminal state. 76 DownloadTestObserver(DownloadManager* download_manager, 77 size_t wait_count, 78 DangerousDownloadAction dangerous_download_action); 79 80 virtual ~DownloadTestObserver(); 81 82 // Wait for the requested number of downloads to enter a terminal state. 83 void WaitForFinished(); 84 85 // Return true if everything's happened that we're configured for. 86 bool IsFinished() const; 87 88 // DownloadItem::Observer 89 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE; 90 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE; 91 92 // DownloadManager::Observer 93 virtual void OnDownloadCreated( 94 DownloadManager* manager, DownloadItem* item) OVERRIDE; 95 96 size_t NumDangerousDownloadsSeen() const; 97 98 size_t NumDownloadsSeenInState(DownloadItem::DownloadState state) const; 99 100 protected: 101 // Only to be called by derived classes' constructors. 102 virtual void Init(); 103 104 // Called to see if a download item is in a final state. 105 virtual bool IsDownloadInFinalState(DownloadItem* download) = 0; 106 107 private: 108 typedef std::set<DownloadItem*> DownloadSet; 109 110 // Maps states to the number of times they have been encountered 111 typedef std::map<DownloadItem::DownloadState, size_t> StateMap; 112 113 // Called when we know that a download item is in a final state. 114 // Note that this is not the same as it first transitioning in to the 115 // final state; multiple notifications may occur once the item is in 116 // that state. So we keep our own track of transitions into final. 117 void DownloadInFinalState(DownloadItem* download); 118 119 void SignalIfFinished(); 120 121 // The observed download manager. 122 scoped_refptr<DownloadManager> download_manager_; 123 124 // The set of DownloadItem's that have transitioned to their finished state 125 // since construction of this object. When the size of this array 126 // reaches wait_count_, we're done. 127 DownloadSet finished_downloads_; 128 129 // The set of DownloadItem's we are currently observing. Generally there 130 // won't be any overlap with the above; once we see the final state 131 // on a DownloadItem, we'll stop observing it. 132 DownloadSet downloads_observed_; 133 134 // The map of states to the number of times they have been observed since 135 // we started looking. 136 // Recorded at the time downloads_observed_ is recorded, but cleared in the 137 // constructor to exclude pre-existing states. 138 StateMap states_observed_; 139 140 // The number of downloads to wait on completing. 141 size_t wait_count_; 142 143 // The number of downloads entered in final state in Init(). We use 144 // |finished_downloads_| to track the incoming transitions to final state we 145 // should ignore, and to track the number of final state transitions that 146 // occurred between construction and return from wait. But some downloads may 147 // be in our final state (and thus be entered into |finished_downloads_|) when 148 // we construct this class. We don't want to count those in our transition to 149 // finished. 150 int finished_downloads_at_construction_; 151 152 // Whether an internal message loop has been started and must be quit upon 153 // all downloads completing. 154 bool waiting_; 155 156 // Action to take if a dangerous download is encountered. 157 DangerousDownloadAction dangerous_download_action_; 158 159 // Holds the download ids which were dangerous. 160 std::set<int32> dangerous_downloads_seen_; 161 162 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserver); 163}; 164 165class DownloadTestObserverTerminal : public DownloadTestObserver { 166 public: 167 // Create an object that will be considered finished when |wait_count| 168 // download items have entered a terminal state (any but IN_PROGRESS). 169 // If |finish_on_select_file| is true, the object will also be 170 // considered finished if the DownloadManager raises a 171 // SelectFileDialogDisplayed() notification. 172 DownloadTestObserverTerminal( 173 DownloadManager* download_manager, 174 size_t wait_count, 175 DangerousDownloadAction dangerous_download_action); 176 177 virtual ~DownloadTestObserverTerminal(); 178 179 private: 180 virtual bool IsDownloadInFinalState(DownloadItem* download) OVERRIDE; 181 182 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverTerminal); 183}; 184 185// Detects changes to the downloads after construction. 186// Finishes when a specified number of downloads change to the 187// IN_PROGRESS state, or a Select File Dialog has appeared. 188// Dangerous downloads are accepted. 189// Callers may either probe for the finished state, or wait on it. 190class DownloadTestObserverInProgress : public DownloadTestObserver { 191 public: 192 // Create an object that will be considered finished when |wait_count| 193 // download items have entered state |IN_PROGRESS|. 194 // If |finish_on_select_file| is true, the object will also be 195 // considered finished if the DownloadManager raises a 196 // SelectFileDialogDisplayed() notification. 197 DownloadTestObserverInProgress( 198 DownloadManager* download_manager, size_t wait_count); 199 200 virtual ~DownloadTestObserverInProgress(); 201 202 private: 203 virtual bool IsDownloadInFinalState(DownloadItem* download) OVERRIDE; 204 205 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverInProgress); 206}; 207 208// The WaitForFlush() method on this class returns after: 209// * There are no IN_PROGRESS download items remaining on the 210// DownloadManager. 211// * There have been two round trip messages through the file and 212// IO threads. 213// This almost certainly means that a Download cancel has propagated through 214// the system. 215class DownloadTestFlushObserver 216 : public DownloadManager::Observer, 217 public DownloadItem::Observer, 218 public base::RefCountedThreadSafe<DownloadTestFlushObserver> { 219 public: 220 explicit DownloadTestFlushObserver(DownloadManager* download_manager); 221 222 void WaitForFlush(); 223 224 // DownloadsManager observer methods. 225 virtual void OnDownloadCreated( 226 DownloadManager* manager, 227 DownloadItem* item) OVERRIDE; 228 229 // DownloadItem observer methods. 230 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE; 231 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE; 232 233 protected: 234 friend class base::RefCountedThreadSafe<DownloadTestFlushObserver>; 235 236 virtual ~DownloadTestFlushObserver(); 237 238 private: 239 typedef std::set<DownloadItem*> DownloadSet; 240 241 // If we're waiting for that flush point, check the number 242 // of downloads in the IN_PROGRESS state and take appropriate 243 // action. If requested, also observes all downloads while iterating. 244 void CheckDownloadsInProgress(bool observe_downloads); 245 246 void PingFileThread(int cycle); 247 248 void PingIOThread(int cycle); 249 250 DownloadManager* download_manager_; 251 DownloadSet downloads_observed_; 252 bool waiting_for_zero_inprogress_; 253 254 DISALLOW_COPY_AND_ASSIGN(DownloadTestFlushObserver); 255}; 256 257// Waits for a callback indicating that the DownloadItem is about to be created, 258// or that an error occurred and it won't be created. 259class DownloadTestItemCreationObserver 260 : public base::RefCountedThreadSafe<DownloadTestItemCreationObserver> { 261 public: 262 DownloadTestItemCreationObserver(); 263 264 void WaitForDownloadItemCreation(); 265 266 int download_id() const { return download_id_; } 267 net::Error error() const { return error_; } 268 bool started() const { return called_back_count_ > 0; } 269 bool succeeded() const { return started() && (error_ == net::OK); } 270 271 const DownloadUrlParameters::OnStartedCallback callback(); 272 273 private: 274 friend class base::RefCountedThreadSafe<DownloadTestItemCreationObserver>; 275 276 ~DownloadTestItemCreationObserver(); 277 278 void DownloadItemCreationCallback(DownloadItem* item, net::Error error); 279 280 // The download creation information we received. 281 int download_id_; 282 net::Error error_; 283 284 // Count of callbacks. 285 size_t called_back_count_; 286 287 // We are in the message loop. 288 bool waiting_; 289 290 DISALLOW_COPY_AND_ASSIGN(DownloadTestItemCreationObserver); 291}; 292 293} // namespace content` 294 295#endif // CONTENT_TEST_DOWNLOAD_TEST_OBSERVER_H_ 296