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