download_test_observer.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 }; 72 73 // Create an object that will be considered finished when |wait_count| 74 // download items have entered a terminal state. 75 DownloadTestObserver(DownloadManager* download_manager, 76 size_t wait_count, 77 DangerousDownloadAction dangerous_download_action); 78 79 virtual ~DownloadTestObserver(); 80 81 // Wait for the requested number of downloads to enter a terminal state. 82 void WaitForFinished(); 83 84 // Return true if everything's happened that we're configured for. 85 bool IsFinished() const; 86 87 // DownloadItem::Observer 88 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE; 89 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE; 90 91 // DownloadManager::Observer 92 virtual void OnDownloadCreated( 93 DownloadManager* manager, DownloadItem* item) OVERRIDE; 94 95 size_t NumDangerousDownloadsSeen() const; 96 97 size_t NumDownloadsSeenInState(DownloadItem::DownloadState state) const; 98 99 protected: 100 // Only to be called by derived classes' constructors. 101 virtual void Init(); 102 103 // Called to see if a download item is in a final state. 104 virtual bool IsDownloadInFinalState(DownloadItem* download) = 0; 105 106 private: 107 typedef std::set<DownloadItem*> DownloadSet; 108 109 // Maps states to the number of times they have been encountered 110 typedef std::map<DownloadItem::DownloadState, size_t> StateMap; 111 112 // Called when we know that a download item is in a final state. 113 // Note that this is not the same as it first transitioning in to the 114 // final state; multiple notifications may occur once the item is in 115 // that state. So we keep our own track of transitions into final. 116 void DownloadInFinalState(DownloadItem* download); 117 118 void SignalIfFinished(); 119 120 // The observed download manager. 121 scoped_refptr<DownloadManager> download_manager_; 122 123 // The set of DownloadItem's that have transitioned to their finished state 124 // since construction of this object. When the size of this array 125 // reaches wait_count_, we're done. 126 DownloadSet finished_downloads_; 127 128 // The set of DownloadItem's we are currently observing. Generally there 129 // won't be any overlap with the above; once we see the final state 130 // on a DownloadItem, we'll stop observing it. 131 DownloadSet downloads_observed_; 132 133 // The map of states to the number of times they have been observed since 134 // we started looking. 135 // Recorded at the time downloads_observed_ is recorded, but cleared in the 136 // constructor to exclude pre-existing states. 137 StateMap states_observed_; 138 139 // The number of downloads to wait on completing. 140 size_t wait_count_; 141 142 // The number of downloads entered in final state in Init(). We use 143 // |finished_downloads_| to track the incoming transitions to final state we 144 // should ignore, and to track the number of final state transitions that 145 // occurred between construction and return from wait. But some downloads may 146 // be in our final state (and thus be entered into |finished_downloads_|) when 147 // we construct this class. We don't want to count those in our transition to 148 // finished. 149 int finished_downloads_at_construction_; 150 151 // Whether an internal message loop has been started and must be quit upon 152 // all downloads completing. 153 bool waiting_; 154 155 // Action to take if a dangerous download is encountered. 156 DangerousDownloadAction dangerous_download_action_; 157 158 // Holds the download ids which were dangerous. 159 std::set<int32> dangerous_downloads_seen_; 160 161 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserver); 162}; 163 164class DownloadTestObserverTerminal : public DownloadTestObserver { 165 public: 166 // Create an object that will be considered finished when |wait_count| 167 // download items have entered a terminal state (any but IN_PROGRESS). 168 // If |finish_on_select_file| is true, the object will also be 169 // considered finished if the DownloadManager raises a 170 // SelectFileDialogDisplayed() notification. 171 DownloadTestObserverTerminal( 172 DownloadManager* download_manager, 173 size_t wait_count, 174 DangerousDownloadAction dangerous_download_action); 175 176 virtual ~DownloadTestObserverTerminal(); 177 178 private: 179 virtual bool IsDownloadInFinalState(DownloadItem* download) OVERRIDE; 180 181 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverTerminal); 182}; 183 184// Detects changes to the downloads after construction. 185// Finishes when a specified number of downloads change to the 186// IN_PROGRESS state, or a Select File Dialog has appeared. 187// Dangerous downloads are accepted. 188// Callers may either probe for the finished state, or wait on it. 189class DownloadTestObserverInProgress : public DownloadTestObserver { 190 public: 191 // Create an object that will be considered finished when |wait_count| 192 // download items have entered state |IN_PROGRESS|. 193 // If |finish_on_select_file| is true, the object will also be 194 // considered finished if the DownloadManager raises a 195 // SelectFileDialogDisplayed() notification. 196 DownloadTestObserverInProgress( 197 DownloadManager* download_manager, size_t wait_count); 198 199 virtual ~DownloadTestObserverInProgress(); 200 201 private: 202 virtual bool IsDownloadInFinalState(DownloadItem* download) OVERRIDE; 203 204 DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverInProgress); 205}; 206 207// The WaitForFlush() method on this class returns after: 208// * There are no IN_PROGRESS download items remaining on the 209// DownloadManager. 210// * There have been two round trip messages through the file and 211// IO threads. 212// This almost certainly means that a Download cancel has propagated through 213// the system. 214class DownloadTestFlushObserver 215 : public DownloadManager::Observer, 216 public DownloadItem::Observer, 217 public base::RefCountedThreadSafe<DownloadTestFlushObserver> { 218 public: 219 explicit DownloadTestFlushObserver(DownloadManager* download_manager); 220 221 void WaitForFlush(); 222 223 // DownloadsManager observer methods. 224 virtual void OnDownloadCreated( 225 DownloadManager* manager, 226 DownloadItem* item) OVERRIDE; 227 228 // DownloadItem observer methods. 229 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE; 230 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE; 231 232 protected: 233 friend class base::RefCountedThreadSafe<DownloadTestFlushObserver>; 234 235 virtual ~DownloadTestFlushObserver(); 236 237 private: 238 typedef std::set<DownloadItem*> DownloadSet; 239 240 // If we're waiting for that flush point, check the number 241 // of downloads in the IN_PROGRESS state and take appropriate 242 // action. If requested, also observes all downloads while iterating. 243 void CheckDownloadsInProgress(bool observe_downloads); 244 245 void PingFileThread(int cycle); 246 247 void PingIOThread(int cycle); 248 249 DownloadManager* download_manager_; 250 DownloadSet downloads_observed_; 251 bool waiting_for_zero_inprogress_; 252 253 DISALLOW_COPY_AND_ASSIGN(DownloadTestFlushObserver); 254}; 255 256// Waits for a callback indicating that the DownloadItem is about to be created, 257// or that an error occurred and it won't be created. 258class DownloadTestItemCreationObserver 259 : public base::RefCountedThreadSafe<DownloadTestItemCreationObserver> { 260 public: 261 DownloadTestItemCreationObserver(); 262 263 void WaitForDownloadItemCreation(); 264 265 int download_id() const { return download_id_; } 266 net::Error error() const { return error_; } 267 bool started() const { return called_back_count_ > 0; } 268 bool succeeded() const { return started() && (error_ == net::OK); } 269 270 const DownloadUrlParameters::OnStartedCallback callback(); 271 272 private: 273 friend class base::RefCountedThreadSafe<DownloadTestItemCreationObserver>; 274 275 ~DownloadTestItemCreationObserver(); 276 277 void DownloadItemCreationCallback(DownloadItem* item, net::Error error); 278 279 // The download creation information we received. 280 int download_id_; 281 net::Error error_; 282 283 // Count of callbacks. 284 size_t called_back_count_; 285 286 // We are in the message loop. 287 bool waiting_; 288 289 DISALLOW_COPY_AND_ASSIGN(DownloadTestItemCreationObserver); 290}; 291 292} // namespace content` 293 294#endif // CONTENT_TEST_DOWNLOAD_TEST_OBSERVER_H_ 295