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