download_manager_unittest.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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/download/download_file.h" 10#include "chrome/browser/download/download_file_manager.h" 11#include "chrome/browser/download/download_item.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/download/mock_download_manager.h" 17#include "chrome/browser/history/download_create_info.h" 18#include "chrome/browser/prefs/pref_service.h" 19#include "chrome/common/pref_names.h" 20#include "chrome/test/testing_profile.h" 21#include "content/browser/browser_thread.h" 22#include "testing/gmock/include/gmock/gmock.h" 23#include "testing/gmock_mutant.h" 24#include "testing/gtest/include/gtest/gtest.h" 25 26class DownloadManagerTest : public testing::Test { 27 public: 28 DownloadManagerTest() 29 : profile_(new TestingProfile()), 30 download_manager_(new MockDownloadManager(&download_status_updater_)), 31 ui_thread_(BrowserThread::UI, &message_loop_) { 32 download_manager_->Init(profile_.get()); 33 } 34 35 ~DownloadManagerTest() { 36 download_manager_->Shutdown(); 37 // profile_ must outlive download_manager_, so we explicitly delete 38 // download_manager_ first. 39 download_manager_ = NULL; 40 profile_.reset(NULL); 41 message_loop_.RunAllPending(); 42 } 43 44 void AddDownloadToFileManager(int id, DownloadFile* download) { 45 file_manager()->downloads_[id] = download; 46 } 47 48 protected: 49 DownloadStatusUpdater download_status_updater_; 50 scoped_ptr<TestingProfile> profile_; 51 scoped_refptr<DownloadManager> download_manager_; 52 scoped_refptr<DownloadFileManager> file_manager_; 53 MessageLoopForUI message_loop_; 54 BrowserThread ui_thread_; 55 56 DownloadFileManager* file_manager() { 57 if (!file_manager_) { 58 file_manager_ = new DownloadFileManager(NULL); 59 download_manager_->file_manager_ = file_manager_; 60 } 61 return file_manager_; 62 } 63 64 // Make sure download item |id| was set with correct safety state for 65 // given |is_dangerous_file| and |is_dangerous_url|. 66 bool VerifySafetyState(bool is_dangerous_file, 67 bool is_dangerous_url, 68 int id) { 69 DownloadItem::SafetyState safety_state = 70 download_manager_->GetDownloadItem(id)->safety_state(); 71 return (is_dangerous_file || is_dangerous_url) ? 72 safety_state != DownloadItem::SAFE : safety_state == DownloadItem::SAFE; 73 } 74 75 DISALLOW_COPY_AND_ASSIGN(DownloadManagerTest); 76}; 77 78namespace { 79 80const struct { 81 const char* url; 82 const char* mime_type; 83 bool save_as; 84 bool prompt_for_download; 85 bool expected_save_as; 86} kStartDownloadCases[] = { 87 { "http://www.foo.com/dont-open.html", 88 "text/html", 89 false, 90 false, 91 false, }, 92 { "http://www.foo.com/save-as.html", 93 "text/html", 94 true, 95 false, 96 true, }, 97 { "http://www.foo.com/always-prompt.html", 98 "text/html", 99 false, 100 true, 101 true, }, 102 { "http://www.foo.com/user-script-text-html-mimetype.user.js", 103 "text/html", 104 false, 105 false, 106 false, }, 107 { "http://www.foo.com/extensionless-extension", 108 "application/x-chrome-extension", 109 true, 110 false, 111 true, }, 112 { "http://www.foo.com/save-as.pdf", 113 "application/pdf", 114 true, 115 false, 116 true, }, 117 { "http://www.foo.com/sometimes_prompt.pdf", 118 "application/pdf", 119 false, 120 true, 121 false, }, 122 { "http://www.foo.com/always_prompt.jar", 123 "application/jar", 124 false, 125 true, 126 true, }, 127}; 128 129} // namespace 130 131TEST_F(DownloadManagerTest, StartDownload) { 132 BrowserThread io_thread(BrowserThread::IO, &message_loop_); 133 PrefService* prefs = profile_->GetPrefs(); 134 prefs->SetFilePath(prefs::kDownloadDefaultDirectory, FilePath()); 135 download_manager_->download_prefs()->EnableAutoOpenBasedOnExtension( 136 FilePath(FILE_PATH_LITERAL("example.pdf"))); 137 138 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kStartDownloadCases); ++i) { 139 prefs->SetBoolean(prefs::kPromptForDownload, 140 kStartDownloadCases[i].prompt_for_download); 141 142 DownloadCreateInfo info; 143 info.prompt_user_for_save_location = kStartDownloadCases[i].save_as; 144 info.url = GURL(kStartDownloadCases[i].url); 145 info.mime_type = kStartDownloadCases[i].mime_type; 146 147 download_manager_->StartDownload(&info); 148 message_loop_.RunAllPending(); 149 150 EXPECT_EQ(kStartDownloadCases[i].expected_save_as, 151 info.prompt_user_for_save_location); 152 } 153} 154 155namespace { 156 157const struct { 158 FilePath::StringType suggested_path; 159 bool is_dangerous_file; 160 bool is_dangerous_url; 161 bool finish_before_rename; 162 int expected_rename_count; 163} kDownloadRenameCases[] = { 164 // Safe download, download finishes BEFORE file name determined. 165 // Renamed twice (linear path through UI). Crdownload file does not need 166 // to be deleted. 167 { FILE_PATH_LITERAL("foo.zip"), 168 false, false, true, 2, }, 169 // Dangerous download (file is dangerous or download URL is not safe or both), 170 // download finishes BEFORE file name determined. Needs to be renamed only 171 // once. 172 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 173 true, false, true, 1, }, 174 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 175 false, true, true, 1, }, 176 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 177 true, true, true, 1, }, 178 // Safe download, download finishes AFTER file name determined. 179 // Needs to be renamed twice. 180 { FILE_PATH_LITERAL("foo.zip"), 181 false, false, false, 2, }, 182 // Dangerous download, download finishes AFTER file name determined. 183 // Needs to be renamed only once. 184 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 185 true, false, false, 1, }, 186 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 187 false, true, false, 1, }, 188 { FILE_PATH_LITERAL("Unconfirmed xxx.crdownload"), 189 true, true, false, 1, }, 190}; 191 192class MockDownloadFile : public DownloadFile { 193 public: 194 explicit MockDownloadFile(DownloadCreateInfo* info) 195 : DownloadFile(info, NULL), renamed_count_(0) { } 196 virtual ~MockDownloadFile() { Destructed(); } 197 MOCK_METHOD1(Rename, bool(const FilePath&)); 198 MOCK_METHOD0(Destructed, void()); 199 200 bool TestMultipleRename( 201 int expected_count, const FilePath& expected, 202 const FilePath& path) { 203 ++renamed_count_; 204 EXPECT_EQ(expected_count, renamed_count_); 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_file = kDownloadRenameCases[i].is_dangerous_file; 229 info->is_dangerous_url = kDownloadRenameCases[i].is_dangerous_url; 230 FilePath new_path(kDownloadRenameCases[i].suggested_path); 231 232 MockDownloadFile* download(new MockDownloadFile(info)); 233 AddDownloadToFileManager(info->download_id, download); 234 235 // |download| is owned by DownloadFileManager. 236 ::testing::Mock::AllowLeak(download); 237 EXPECT_CALL(*download, Destructed()).Times(1); 238 239 if (kDownloadRenameCases[i].expected_rename_count == 1) { 240 EXPECT_CALL(*download, Rename(new_path)).WillOnce(Return(true)); 241 } else { 242 ASSERT_EQ(2, kDownloadRenameCases[i].expected_rename_count); 243 FilePath crdownload(download_util::GetCrDownloadPath(new_path)); 244 EXPECT_CALL(*download, Rename(_)) 245 .WillOnce(testing::WithArgs<0>(Invoke(CreateFunctor( 246 download, &MockDownloadFile::TestMultipleRename, 247 1, crdownload)))) 248 .WillOnce(testing::WithArgs<0>(Invoke(CreateFunctor( 249 download, &MockDownloadFile::TestMultipleRename, 250 2, new_path)))); 251 } 252 download_manager_->CreateDownloadItem(info); 253 254 if (kDownloadRenameCases[i].finish_before_rename) { 255 download_manager_->OnAllDataSaved(i, 1024); 256 download_manager_->FileSelected(new_path, i, info); 257 } else { 258 download_manager_->FileSelected(new_path, i, info); 259 download_manager_->OnAllDataSaved(i, 1024); 260 } 261 262 message_loop_.RunAllPending(); 263 EXPECT_TRUE(VerifySafetyState(kDownloadRenameCases[i].is_dangerous_file, 264 kDownloadRenameCases[i].is_dangerous_url, 265 i)); 266 } 267} 268