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