download_manager_unittest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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 <string>
6
7#include "base/string_util.h"
8#include "build/build_config.h"
9#include "chrome/browser/browser_thread.h"
10#include "chrome/browser/download/download_file.h"
11#include "chrome/browser/download/download_file_manager.h"
12#include "chrome/browser/download/download_manager.h"
13#include "chrome/browser/download/download_prefs.h"
14#include "chrome/browser/download/download_status_updater.h"
15#include "chrome/browser/download/download_util.h"
16#include "chrome/browser/history/download_create_info.h"
17#include "chrome/browser/prefs/pref_service.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/testing_profile.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gmock_mutant.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24class MockDownloadManager : public DownloadManager {
25 public:
26  explicit MockDownloadManager(DownloadStatusUpdater* updater)
27      : DownloadManager(updater) {
28  }
29
30  // Override some functions.
31  virtual void UpdateHistoryForDownload(DownloadItem*) { }
32  virtual void ContinueDownloadFinished(DownloadItem*) { }
33};
34
35class DownloadManagerTest : public testing::Test {
36 public:
37  DownloadManagerTest()
38      : profile_(new TestingProfile()),
39        download_manager_(new MockDownloadManager(&download_status_updater_)),
40        ui_thread_(BrowserThread::UI, &message_loop_) {
41    download_manager_->Init(profile_.get());
42  }
43
44  ~DownloadManagerTest() {
45    download_manager_->Shutdown();
46    // profile_ must outlive download_manager_, so we explicitly delete
47    // download_manager_ first.
48    download_manager_ = NULL;
49    profile_.reset(NULL);
50    message_loop_.RunAllPending();
51  }
52
53  void AddDownloadToFileManager(int id, DownloadFile* download) {
54    file_manager()->downloads_[id] = download;
55  }
56
57 protected:
58  DownloadStatusUpdater download_status_updater_;
59  scoped_ptr<TestingProfile> profile_;
60  scoped_refptr<DownloadManager> download_manager_;
61  scoped_refptr<DownloadFileManager> file_manager_;
62  MessageLoopForUI message_loop_;
63  BrowserThread ui_thread_;
64
65  DownloadFileManager* file_manager() {
66    if (!file_manager_) {
67      file_manager_ = new DownloadFileManager(NULL);
68      download_manager_->file_manager_ = file_manager_;
69    }
70    return file_manager_;
71  }
72
73  DISALLOW_COPY_AND_ASSIGN(DownloadManagerTest);
74};
75
76namespace {
77
78const struct {
79  const char* url;
80  const char* mime_type;
81  bool save_as;
82  bool prompt_for_download;
83  bool expected_save_as;
84} kStartDownloadCases[] = {
85  { "http://www.foo.com/dont-open.html",
86    "text/html",
87    false,
88    false,
89    false, },
90  { "http://www.foo.com/save-as.html",
91    "text/html",
92    true,
93    false,
94    true, },
95  { "http://www.foo.com/always-prompt.html",
96    "text/html",
97    false,
98    true,
99    true, },
100  { "http://www.foo.com/wrong_mime_extension.user.js",
101    "text/html",
102    false,
103    true,
104    false, },
105  { "http://www.foo.com/extensionless-extension",
106    "application/x-chrome-extension",
107    true,
108    false,
109    true, },
110  { "http://www.foo.com/save-as.pdf",
111    "application/pdf",
112    true,
113    false,
114    true, },
115  { "http://www.foo.com/sometimes_prompt.pdf",
116    "application/pdf",
117    false,
118    true,
119    false, },
120  { "http://www.foo.com/always_prompt.jar",
121    "application/jar",
122    false,
123    true,
124    true, },
125};
126
127}  // namespace
128
129TEST_F(DownloadManagerTest, StartDownload) {
130  PrefService* prefs = profile_->GetPrefs();
131  prefs->SetFilePath(prefs::kDownloadDefaultDirectory, FilePath());
132  download_manager_->download_prefs()->EnableAutoOpenBasedOnExtension(
133      FilePath(FILE_PATH_LITERAL("example.pdf")));
134
135  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kStartDownloadCases); ++i) {
136    prefs->SetBoolean(prefs::kPromptForDownload,
137                      kStartDownloadCases[i].prompt_for_download);
138
139    DownloadCreateInfo info;
140    info.prompt_user_for_save_location = kStartDownloadCases[i].save_as;
141    info.url = GURL(kStartDownloadCases[i].url);
142    info.mime_type = kStartDownloadCases[i].mime_type;
143
144    download_manager_->StartDownload(&info);
145
146    EXPECT_EQ(kStartDownloadCases[i].expected_save_as,
147        info.prompt_user_for_save_location);
148  }
149}
150
151namespace {
152
153const struct {
154  FilePath::StringType suggested_path;
155  bool is_dangerous;
156  bool finish_before_rename;
157  bool will_delete_crdownload;
158  int expected_rename_count;
159} kDownloadRenameCases[] = {
160  // Safe download, download finishes BEFORE rename.
161  // Needs to be renamed only once.  Crdownload file needs to be deleted.
162  { FILE_PATH_LITERAL("foo.zip"),
163    false,
164    true,
165    true,
166    1, },
167  // Dangerous download, download finishes BEFORE rename.
168  // Needs to be renamed only once.
169  { FILE_PATH_LITERAL("unconfirmed xxx.crdownload"),
170    true,
171    true,
172    false,
173    1, },
174  // Safe download, download finishes AFTER rename.
175  // Needs to be renamed twice.
176  { FILE_PATH_LITERAL("foo.zip"),
177    false,
178    false,
179    false,
180    2, },
181  // Dangerous download, download finishes AFTER rename.
182  // Needs to be renamed only once.
183  { FILE_PATH_LITERAL("unconfirmed xxx.crdownload"),
184    true,
185    false,
186    false,
187    1, },
188};
189
190class MockDownloadFile : public DownloadFile {
191 public:
192  explicit MockDownloadFile(DownloadCreateInfo* info)
193      : DownloadFile(info, NULL), renamed_count_(0) { }
194  virtual ~MockDownloadFile() { Destructed(); }
195  MOCK_METHOD2(Rename, bool(const FilePath&, bool));
196  MOCK_METHOD0(DeleteCrDownload, void());
197  MOCK_METHOD0(Destructed, void());
198
199  bool TestMultipleRename(
200      int expected_count, bool expected_final, const FilePath& expected,
201      const FilePath& path, bool is_final_rename) {
202    ++renamed_count_;
203    EXPECT_EQ(expected_count, renamed_count_);
204    EXPECT_EQ(expected_final, is_final_rename);
205    EXPECT_EQ(expected.value(), path.value());
206    return true;
207  }
208
209 private:
210  int renamed_count_;
211};
212
213}  // namespace
214
215TEST_F(DownloadManagerTest, DownloadRenameTest) {
216  using ::testing::_;
217  using ::testing::CreateFunctor;
218  using ::testing::Invoke;
219  using ::testing::Return;
220
221  BrowserThread file_thread(BrowserThread::FILE, &message_loop_);
222
223  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDownloadRenameCases); ++i) {
224    // |info| will be destroyed in download_manager_.
225    DownloadCreateInfo* info(new DownloadCreateInfo);
226    info->download_id = static_cast<int>(i);
227    info->prompt_user_for_save_location = false;
228    info->is_dangerous = kDownloadRenameCases[i].is_dangerous;
229    FilePath new_path(kDownloadRenameCases[i].suggested_path);
230
231    MockDownloadFile* download(new MockDownloadFile(info));
232    AddDownloadToFileManager(info->download_id, download);
233
234    // |download| is owned by DownloadFileManager.
235    ::testing::Mock::AllowLeak(download);
236    EXPECT_CALL(*download, Destructed()).Times(1);
237
238    if (kDownloadRenameCases[i].expected_rename_count == 1) {
239      EXPECT_CALL(*download, Rename(new_path, true)).WillOnce(Return(true));
240    } else {
241      ASSERT_EQ(2, kDownloadRenameCases[i].expected_rename_count);
242      FilePath crdownload(download_util::GetCrDownloadPath(new_path));
243      EXPECT_CALL(*download, Rename(_, _))
244          .WillOnce(testing::WithArgs<0, 1>(Invoke(CreateFunctor(
245              download, &MockDownloadFile::TestMultipleRename,
246              1, false, crdownload))))
247          .WillOnce(testing::WithArgs<0, 1>(Invoke(CreateFunctor(
248              download, &MockDownloadFile::TestMultipleRename,
249              2, true, new_path))));
250    }
251
252    if (kDownloadRenameCases[i].will_delete_crdownload)
253      EXPECT_CALL(*download, DeleteCrDownload()).Times(1);
254
255    download_manager_->CreateDownloadItem(info);
256
257    if (kDownloadRenameCases[i].finish_before_rename) {
258      download_manager_->OnAllDataSaved(i, 1024);
259      download_manager_->FileSelected(new_path, i, info);
260    } else {
261      download_manager_->FileSelected(new_path, i, info);
262      download_manager_->OnAllDataSaved(i, 1024);
263    }
264
265    message_loop_.RunAllPending();
266  }
267}
268