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_PUBLIC_TEST_DOWNLOAD_TEST_OBSERVER_H_
6 #define CONTENT_PUBLIC_TEST_DOWNLOAD_TEST_OBSERVER_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <set>
12 #include <vector>
13 
14 #include "base/callback_forward.h"
15 #include "base/macros.h"
16 #include "base/run_loop.h"
17 #include "components/download/public/common/download_interrupt_reasons.h"
18 #include "components/download/public/common/download_item.h"
19 #include "components/download/public/common/download_url_parameters.h"
20 #include "content/public/browser/download_manager.h"
21 
22 namespace content {
23 
24 // Detects an arbitrary change on a download item.
25 // TODO: Rewrite other observers to use this (or be replaced by it).
26 class DownloadUpdatedObserver : public download::DownloadItem::Observer {
27  public:
28   using EventFilter = base::RepeatingCallback<bool(download::DownloadItem*)>;
29 
30   // The filter passed may be called multiple times, even after it
31   // returns true.
32   DownloadUpdatedObserver(download::DownloadItem* item, EventFilter filter);
33   ~DownloadUpdatedObserver() override;
34 
35   // Returns when either the event has been seen (at least once since
36   // object construction) or the item is destroyed.  Return value indicates
37   // if the wait ended because the item was seen (true) or the object
38   // destroyed (false).
39   bool WaitForEvent();
40 
41  private:
42   // download::DownloadItem::Observer
43   void OnDownloadUpdated(download::DownloadItem* item) override;
44   void OnDownloadDestroyed(download::DownloadItem* item) override;
45 
46   download::DownloadItem* item_;
47   EventFilter filter_;
48   bool waiting_;
49   bool event_seen_;
50 
51   DISALLOW_COPY_AND_ASSIGN(DownloadUpdatedObserver);
52 };
53 
54 // Detects changes to the downloads after construction.
55 //
56 // Finishes when one of the following happens:
57 //   - A specified number of downloads change to a terminal state (defined
58 //     in derived classes).
59 //   - The download manager was shutdown.
60 //
61 // Callers may either probe for the finished state, or wait on it.
62 class DownloadTestObserver : public DownloadManager::Observer,
63                              public download::DownloadItem::Observer {
64  public:
65   // Action an observer should take if a dangerous download is encountered.
66   enum DangerousDownloadAction {
67     ON_DANGEROUS_DOWNLOAD_ACCEPT,  // Accept the download
68     ON_DANGEROUS_DOWNLOAD_DENY,    // Deny the download
69     ON_DANGEROUS_DOWNLOAD_FAIL,    // Fail if a dangerous download is seen
70     ON_DANGEROUS_DOWNLOAD_IGNORE,  // Make it the callers problem.
71     ON_DANGEROUS_DOWNLOAD_QUIT     // Will set final state without decision.
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   ~DownloadTestObserver() override;
81 
82   // Wait for one of the finish conditions.
83   void WaitForFinished();
84 
85   // Return true if we reached one of the finish conditions.
86   bool IsFinished() const;
87 
88   // download::DownloadItem::Observer
89   void OnDownloadUpdated(download::DownloadItem* download) override;
90   void OnDownloadDestroyed(download::DownloadItem* download) override;
91 
92   // DownloadManager::Observer
93   void OnDownloadCreated(DownloadManager* manager,
94                          download::DownloadItem* item) override;
95   void ManagerGoingDown(DownloadManager* manager) override;
96 
97   size_t NumDangerousDownloadsSeen() const;
98 
99   size_t NumDownloadsSeenInState(
100       download::DownloadItem::DownloadState state) const;
101 
102  protected:
103   // Only to be called by derived classes' constructors.
104   virtual void Init();
105 
106   // Called to see if a download item is in a final state.
107   virtual bool IsDownloadInFinalState(download::DownloadItem* download) = 0;
108 
109  private:
110   typedef std::set<download::DownloadItem*> DownloadSet;
111 
112   // Maps states to the number of times they have been encountered
113   typedef std::map<download::DownloadItem::DownloadState, size_t> StateMap;
114 
115   // Called when we know that a download item is in a final state.
116   // Note that this is not the same as it first transitioning in to the
117   // final state; multiple notifications may occur once the item is in
118   // that state.  So we keep our own track of transitions into final.
119   void DownloadInFinalState(download::DownloadItem* download);
120 
121   void SignalIfFinished();
122 
123   // Fake user click on "Accept".
124   void AcceptDangerousDownload(uint32_t download_id);
125 
126   // Fake user click on "Deny".
127   void DenyDangerousDownload(uint32_t download_id);
128 
129   // The observed download manager.
130   DownloadManager* download_manager_;
131 
132   // The set of download::DownloadItem's that have transitioned to their
133   // finished state since construction of this object.  When the size of this
134   // array reaches wait_count_, we're done.
135   DownloadSet finished_downloads_;
136 
137   // The set of download::DownloadItem's we are currently observing.  Generally
138   // there won't be any overlap with the above; once we see the final state on a
139   // download::DownloadItem, we'll stop observing it.
140   DownloadSet downloads_observed_;
141 
142   // The map of states to the number of times they have been observed since
143   // we started looking.
144   // Recorded at the time downloads_observed_ is recorded, but cleared in the
145   // constructor to exclude pre-existing states.
146   StateMap states_observed_;
147 
148   // The number of downloads to wait on completing.
149   size_t wait_count_;
150 
151   // The number of downloads entered in final state in Init().  We use
152   // |finished_downloads_| to track the incoming transitions to final state we
153   // should ignore, and to track the number of final state transitions that
154   // occurred between construction and return from wait.  But some downloads may
155   // be in our final state (and thus be entered into |finished_downloads_|) when
156   // we construct this class.  We don't want to count those in our transition to
157   // finished.
158   int finished_downloads_at_construction_;
159 
160   // Whether an internal message loop has been started and must be quit upon
161   // all downloads completing.
162   bool waiting_;
163 
164   // Action to take if a dangerous download is encountered.
165   DangerousDownloadAction dangerous_download_action_;
166 
167   // Holds the download ids which were dangerous.
168   std::set<uint32_t> dangerous_downloads_seen_;
169 
170   base::WeakPtrFactory<DownloadTestObserver> weak_factory_{this};
171 
172   DISALLOW_COPY_AND_ASSIGN(DownloadTestObserver);
173 };
174 
175 class DownloadTestObserverTerminal : public DownloadTestObserver {
176  public:
177   // Create an object that will be considered finished when |wait_count|
178   // download items have entered a terminal state
179   // (download::DownloadItem::IsDone() is true).
180   DownloadTestObserverTerminal(
181       DownloadManager* download_manager,
182       size_t wait_count,
183       DangerousDownloadAction dangerous_download_action);
184 
185   ~DownloadTestObserverTerminal() override;
186 
187  private:
188   bool IsDownloadInFinalState(download::DownloadItem* download) override;
189 
190   DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverTerminal);
191 };
192 
193 // Detects changes to the downloads after construction.
194 // Finishes when a specified number of downloads change to the
195 // IN_PROGRESS state, or when the download manager is destroyed.
196 // Dangerous downloads are accepted.
197 // Callers may either probe for the finished state, or wait on it.
198 class DownloadTestObserverInProgress : public DownloadTestObserver {
199  public:
200   // Create an object that will be considered finished when |wait_count|
201   // download items have entered state |IN_PROGRESS|.
202   DownloadTestObserverInProgress(
203       DownloadManager* download_manager, size_t wait_count);
204 
205   ~DownloadTestObserverInProgress() override;
206 
207  private:
208   bool IsDownloadInFinalState(download::DownloadItem* download) override;
209 
210   DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverInProgress);
211 };
212 
213 class DownloadTestObserverInterrupted : public DownloadTestObserver {
214  public:
215   // Create an object that will be considered finished when |wait_count|
216   // download items are interrupted.
217   DownloadTestObserverInterrupted(
218       DownloadManager* download_manager,
219       size_t wait_count,
220       DangerousDownloadAction dangerous_download_action);
221 
222   ~DownloadTestObserverInterrupted() override;
223 
224  private:
225   bool IsDownloadInFinalState(download::DownloadItem* download) override;
226 
227   DISALLOW_COPY_AND_ASSIGN(DownloadTestObserverInterrupted);
228 };
229 
230 // The WaitForFlush() method on this class returns after:
231 //      * There are no IN_PROGRESS download items remaining on the
232 //        DownloadManager.
233 //      * There have been two round trip messages through the file and
234 //        IO threads.
235 // This almost certainly means that a Download cancel has propagated through
236 // the system.
237 class DownloadTestFlushObserver : public DownloadManager::Observer,
238                                   public download::DownloadItem::Observer {
239  public:
240   explicit DownloadTestFlushObserver(DownloadManager* download_manager);
241   ~DownloadTestFlushObserver() override;
242 
243   void WaitForFlush();
244 
245   // DownloadsManager observer methods.
246   void OnDownloadCreated(DownloadManager* manager,
247                          download::DownloadItem* item) override;
248   void ManagerGoingDown(DownloadManager* manager) override;
249 
250   // download::DownloadItem observer methods.
251   void OnDownloadUpdated(download::DownloadItem* download) override;
252   void OnDownloadDestroyed(download::DownloadItem* download) override;
253 
254  private:
255   typedef std::set<download::DownloadItem*> DownloadSet;
256 
257   // If we're waiting for that flush point, check the number
258   // of downloads in the IN_PROGRESS state and take appropriate
259   // action.  If requested, also observes all downloads while iterating.
260   void CheckDownloadsInProgress(bool observe_downloads);
261 
262   DownloadManager* download_manager_;
263   DownloadSet downloads_observed_;
264   bool waiting_for_zero_inprogress_;
265   base::RunLoop run_loop_;
266 
267   DISALLOW_COPY_AND_ASSIGN(DownloadTestFlushObserver);
268 };
269 
270 // Waits for a callback indicating that the download::DownloadItem is about to
271 // be created, or that an error occurred and it won't be created.
272 class DownloadTestItemCreationObserver
273     : public base::RefCountedThreadSafe<DownloadTestItemCreationObserver> {
274  public:
275   DownloadTestItemCreationObserver();
276 
277   void WaitForDownloadItemCreation();
278 
download_id()279   uint32_t download_id() const { return download_id_; }
interrupt_reason()280   download::DownloadInterruptReason interrupt_reason() const {
281     return interrupt_reason_;
282   }
started()283   bool started() const { return called_back_count_ > 0; }
succeeded()284   bool succeeded() const {
285     return started() &&
286            interrupt_reason_ == download::DOWNLOAD_INTERRUPT_REASON_NONE;
287   }
288 
289   download::DownloadUrlParameters::OnStartedCallback callback();
290 
291  private:
292   friend class base::RefCountedThreadSafe<DownloadTestItemCreationObserver>;
293 
294   ~DownloadTestItemCreationObserver();
295 
296   void DownloadItemCreationCallback(
297       download::DownloadItem* item,
298       download::DownloadInterruptReason interrupt_reason);
299 
300   // The download creation information we received.
301   uint32_t download_id_;
302   download::DownloadInterruptReason interrupt_reason_;
303 
304   // Count of callbacks.
305   size_t called_back_count_;
306 
307   // We are in the message loop.
308   bool waiting_;
309 
310   DISALLOW_COPY_AND_ASSIGN(DownloadTestItemCreationObserver);
311 };
312 
313 // Class for mornitoring whether a save package download finishes.
314 class SavePackageFinishedObserver : public download::DownloadItem::Observer,
315                                     public DownloadManager::Observer {
316  public:
317   SavePackageFinishedObserver(DownloadManager* manager,
318                               base::OnceClosure callback);
319   ~SavePackageFinishedObserver() override;
320 
321   // download::DownloadItem::Observer:
322   void OnDownloadUpdated(download::DownloadItem* download) override;
323   void OnDownloadDestroyed(download::DownloadItem* download) override;
324 
325   // DownloadManager::Observer:
326   void OnDownloadCreated(DownloadManager* manager,
327                          download::DownloadItem* download) override;
328   void ManagerGoingDown(DownloadManager* manager) override;
329 
330  private:
331   DownloadManager* download_manager_;
332   download::DownloadItem* download_;
333   base::OnceClosure callback_;
334 
335   DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
336 };
337 
338 }  // namespace content`
339 
340 #endif  // CONTENT_PUBLIC_TEST_DOWNLOAD_TEST_OBSERVER_H_
341