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 #include "content/browser/download/download_manager_impl.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <tuple>
15 #include <utility>
16 
17 #include "base/bind.h"
18 #include "base/bind_helpers.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/guid.h"
21 #include "base/macros.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/optional.h"
24 #include "base/run_loop.h"
25 #include "base/stl_util.h"
26 #include "base/strings/string16.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/test/gmock_callback_support.h"
30 #include "base/test/scoped_feature_list.h"
31 #include "build/build_config.h"
32 #include "components/download/public/common/download_create_info.h"
33 #include "components/download/public/common/download_features.h"
34 #include "components/download/public/common/download_file_factory.h"
35 #include "components/download/public/common/download_interrupt_reasons.h"
36 #include "components/download/public/common/download_item.h"
37 #include "components/download/public/common/download_item_factory.h"
38 #include "components/download/public/common/download_item_impl.h"
39 #include "components/download/public/common/download_item_impl_delegate.h"
40 #include "components/download/public/common/mock_download_file.h"
41 #include "components/download/public/common/mock_download_item_impl.h"
42 #include "components/download/public/common/mock_input_stream.h"
43 #include "content/public/browser/browser_context.h"
44 #include "content/public/browser/download_manager_delegate.h"
45 #include "content/public/browser/storage_partition.h"
46 #include "content/public/test/browser_task_environment.h"
47 #include "content/public/test/test_browser_context.h"
48 #include "testing/gmock/include/gmock/gmock.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "url/origin.h"
51 
52 using base::test::RunOnceCallback;
53 using ::testing::_;
54 using ::testing::AllOf;
55 using ::testing::DoAll;
56 using ::testing::Eq;
57 using ::testing::Ref;
58 using ::testing::Return;
59 using ::testing::ReturnRef;
60 using ::testing::ReturnRefOfCopy;
61 using ::testing::SetArgPointee;
62 using ::testing::StrictMock;
63 
64 namespace content {
65 
66 namespace {
67 
68 const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
69 
URLAlwaysSafe(int render_process_id,const GURL & url)70 bool URLAlwaysSafe(int render_process_id, const GURL& url) {
71   return true;
72 }
73 
74 class MockDownloadManagerDelegate : public DownloadManagerDelegate {
75  public:
76   MockDownloadManagerDelegate();
77   ~MockDownloadManagerDelegate() override;
78 
79   MOCK_METHOD0(Shutdown, void());
GetNextId(DownloadIdCallback cb)80   void GetNextId(DownloadIdCallback cb) override { GetNextId_(cb); }
81   MOCK_METHOD1(GetNextId_, void(DownloadIdCallback&));
82   MOCK_METHOD2(DetermineDownloadTarget,
83                bool(download::DownloadItem*, DownloadTargetCallback*));
84   MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const base::FilePath&));
ShouldCompleteDownload(download::DownloadItem * item,base::OnceClosure cb)85   bool ShouldCompleteDownload(download::DownloadItem* item,
86                               base::OnceClosure cb) override {
87     return ShouldCompleteDownload_(item, cb);
88   }
89   MOCK_METHOD2(ShouldCompleteDownload_,
90                bool(download::DownloadItem*, base::OnceClosure&));
ShouldOpenDownload(download::DownloadItem * item,DownloadOpenDelayedCallback cb)91   bool ShouldOpenDownload(download::DownloadItem* item,
92                           DownloadOpenDelayedCallback cb) override {
93     return ShouldOpenDownload_(item, cb);
94   }
95   MOCK_METHOD2(ShouldOpenDownload_,
96                bool(download::DownloadItem*, DownloadOpenDelayedCallback&));
97   MOCK_METHOD3(GetSaveDir,
98                void(BrowserContext*, base::FilePath*, base::FilePath*));
99   MOCK_METHOD5(ChooseSavePath,
100                void(WebContents*,
101                     const base::FilePath&,
102                     const base::FilePath::StringType&,
103                     bool,
104                     SavePackagePathPickedCallback));
105   MOCK_METHOD0(ApplicationClientIdForFileScanning, std::string());
106 };
107 
MockDownloadManagerDelegate()108 MockDownloadManagerDelegate::MockDownloadManagerDelegate() {}
109 
~MockDownloadManagerDelegate()110 MockDownloadManagerDelegate::~MockDownloadManagerDelegate() {}
111 
112 class MockDownloadItemFactory
113     : public download::DownloadItemFactory,
114       public base::SupportsWeakPtr<MockDownloadItemFactory> {
115  public:
116   MockDownloadItemFactory();
117   ~MockDownloadItemFactory() override;
118 
119   // Access to map of created items.
120   // TODO(rdsmith): Could add type (save page, persisted, etc.)
121   // functionality if it's ever needed by consumers.
122 
123   // Returns NULL if no item of that id is present.
124   download::MockDownloadItemImpl* GetItem(int id);
125 
126   // Remove and return an item made by the factory.
127   // Generally used during teardown.
128   download::MockDownloadItemImpl* PopItem();
129 
130   // Should be called when the item of this id is removed so that
131   // we don't keep dangling pointers.
132   void RemoveItem(int id);
133 
134   // Overridden methods from DownloadItemFactory.
135   download::DownloadItemImpl* CreatePersistedItem(
136       download::DownloadItemImplDelegate* delegate,
137       const std::string& guid,
138       uint32_t download_id,
139       const base::FilePath& current_path,
140       const base::FilePath& target_path,
141       const std::vector<GURL>& url_chain,
142       const GURL& referrer_url,
143       const GURL& site_url,
144       const GURL& tab_url,
145       const GURL& tab_referrer_url,
146       const base::Optional<url::Origin>& request_initiator,
147       const std::string& mime_type,
148       const std::string& original_mime_type,
149       base::Time start_time,
150       base::Time end_time,
151       const std::string& etag,
152       const std::string& last_modofied,
153       int64_t received_bytes,
154       int64_t total_bytes,
155       const std::string& hash,
156       download::DownloadItem::DownloadState state,
157       download::DownloadDangerType danger_type,
158       download::DownloadInterruptReason interrupt_reason,
159       bool opened,
160       base::Time last_access_time,
161       bool transient,
162       const std::vector<download::DownloadItem::ReceivedSlice>& received_slices)
163       override;
164   download::DownloadItemImpl* CreateActiveItem(
165       download::DownloadItemImplDelegate* delegate,
166       uint32_t download_id,
167       const download::DownloadCreateInfo& info) override;
168   download::DownloadItemImpl* CreateSavePageItem(
169       download::DownloadItemImplDelegate* delegate,
170       uint32_t download_id,
171       const base::FilePath& path,
172       const GURL& url,
173       const std::string& mime_type,
174       download::DownloadJob::CancelRequestCallback cancel_request_callback)
175       override;
176 
set_is_download_persistent(bool is_download_persistent)177   void set_is_download_persistent(bool is_download_persistent) {
178     is_download_persistent_ = is_download_persistent;
179   }
180 
181  private:
182   std::map<uint32_t, download::MockDownloadItemImpl*> items_;
183   download::DownloadItemImplDelegate item_delegate_;
184   bool is_download_persistent_;
185 
186   DISALLOW_COPY_AND_ASSIGN(MockDownloadItemFactory);
187 };
188 
MockDownloadItemFactory()189 MockDownloadItemFactory::MockDownloadItemFactory()
190     : is_download_persistent_(false) {}
191 
~MockDownloadItemFactory()192 MockDownloadItemFactory::~MockDownloadItemFactory() {}
193 
GetItem(int id)194 download::MockDownloadItemImpl* MockDownloadItemFactory::GetItem(int id) {
195   if (items_.find(id) == items_.end())
196     return nullptr;
197   return items_[id];
198 }
199 
PopItem()200 download::MockDownloadItemImpl* MockDownloadItemFactory::PopItem() {
201   if (items_.empty())
202     return nullptr;
203 
204   auto first_item = items_.begin();
205   download::MockDownloadItemImpl* result = first_item->second;
206   items_.erase(first_item);
207   return result;
208 }
209 
RemoveItem(int id)210 void MockDownloadItemFactory::RemoveItem(int id) {
211   DCHECK(items_.find(id) != items_.end());
212   items_.erase(id);
213 }
214 
CreatePersistedItem(download::DownloadItemImplDelegate * delegate,const std::string & guid,uint32_t download_id,const base::FilePath & current_path,const base::FilePath & target_path,const std::vector<GURL> & url_chain,const GURL & referrer_url,const GURL & site_url,const GURL & tab_url,const GURL & tab_referrer_url,const base::Optional<url::Origin> & request_initiator,const std::string & mime_type,const std::string & original_mime_type,base::Time start_time,base::Time end_time,const std::string & etag,const std::string & last_modified,int64_t received_bytes,int64_t total_bytes,const std::string & hash,download::DownloadItem::DownloadState state,download::DownloadDangerType danger_type,download::DownloadInterruptReason interrupt_reason,bool opened,base::Time last_access_time,bool transient,const std::vector<download::DownloadItem::ReceivedSlice> & received_slices)215 download::DownloadItemImpl* MockDownloadItemFactory::CreatePersistedItem(
216     download::DownloadItemImplDelegate* delegate,
217     const std::string& guid,
218     uint32_t download_id,
219     const base::FilePath& current_path,
220     const base::FilePath& target_path,
221     const std::vector<GURL>& url_chain,
222     const GURL& referrer_url,
223     const GURL& site_url,
224     const GURL& tab_url,
225     const GURL& tab_referrer_url,
226     const base::Optional<url::Origin>& request_initiator,
227     const std::string& mime_type,
228     const std::string& original_mime_type,
229     base::Time start_time,
230     base::Time end_time,
231     const std::string& etag,
232     const std::string& last_modified,
233     int64_t received_bytes,
234     int64_t total_bytes,
235     const std::string& hash,
236     download::DownloadItem::DownloadState state,
237     download::DownloadDangerType danger_type,
238     download::DownloadInterruptReason interrupt_reason,
239     bool opened,
240     base::Time last_access_time,
241     bool transient,
242     const std::vector<download::DownloadItem::ReceivedSlice>& received_slices) {
243   DCHECK(items_.find(download_id) == items_.end());
244   download::MockDownloadItemImpl* result =
245       new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
246   EXPECT_CALL(*result, GetId())
247       .WillRepeatedly(Return(download_id));
248   EXPECT_CALL(*result, GetGuid()).WillRepeatedly(ReturnRefOfCopy(guid));
249   items_[download_id] = result;
250   return result;
251 }
252 
CreateActiveItem(download::DownloadItemImplDelegate * delegate,uint32_t download_id,const download::DownloadCreateInfo & info)253 download::DownloadItemImpl* MockDownloadItemFactory::CreateActiveItem(
254     download::DownloadItemImplDelegate* delegate,
255     uint32_t download_id,
256     const download::DownloadCreateInfo& info) {
257   DCHECK(items_.find(download_id) == items_.end());
258 
259   download::MockDownloadItemImpl* result =
260       new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
261   EXPECT_CALL(*result, GetId())
262       .WillRepeatedly(Return(download_id));
263   EXPECT_CALL(*result, GetGuid())
264       .WillRepeatedly(ReturnRefOfCopy(base::GenerateGUID()));
265   EXPECT_CALL(*result, GetUrlChain())
266       .WillRepeatedly(ReturnRefOfCopy(std::vector<GURL>()));
267   EXPECT_CALL(*result, GetReferrerUrl())
268       .WillRepeatedly(ReturnRefOfCopy(GURL()));
269   EXPECT_CALL(*result, GetTabUrl()).WillRepeatedly(ReturnRefOfCopy(GURL()));
270   EXPECT_CALL(*result, GetTabReferrerUrl())
271       .WillRepeatedly(ReturnRefOfCopy(GURL()));
272   EXPECT_CALL(*result, GetETag())
273       .WillRepeatedly(ReturnRefOfCopy(std::string()));
274   EXPECT_CALL(*result, GetLastModifiedTime())
275       .WillRepeatedly(ReturnRefOfCopy(std::string()));
276   EXPECT_CALL(*result, GetMimeType()).WillRepeatedly(Return(std::string()));
277   EXPECT_CALL(*result, GetOriginalMimeType())
278       .WillRepeatedly(Return(std::string()));
279   EXPECT_CALL(*result, GetTotalBytes()).WillRepeatedly(Return(0));
280   EXPECT_CALL(*result, GetFullPath())
281       .WillRepeatedly(
282           ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("foo"))));
283   EXPECT_CALL(*result, GetTargetFilePath())
284       .WillRepeatedly(
285           ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("foo"))));
286   EXPECT_CALL(*result, GetReceivedBytes()).WillRepeatedly(Return(0));
287   EXPECT_CALL(*result, GetStartTime()).WillRepeatedly(Return(base::Time()));
288   EXPECT_CALL(*result, GetEndTime()).WillRepeatedly(Return(base::Time()));
289   EXPECT_CALL(*result, GetReceivedSlices())
290       .WillRepeatedly(ReturnRefOfCopy(
291           std::vector<download::DownloadItem::ReceivedSlice>()));
292   EXPECT_CALL(*result, GetHash())
293       .WillRepeatedly(ReturnRefOfCopy(std::string()));
294   EXPECT_CALL(*result, GetState())
295       .WillRepeatedly(Return(download::DownloadItem::IN_PROGRESS));
296   EXPECT_CALL(*result, GetDangerType())
297       .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
298   EXPECT_CALL(*result, GetLastReason())
299       .WillRepeatedly(Return(download::DOWNLOAD_INTERRUPT_REASON_NONE));
300   EXPECT_CALL(*result, IsPaused()).WillRepeatedly(Return(false));
301   EXPECT_CALL(*result, IsTemporary()).WillRepeatedly(Return(false));
302 
303   if (is_download_persistent_) {
304     EXPECT_CALL(*result, RemoveObserver(_));
305     EXPECT_CALL(*result, AddObserver(_));
306   }
307   items_[download_id] = result;
308 
309   // Active items are created and then immediately are called to start
310   // the download.
311   EXPECT_CALL(*result, MockStart(_));
312 
313   return result;
314 }
315 
CreateSavePageItem(download::DownloadItemImplDelegate * delegate,uint32_t download_id,const base::FilePath & path,const GURL & url,const std::string & mime_type,download::DownloadJob::CancelRequestCallback cancel_request_callback)316 download::DownloadItemImpl* MockDownloadItemFactory::CreateSavePageItem(
317     download::DownloadItemImplDelegate* delegate,
318     uint32_t download_id,
319     const base::FilePath& path,
320     const GURL& url,
321     const std::string& mime_type,
322     download::DownloadJob::CancelRequestCallback cancel_request_callback) {
323   DCHECK(items_.find(download_id) == items_.end());
324 
325   download::MockDownloadItemImpl* result =
326       new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
327   EXPECT_CALL(*result, GetId())
328       .WillRepeatedly(Return(download_id));
329   items_[download_id] = result;
330 
331   return result;
332 }
333 
334 class MockDownloadFileFactory
335     : public download::DownloadFileFactory,
336       public base::SupportsWeakPtr<MockDownloadFileFactory> {
337  public:
MockDownloadFileFactory()338   MockDownloadFileFactory() {}
~MockDownloadFileFactory()339   ~MockDownloadFileFactory() override {}
340 
341   // Overridden method from DownloadFileFactory
342   MOCK_METHOD2(MockCreateFile,
343                download::MockDownloadFile*(const download::DownloadSaveInfo&,
344                                            download::InputStream*));
345 
CreateFile(std::unique_ptr<download::DownloadSaveInfo> save_info,const base::FilePath & default_download_directory,std::unique_ptr<download::InputStream> stream,uint32_t download_id,base::WeakPtr<download::DownloadDestinationObserver> observer)346   download::DownloadFile* CreateFile(
347       std::unique_ptr<download::DownloadSaveInfo> save_info,
348       const base::FilePath& default_download_directory,
349       std::unique_ptr<download::InputStream> stream,
350       uint32_t download_id,
351       base::WeakPtr<download::DownloadDestinationObserver> observer) override {
352     return MockCreateFile(*save_info, stream.get());
353   }
354 };
355 
356 class MockDownloadManagerObserver : public DownloadManager::Observer {
357  public:
MockDownloadManagerObserver()358   MockDownloadManagerObserver() {}
~MockDownloadManagerObserver()359   ~MockDownloadManagerObserver() override {}
360   MOCK_METHOD2(OnDownloadCreated,
361                void(DownloadManager*, download::DownloadItem*));
362   MOCK_METHOD1(ManagerGoingDown, void(DownloadManager*));
363   MOCK_METHOD2(SelectFileDialogDisplayed, void(DownloadManager*, int32_t));
364 };
365 
366 class TestInProgressManager : public download::InProgressDownloadManager {
367  public:
368   TestInProgressManager();
369   ~TestInProgressManager() override = default;
370 
371   std::vector<std::unique_ptr<download::DownloadItemImpl>>
372   TakeInProgressDownloads() override;
373 
374   void AddDownloadItem(std::unique_ptr<download::DownloadItemImpl> item);
375 
376  private:
377   std::vector<std::unique_ptr<download::DownloadItemImpl>> download_items_;
378 };
379 
TestInProgressManager()380 TestInProgressManager::TestInProgressManager()
381     : download::InProgressDownloadManager(
382           nullptr,
383           base::FilePath(),
384           nullptr,
385           download::InProgressDownloadManager::IsOriginSecureCallback(),
386           base::BindRepeating(&URLAlwaysSafe),
387           /*wake_lock_provider_binder*/ base::NullCallback()) {}
388 
AddDownloadItem(std::unique_ptr<download::DownloadItemImpl> item)389 void TestInProgressManager::AddDownloadItem(
390     std::unique_ptr<download::DownloadItemImpl> item) {
391   download_items_.emplace_back(std::move(item));
392 }
393 
394 std::vector<std::unique_ptr<download::DownloadItemImpl>>
TakeInProgressDownloads()395 TestInProgressManager::TakeInProgressDownloads() {
396   return std::move(download_items_);
397 }
398 
399 }  // namespace
400 
401 class DownloadManagerTest : public testing::Test {
402  public:
403   static const char* kTestData;
404   static const size_t kTestDataLen;
405 
DownloadManagerTest()406   DownloadManagerTest()
407       : callback_called_(false),
408         target_disposition_(
409             download::DownloadItem::TARGET_DISPOSITION_OVERWRITE),
410         danger_type_(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
411         interrupt_reason_(download::DOWNLOAD_INTERRUPT_REASON_NONE),
412         next_download_id_(0) {}
413 
414   // We tear down everything in TearDown().
~DownloadManagerTest()415   ~DownloadManagerTest() override {}
416 
417   // Create a MockDownloadItemFactory and MockDownloadManagerDelegate,
418   // then create a DownloadManager that points
419   // at all of those.
SetUp()420   void SetUp() override {
421     DCHECK(!download_manager_);
422 
423     mock_download_item_factory_ = (new MockDownloadItemFactory())->AsWeakPtr();
424     mock_download_file_factory_ = (new MockDownloadFileFactory())->AsWeakPtr();
425     mock_download_manager_delegate_.reset(
426         new StrictMock<MockDownloadManagerDelegate>);
427     EXPECT_CALL(*mock_download_manager_delegate_.get(), Shutdown())
428         .WillOnce(Return());
429     browser_context_ = std::make_unique<TestBrowserContext>();
430     download_manager_.reset(new DownloadManagerImpl(browser_context_.get()));
431     download_manager_->SetDownloadItemFactoryForTesting(
432         std::unique_ptr<download::DownloadItemFactory>(
433             mock_download_item_factory_.get()));
434     download_manager_->SetDownloadFileFactoryForTesting(
435         std::unique_ptr<download::DownloadFileFactory>(
436             mock_download_file_factory_.get()));
437     observer_.reset(new MockDownloadManagerObserver());
438     download_manager_->AddObserver(observer_.get());
439     download_manager_->SetDelegate(mock_download_manager_delegate_.get());
440     download_urls_.push_back(GURL("http://www.url1.com"));
441     download_urls_.push_back(GURL("http://www.url2.com"));
442     download_urls_.push_back(GURL("http://www.url3.com"));
443     download_urls_.push_back(GURL("http://www.url4.com"));
444   }
445 
TearDown()446   void TearDown() override {
447     while (download::MockDownloadItemImpl* item =
448                mock_download_item_factory_->PopItem()) {
449       EXPECT_CALL(*item, GetState())
450           .WillOnce(Return(download::DownloadItem::CANCELLED));
451     }
452     EXPECT_CALL(GetMockObserver(), ManagerGoingDown(download_manager_.get()))
453         .WillOnce(Return());
454 
455     download_manager_->Shutdown();
456     download_manager_.reset();
457     base::RunLoop().RunUntilIdle();
458     ASSERT_FALSE(mock_download_item_factory_);
459     mock_download_manager_delegate_.reset();
460     download_urls_.clear();
461   }
462 
463   // Returns download id.
AddItemToManager()464   download::MockDownloadItemImpl& AddItemToManager() {
465     download::DownloadCreateInfo info;
466 
467     // Args are ignored except for download id, so everything else can be
468     // null.
469     uint32_t id = next_download_id_;
470     ++next_download_id_;
471     download_manager_->CreateActiveItem(id, info);
472     DCHECK(mock_download_item_factory_->GetItem(id));
473     download::MockDownloadItemImpl& item(
474         *mock_download_item_factory_->GetItem(id));
475     // Satisfy expectation.  If the item is created in StartDownload(),
476     // we call Start on it immediately, so we need to set that expectation
477     // in the factory.
478     item.Start(std::unique_ptr<download::DownloadFile>(), base::DoNothing(),
479                info, download::URLLoaderFactoryProvider::GetNullPtr());
480     DCHECK(id < download_urls_.size());
481     EXPECT_CALL(item, GetURL()).WillRepeatedly(ReturnRef(download_urls_[id]));
482 
483     return item;
484   }
485 
486   // Helper function to create a download item.
CreateDownloadItem(const base::Time & start_time,const std::vector<GURL> & url_chain,download::DownloadItem::DownloadState download_state)487   download::DownloadItem* CreateDownloadItem(
488       const base::Time& start_time,
489       const std::vector<GURL>& url_chain,
490       download::DownloadItem::DownloadState download_state) {
491     download::DownloadItem* download_item =
492         download_manager_->CreateDownloadItem(
493             kGuid, 10, base::FilePath(), base::FilePath(), url_chain,
494             GURL("http://example.com/a"), GURL("http://example.com/a"),
495             GURL("http://example.com/a"), GURL("http://example.com/a"),
496             url::Origin::Create(GURL("http://example.com/")),
497             "application/octet-stream", "application/octet-stream", start_time,
498             base::Time::Now(), std::string(), std::string(), 10, 10,
499             std::string(), download_state,
500             download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
501             download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, false,
502             base::Time::Now(), true,
503             std::vector<download::DownloadItem::ReceivedSlice>());
504     return download_item;
505   }
506 
GetMockDownloadItem(int id)507   download::MockDownloadItemImpl& GetMockDownloadItem(int id) {
508     download::MockDownloadItemImpl* itemp =
509         mock_download_item_factory_->GetItem(id);
510 
511     DCHECK(itemp);
512     return *itemp;
513   }
514 
RemoveMockDownloadItem(int id)515   void RemoveMockDownloadItem(int id) {
516     // Owned by DownloadManager; should be deleted there.
517     mock_download_item_factory_->RemoveItem(id);
518   }
519 
GetMockDownloadManagerDelegate()520   MockDownloadManagerDelegate& GetMockDownloadManagerDelegate() {
521     return *mock_download_manager_delegate_;
522   }
523 
GetMockObserver()524   MockDownloadManagerObserver& GetMockObserver() {
525     return *observer_;
526   }
527 
DownloadTargetDeterminedCallback(const base::FilePath & target_path,download::DownloadItem::TargetDisposition disposition,download::DownloadDangerType danger_type,download::DownloadItem::MixedContentStatus mixed_content_status,const base::FilePath & intermediate_path,download::DownloadInterruptReason interrupt_reason)528   void DownloadTargetDeterminedCallback(
529       const base::FilePath& target_path,
530       download::DownloadItem::TargetDisposition disposition,
531       download::DownloadDangerType danger_type,
532       download::DownloadItem::MixedContentStatus mixed_content_status,
533       const base::FilePath& intermediate_path,
534       download::DownloadInterruptReason interrupt_reason) {
535     callback_called_ = true;
536     target_path_ = target_path;
537     target_disposition_ = disposition;
538     danger_type_ = danger_type;
539     intermediate_path_ = intermediate_path;
540     interrupt_reason_ = interrupt_reason;
541   }
542 
DetermineDownloadTarget(download::DownloadItemImpl * item)543   void DetermineDownloadTarget(download::DownloadItemImpl* item) {
544     download_manager_->DetermineDownloadTarget(
545         item,
546         base::BindOnce(&DownloadManagerTest::DownloadTargetDeterminedCallback,
547                        base::Unretained(this)));
548   }
549 
OnInProgressDownloadManagerInitialized()550   void OnInProgressDownloadManagerInitialized() {
551     download_manager_->OnDownloadsInitialized();
552   }
553 
OnHistoryDBInitialized()554   void OnHistoryDBInitialized() {
555     download_manager_->PostInitialization(
556         DownloadManager::DOWNLOAD_INITIALIZATION_DEPENDENCY_HISTORY_DB);
557   }
558 
SetInProgressDownloadManager(std::unique_ptr<download::InProgressDownloadManager> manager)559   void SetInProgressDownloadManager(
560       std::unique_ptr<download::InProgressDownloadManager> manager) {
561     download_manager_->in_progress_manager_ = std::move(manager);
562   }
563 
564  protected:
565   // Key test variable; we'll keep it available to sub-classes.
566   std::unique_ptr<DownloadManagerImpl> download_manager_;
567   base::WeakPtr<MockDownloadFileFactory> mock_download_file_factory_;
568   base::WeakPtr<MockDownloadItemFactory> mock_download_item_factory_;
569 
570   // Target detetermined callback.
571   bool callback_called_;
572   base::FilePath target_path_;
573   download::DownloadItem::TargetDisposition target_disposition_;
574   download::DownloadDangerType danger_type_;
575   base::FilePath intermediate_path_;
576   download::DownloadInterruptReason interrupt_reason_;
577 
578   std::vector<GURL> download_urls_;
579 
580  private:
581   BrowserTaskEnvironment task_environment_;
582   std::unique_ptr<MockDownloadManagerDelegate> mock_download_manager_delegate_;
583   std::unique_ptr<MockDownloadManagerObserver> observer_;
584   std::unique_ptr<TestBrowserContext> browser_context_;
585   uint32_t next_download_id_;
586 
587   DISALLOW_COPY_AND_ASSIGN(DownloadManagerTest);
588 };
589 
590 // Confirm the appropriate invocations occur when you start a download.
TEST_F(DownloadManagerTest,StartDownload)591 TEST_F(DownloadManagerTest, StartDownload) {
592   std::unique_ptr<download::DownloadCreateInfo> info(
593       new download::DownloadCreateInfo);
594   // Random value, a non 0 value means history db is properly loaded, and new
595   // downloads should be persisted to the in-progress db.
596   uint32_t local_id(5);
597   base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
598   OnInProgressDownloadManagerInitialized();
599 
600   EXPECT_FALSE(download_manager_->GetDownload(local_id));
601 
602   EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _))
603       .WillOnce(Return());
604   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId_(_))
605       .WillOnce(RunOnceCallback<0>(local_id));
606 
607 #if !defined(USE_X11)
608   // Doing nothing will set the default download directory to null.
609   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _));
610 #endif
611   EXPECT_CALL(GetMockDownloadManagerDelegate(),
612               ApplicationClientIdForFileScanning())
613       .WillRepeatedly(Return("client-id"));
614   download::MockDownloadFile* mock_file = new download::MockDownloadFile;
615   auto input_stream = std::make_unique<download::MockInputStream>();
616   EXPECT_CALL(*input_stream, IsEmpty()).WillRepeatedly(Return(false));
617   EXPECT_CALL(*mock_download_file_factory_.get(),
618               MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
619       .WillOnce(Return(mock_file));
620 
621   mock_download_item_factory_->set_is_download_persistent(true);
622   download_manager_->StartDownload(
623       std::move(info), std::move(input_stream),
624       download::DownloadUrlParameters::OnStartedCallback());
625   EXPECT_TRUE(download_manager_->GetDownload(local_id));
626 }
627 
628 // Test the case that a new download is started when history db failed to
629 // initialize.
TEST_F(DownloadManagerTest,StartDownloadWithoutHistoryDB)630 TEST_F(DownloadManagerTest, StartDownloadWithoutHistoryDB) {
631   std::unique_ptr<download::DownloadCreateInfo> info(
632       new download::DownloadCreateInfo);
633   base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
634   OnInProgressDownloadManagerInitialized();
635   EXPECT_FALSE(download_manager_->GetDownload(1));
636 
637   EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _))
638       .WillOnce(Return());
639   // Returning kInvalidId to indicate that the history db failed.
640   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId_(_))
641       .WillOnce(RunOnceCallback<0>(download::DownloadItem::kInvalidId));
642 
643 #if !defined(USE_X11)
644   // Doing nothing will set the default download directory to null.
645   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _));
646 #endif
647   EXPECT_CALL(GetMockDownloadManagerDelegate(),
648               ApplicationClientIdForFileScanning())
649       .WillRepeatedly(Return("client-id"));
650   download::MockDownloadFile* mock_file = new download::MockDownloadFile;
651   auto input_stream = std::make_unique<download::MockInputStream>();
652   EXPECT_CALL(*input_stream, IsEmpty()).WillRepeatedly(Return(false));
653   EXPECT_CALL(*mock_download_file_factory_.get(),
654               MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
655       .WillOnce(Return(mock_file));
656 
657   download_manager_->StartDownload(
658       std::move(info), std::move(input_stream),
659       download::DownloadUrlParameters::OnStartedCallback());
660   EXPECT_TRUE(download_manager_->GetDownload(1));
661 }
662 
663 // Confirm that calling DetermineDownloadTarget behaves properly if the delegate
664 // blocks starting.
TEST_F(DownloadManagerTest,DetermineDownloadTarget_True)665 TEST_F(DownloadManagerTest, DetermineDownloadTarget_True) {
666   // Put a mock we have a handle to on the download manager.
667   download::MockDownloadItemImpl& item(AddItemToManager());
668   EXPECT_CALL(item, GetState())
669       .WillRepeatedly(Return(download::DownloadItem::IN_PROGRESS));
670 
671   EXPECT_CALL(GetMockDownloadManagerDelegate(),
672               DetermineDownloadTarget(&item, _))
673       .WillOnce(Return(true));
674   DetermineDownloadTarget(&item);
675 }
676 
677 // Confirm that calling DetermineDownloadTarget behaves properly if the delegate
678 // allows starting.  This also tests OnDownloadTargetDetermined.
TEST_F(DownloadManagerTest,DetermineDownloadTarget_False)679 TEST_F(DownloadManagerTest, DetermineDownloadTarget_False) {
680   // Put a mock we have a handle to on the download manager.
681   download::MockDownloadItemImpl& item(AddItemToManager());
682 
683   base::FilePath path(FILE_PATH_LITERAL("random_filepath.txt"));
684   EXPECT_CALL(GetMockDownloadManagerDelegate(),
685               DetermineDownloadTarget(&item, _))
686       .WillOnce(Return(false));
687   EXPECT_CALL(item, GetForcedFilePath())
688       .WillOnce(ReturnRef(path));
689 
690   // Confirm that the callback was called with the right values in this case.
691   DetermineDownloadTarget(&item);
692   EXPECT_TRUE(callback_called_);
693   EXPECT_EQ(path, target_path_);
694   EXPECT_EQ(download::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
695             target_disposition_);
696   EXPECT_EQ(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, danger_type_);
697   EXPECT_EQ(path, intermediate_path_);
698   EXPECT_EQ(download::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason_);
699 }
700 
TEST_F(DownloadManagerTest,GetDownloadByGuid)701 TEST_F(DownloadManagerTest, GetDownloadByGuid) {
702   for (uint32_t i = 0; i < 4; ++i)
703     AddItemToManager();
704 
705   download::MockDownloadItemImpl& item = GetMockDownloadItem(0);
706   download::DownloadItem* result =
707       download_manager_->GetDownloadByGuid(item.GetGuid());
708   ASSERT_TRUE(result);
709   ASSERT_EQ(static_cast<download::DownloadItem*>(&item), result);
710 
711   ASSERT_FALSE(download_manager_->GetDownloadByGuid(""));
712 
713   std::vector<GURL> url_chain;
714   url_chain.emplace_back("http://example.com/1.zip");
715   EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _));
716   download::DownloadItem* persisted_item = CreateDownloadItem(
717       base::Time::Now(), url_chain, download::DownloadItem::INTERRUPTED);
718   ASSERT_TRUE(persisted_item);
719   ASSERT_EQ(persisted_item, download_manager_->GetDownloadByGuid(kGuid));
720 }
721 
722 namespace {
723 
GetSingleURLFilter(const GURL & url)724 base::RepeatingCallback<bool(const GURL&)> GetSingleURLFilter(const GURL& url) {
725   return base::BindRepeating(
726       [](const GURL& a, const GURL& b) { return a == b; }, url);
727 }
728 
729 }  // namespace
730 
731 // Confirm that only downloads with the specified URL are removed.
TEST_F(DownloadManagerTest,RemoveDownloadsByURL)732 TEST_F(DownloadManagerTest, RemoveDownloadsByURL) {
733   base::Time now(base::Time::Now());
734   for (uint32_t i = 0; i < 2; ++i) {
735     download::MockDownloadItemImpl& item(AddItemToManager());
736     EXPECT_CALL(item, GetStartTime()).WillRepeatedly(Return(now));
737     EXPECT_CALL(item, GetState())
738         .WillRepeatedly(Return(download::DownloadItem::COMPLETE));
739   }
740 
741   EXPECT_CALL(GetMockDownloadItem(0), Remove());
742   EXPECT_CALL(GetMockDownloadItem(1), Remove()).Times(0);
743 
744   base::RepeatingCallback<bool(const GURL&)> url_filter =
745       GetSingleURLFilter(download_urls_[0]);
746   int remove_count = download_manager_->RemoveDownloadsByURLAndTime(
747       std::move(url_filter), base::Time(), base::Time::Max());
748   EXPECT_EQ(remove_count, 1);
749 }
750 
751 // Confirm that in-progress downloads will be taken and managed by
752 // DownloadManager.
TEST_F(DownloadManagerTest,OnInProgressDownloadsLoaded)753 TEST_F(DownloadManagerTest, OnInProgressDownloadsLoaded) {
754   auto in_progress_manager = std::make_unique<TestInProgressManager>();
755   std::vector<GURL> url_chain;
756   url_chain.emplace_back("http://example.com/1.zip");
757   auto in_progress_item = std::make_unique<download::DownloadItemImpl>(
758       in_progress_manager.get(), kGuid, 10, base::FilePath(), base::FilePath(),
759       url_chain, GURL("http://example.com/a"), GURL("http://example.com/a"),
760       GURL("http://example.com/a"), GURL("http://example.com/a"),
761       url::Origin::Create(GURL("http://example.com")),
762       "application/octet-stream", "application/octet-stream", base::Time::Now(),
763       base::Time::Now(), std::string(), std::string(), 10, 10, 0, std::string(),
764       download::DownloadItem::INTERRUPTED,
765       download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
766       download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, false, false, false,
767       base::Time::Now(), true,
768       std::vector<download::DownloadItem::ReceivedSlice>(),
769       nullptr /* download_entry */);
770   in_progress_manager->AddDownloadItem(std::move(in_progress_item));
771   SetInProgressDownloadManager(std::move(in_progress_manager));
772   EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _))
773       .WillOnce(Return());
774   OnInProgressDownloadManagerInitialized();
775   ASSERT_TRUE(download_manager_->GetDownloadByGuid(kGuid));
776   std::vector<download::DownloadItem*> vector;
777   download_manager_->GetAllDownloads(&vector);
778   ASSERT_EQ(0u, vector.size());
779 
780   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId_(_))
781       .WillOnce(RunOnceCallback<0>(1));
782   OnHistoryDBInitialized();
783   ASSERT_TRUE(download_manager_->GetDownloadByGuid(kGuid));
784   download::DownloadItem* download =
785       download_manager_->GetDownloadByGuid(kGuid);
786   download_manager_->GetAllDownloads(&vector);
787   ASSERT_EQ(1u, vector.size());
788   download->Remove();
789   ASSERT_FALSE(download_manager_->GetDownloadByGuid(kGuid));
790 }
791 
792 // Verifies that expired canceled or interrupted downloads are deleted
793 // correctly.
TEST_F(DownloadManagerTest,DeleteExpiredDownload)794 TEST_F(DownloadManagerTest, DeleteExpiredDownload) {
795   base::test::ScopedFeatureList scoped_feature_list;
796   std::map<std::string, std::string> params = {
797       {download::kExpiredDownloadDeleteTimeFinchKey, base::NumberToString(1)}};
798   scoped_feature_list.InitAndEnableFeatureWithParameters(
799       download::features::kDeleteExpiredDownloads, params);
800 
801   std::vector<GURL> url_chain;
802   url_chain.emplace_back("http://example.com/1.zip");
803   auto expired_start_time = base::Time::Now() - base::TimeDelta::FromDays(10);
804   download::DownloadItem* download_item = CreateDownloadItem(
805       expired_start_time, url_chain, download::DownloadItem::INTERRUPTED);
806   EXPECT_FALSE(download_item)
807       << "Expired interrupted download will be deleted.";
808 
809   download_item = CreateDownloadItem(expired_start_time, url_chain,
810                                      download::DownloadItem::CANCELLED);
811   EXPECT_FALSE(download_item) << "Expired canceled download will be deleted.";
812 
813   download_item = CreateDownloadItem(expired_start_time, std::vector<GURL>(),
814                                      download::DownloadItem::COMPLETE);
815   EXPECT_FALSE(download_item) << "Download without URL chain will be deleted.";
816 
817   EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _));
818   download_item = CreateDownloadItem(expired_start_time, url_chain,
819                                      download::DownloadItem::COMPLETE);
820   EXPECT_TRUE(download_item)
821       << "Expired complete download will not be deleted.";
822 }
823 
824 }  // namespace content
825