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_interrupt_reasons.h"
15#include "content/public/browser/download_item.h"
16#include "content/public/browser/download_manager.h"
17#include "content/public/browser/download_url_parameters.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//
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.
59class 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
171class 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.
194class 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
209class 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.
233class 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.
277class DownloadTestItemCreationObserver
278    : public base::RefCountedThreadSafe<DownloadTestItemCreationObserver> {
279 public:
280  DownloadTestItemCreationObserver();
281
282  void WaitForDownloadItemCreation();
283
284  uint32 download_id() const { return download_id_; }
285  DownloadInterruptReason interrupt_reason() const { return interrupt_reason_; }
286  bool started() const { return called_back_count_ > 0; }
287  bool succeeded() const {
288    return started() && interrupt_reason_ == DOWNLOAD_INTERRUPT_REASON_NONE;
289  }
290
291  const DownloadUrlParameters::OnStartedCallback callback();
292
293 private:
294  friend class base::RefCountedThreadSafe<DownloadTestItemCreationObserver>;
295
296  ~DownloadTestItemCreationObserver();
297
298  void DownloadItemCreationCallback(DownloadItem* item,
299                                    DownloadInterruptReason interrupt_reason);
300
301  // The download creation information we received.
302  uint32 download_id_;
303  DownloadInterruptReason interrupt_reason_;
304
305  // Count of callbacks.
306  size_t called_back_count_;
307
308  // We are in the message loop.
309  bool waiting_;
310
311  DISALLOW_COPY_AND_ASSIGN(DownloadTestItemCreationObserver);
312};
313
314}  // namespace content`
315
316#endif  // CONTENT_TEST_DOWNLOAD_TEST_OBSERVER_H_
317