1 // Copyright 2013 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 "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/files/file_path.h" 8 #include "base/files/file_util.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/path_service.h" 13 #include "base/run_loop.h" 14 #include "components/component_updater/crx_downloader.h" 15 #include "net/base/net_errors.h" 16 #include "net/url_request/test_url_request_interceptor.h" 17 #include "net/url_request/url_request_test_util.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using base::ContentsEqual; 21 22 namespace component_updater { 23 24 namespace { 25 26 // Intercepts HTTP GET requests sent to "localhost". 27 typedef net::LocalHostTestURLRequestInterceptor GetInterceptor; 28 29 const char kTestFileName[] = "jebgalgnebhfojomionfpkfelancnnkf.crx"; 30 31 base::FilePath MakeTestFilePath(const char* file) { 32 base::FilePath path; 33 PathService::Get(base::DIR_SOURCE_ROOT, &path); 34 return path.AppendASCII("components").AppendASCII("test").AppendASCII("data") 35 .AppendASCII("component_updater").AppendASCII(file); 36 } 37 38 } // namespace 39 40 class CrxDownloaderTest : public testing::Test { 41 public: 42 CrxDownloaderTest(); 43 virtual ~CrxDownloaderTest(); 44 45 // Overrides from testing::Test. 46 virtual void SetUp() OVERRIDE; 47 virtual void TearDown() OVERRIDE; 48 49 void Quit(); 50 void RunThreads(); 51 void RunThreadsUntilIdle(); 52 53 void DownloadComplete(int crx_context, const CrxDownloader::Result& result); 54 55 void DownloadProgress(int crx_context, const CrxDownloader::Result& result); 56 57 protected: 58 scoped_ptr<CrxDownloader> crx_downloader_; 59 60 scoped_ptr<GetInterceptor> get_interceptor_; 61 62 CrxDownloader::DownloadCallback callback_; 63 CrxDownloader::ProgressCallback progress_callback_; 64 65 int crx_context_; 66 67 int num_download_complete_calls_; 68 CrxDownloader::Result download_complete_result_; 69 70 // These members are updated by DownloadProgress. 71 int num_progress_calls_; 72 CrxDownloader::Result download_progress_result_; 73 74 // A magic value for the context to be used in the tests. 75 static const int kExpectedContext = 0xaabb; 76 77 private: 78 base::MessageLoopForIO loop_; 79 scoped_refptr<net::TestURLRequestContextGetter> context_; 80 base::Closure quit_closure_; 81 }; 82 83 const int CrxDownloaderTest::kExpectedContext; 84 85 CrxDownloaderTest::CrxDownloaderTest() 86 : callback_(base::Bind(&CrxDownloaderTest::DownloadComplete, 87 base::Unretained(this), 88 kExpectedContext)), 89 progress_callback_(base::Bind(&CrxDownloaderTest::DownloadProgress, 90 base::Unretained(this), 91 kExpectedContext)), 92 crx_context_(0), 93 num_download_complete_calls_(0), 94 num_progress_calls_(0), 95 context_(new net::TestURLRequestContextGetter( 96 base::MessageLoopProxy::current())) { 97 } 98 99 CrxDownloaderTest::~CrxDownloaderTest() { 100 context_ = NULL; 101 102 // The GetInterceptor requires the message loop to run to destruct correctly. 103 get_interceptor_.reset(); 104 RunThreadsUntilIdle(); 105 } 106 107 void CrxDownloaderTest::SetUp() { 108 num_download_complete_calls_ = 0; 109 download_complete_result_ = CrxDownloader::Result(); 110 num_progress_calls_ = 0; 111 download_progress_result_ = CrxDownloader::Result(); 112 113 crx_downloader_.reset(CrxDownloader::Create( 114 false, // Do not use the background downloader in these tests. 115 context_.get(), 116 base::MessageLoopProxy::current(), 117 NULL)); // No |background_task_runner| because no background downloader. 118 crx_downloader_->set_progress_callback(progress_callback_); 119 120 get_interceptor_.reset(new GetInterceptor(base::MessageLoopProxy::current(), 121 base::MessageLoopProxy::current())); 122 } 123 124 void CrxDownloaderTest::TearDown() { 125 crx_downloader_.reset(); 126 } 127 128 void CrxDownloaderTest::Quit() { 129 if (!quit_closure_.is_null()) 130 quit_closure_.Run(); 131 } 132 133 void CrxDownloaderTest::DownloadComplete(int crx_context, 134 const CrxDownloader::Result& result) { 135 ++num_download_complete_calls_; 136 crx_context_ = crx_context; 137 download_complete_result_ = result; 138 Quit(); 139 } 140 141 void CrxDownloaderTest::DownloadProgress(int crx_context, 142 const CrxDownloader::Result& result) { 143 ++num_progress_calls_; 144 download_progress_result_ = result; 145 } 146 147 void CrxDownloaderTest::RunThreads() { 148 base::RunLoop runloop; 149 quit_closure_ = runloop.QuitClosure(); 150 runloop.Run(); 151 152 // Since some tests need to drain currently enqueued tasks such as network 153 // intercepts on the IO thread, run the threads until they are 154 // idle. The component updater service won't loop again until the loop count 155 // is set and the service is started. 156 RunThreadsUntilIdle(); 157 } 158 159 void CrxDownloaderTest::RunThreadsUntilIdle() { 160 base::RunLoop().RunUntilIdle(); 161 } 162 163 // Tests that starting a download without a url results in an error. 164 TEST_F(CrxDownloaderTest, NoUrl) { 165 std::vector<GURL> urls; 166 crx_downloader_->StartDownload(urls, callback_); 167 RunThreadsUntilIdle(); 168 169 EXPECT_EQ(1, num_download_complete_calls_); 170 EXPECT_EQ(kExpectedContext, crx_context_); 171 EXPECT_EQ(-1, download_complete_result_.error); 172 EXPECT_TRUE(download_complete_result_.response.empty()); 173 EXPECT_EQ(-1, download_complete_result_.downloaded_bytes); 174 EXPECT_EQ(-1, download_complete_result_.total_bytes); 175 EXPECT_EQ(0, num_progress_calls_); 176 } 177 178 // Tests that downloading from one url is successful. 179 TEST_F(CrxDownloaderTest, OneUrl) { 180 const GURL expected_crx_url = 181 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 182 183 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 184 get_interceptor_->SetResponse(expected_crx_url, test_file); 185 186 crx_downloader_->StartDownloadFromUrl(expected_crx_url, callback_); 187 RunThreads(); 188 189 EXPECT_EQ(1, get_interceptor_->GetHitCount()); 190 191 EXPECT_EQ(1, num_download_complete_calls_); 192 EXPECT_EQ(kExpectedContext, crx_context_); 193 EXPECT_EQ(0, download_complete_result_.error); 194 EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); 195 EXPECT_EQ(1843, download_complete_result_.total_bytes); 196 EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); 197 198 EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); 199 200 EXPECT_LE(1, num_progress_calls_); 201 EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); 202 EXPECT_EQ(1843, download_progress_result_.total_bytes); 203 } 204 205 // Tests that specifying from two urls has no side effects. Expect a successful 206 // download, and only one download request be made. 207 // This test is flaky on Android. crbug.com/329883 208 #if defined(OS_ANDROID) 209 #define MAYBE_TwoUrls DISABLED_TwoUrls 210 #else 211 #define MAYBE_TwoUrls TwoUrls 212 #endif 213 TEST_F(CrxDownloaderTest, MAYBE_TwoUrls) { 214 const GURL expected_crx_url = 215 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 216 217 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 218 get_interceptor_->SetResponse(expected_crx_url, test_file); 219 220 std::vector<GURL> urls; 221 urls.push_back(expected_crx_url); 222 urls.push_back(expected_crx_url); 223 224 crx_downloader_->StartDownload(urls, callback_); 225 RunThreads(); 226 227 EXPECT_EQ(1, get_interceptor_->GetHitCount()); 228 229 EXPECT_EQ(1, num_download_complete_calls_); 230 EXPECT_EQ(kExpectedContext, crx_context_); 231 EXPECT_EQ(0, download_complete_result_.error); 232 EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); 233 EXPECT_EQ(1843, download_complete_result_.total_bytes); 234 EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); 235 236 EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); 237 238 EXPECT_LE(1, num_progress_calls_); 239 EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); 240 EXPECT_EQ(1843, download_progress_result_.total_bytes); 241 } 242 243 // Tests that an invalid host results in a download error. 244 TEST_F(CrxDownloaderTest, OneUrl_InvalidHost) { 245 const GURL expected_crx_url = 246 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 247 248 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 249 get_interceptor_->SetResponse(expected_crx_url, test_file); 250 251 crx_downloader_->StartDownloadFromUrl( 252 GURL("http://no.such.host" 253 "/download/jebgalgnebhfojomionfpkfelancnnkf.crx"), 254 callback_); 255 RunThreads(); 256 257 EXPECT_EQ(0, get_interceptor_->GetHitCount()); 258 259 EXPECT_EQ(1, num_download_complete_calls_); 260 EXPECT_EQ(kExpectedContext, crx_context_); 261 EXPECT_NE(0, download_complete_result_.error); 262 EXPECT_TRUE(download_complete_result_.response.empty()); 263 } 264 265 // Tests that an invalid path results in a download error. 266 TEST_F(CrxDownloaderTest, OneUrl_InvalidPath) { 267 const GURL expected_crx_url = 268 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 269 270 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 271 get_interceptor_->SetResponse(expected_crx_url, test_file); 272 273 crx_downloader_->StartDownloadFromUrl(GURL("http://localhost/no/such/file"), 274 callback_); 275 RunThreads(); 276 277 EXPECT_EQ(0, get_interceptor_->GetHitCount()); 278 279 EXPECT_EQ(1, num_download_complete_calls_); 280 EXPECT_EQ(kExpectedContext, crx_context_); 281 EXPECT_NE(0, download_complete_result_.error); 282 EXPECT_TRUE(download_complete_result_.response.empty()); 283 } 284 285 // Tests that the fallback to a valid url is successful. 286 // This test is flaky on Android. crbug.com/329883 287 #if defined(OS_ANDROID) 288 #define MAYBE_TwoUrls_FirstInvalid DISABLED_TwoUrls_FirstInvalid 289 #else 290 #define MAYBE_TwoUrls_FirstInvalid TwoUrls_FirstInvalid 291 #endif 292 TEST_F(CrxDownloaderTest, MAYBE_TwoUrls_FirstInvalid) { 293 const GURL expected_crx_url = 294 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 295 296 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 297 get_interceptor_->SetResponse(expected_crx_url, test_file); 298 299 std::vector<GURL> urls; 300 urls.push_back(GURL("http://localhost/no/such/file")); 301 urls.push_back(expected_crx_url); 302 303 crx_downloader_->StartDownload(urls, callback_); 304 RunThreads(); 305 306 EXPECT_EQ(1, get_interceptor_->GetHitCount()); 307 308 EXPECT_EQ(1, num_download_complete_calls_); 309 EXPECT_EQ(kExpectedContext, crx_context_); 310 EXPECT_EQ(0, download_complete_result_.error); 311 EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); 312 EXPECT_EQ(1843, download_complete_result_.total_bytes); 313 EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); 314 315 EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); 316 317 EXPECT_LE(1, num_progress_calls_); 318 EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); 319 EXPECT_EQ(1843, download_progress_result_.total_bytes); 320 } 321 322 // Tests that the download succeeds if the first url is correct and the 323 // second bad url does not have a side-effect. 324 TEST_F(CrxDownloaderTest, TwoUrls_SecondInvalid) { 325 const GURL expected_crx_url = 326 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 327 328 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 329 get_interceptor_->SetResponse(expected_crx_url, test_file); 330 331 std::vector<GURL> urls; 332 urls.push_back(expected_crx_url); 333 urls.push_back(GURL("http://localhost/no/such/file")); 334 335 crx_downloader_->StartDownload(urls, callback_); 336 RunThreads(); 337 338 EXPECT_EQ(1, get_interceptor_->GetHitCount()); 339 340 EXPECT_EQ(1, num_download_complete_calls_); 341 EXPECT_EQ(kExpectedContext, crx_context_); 342 EXPECT_EQ(0, download_complete_result_.error); 343 EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); 344 EXPECT_EQ(1843, download_complete_result_.total_bytes); 345 EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); 346 347 EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); 348 349 EXPECT_LE(1, num_progress_calls_); 350 EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); 351 EXPECT_EQ(1843, download_progress_result_.total_bytes); 352 } 353 354 // Tests that the download fails if both urls are bad. 355 TEST_F(CrxDownloaderTest, TwoUrls_BothInvalid) { 356 const GURL expected_crx_url = 357 GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); 358 359 const base::FilePath test_file(MakeTestFilePath(kTestFileName)); 360 get_interceptor_->SetResponse(expected_crx_url, test_file); 361 362 std::vector<GURL> urls; 363 urls.push_back(GURL("http://localhost/no/such/file")); 364 urls.push_back(GURL("http://no.such.host/" 365 "/download/jebgalgnebhfojomionfpkfelancnnkf.crx")); 366 367 crx_downloader_->StartDownload(urls, callback_); 368 RunThreads(); 369 370 EXPECT_EQ(0, get_interceptor_->GetHitCount()); 371 372 EXPECT_EQ(1, num_download_complete_calls_); 373 EXPECT_EQ(kExpectedContext, crx_context_); 374 EXPECT_NE(0, download_complete_result_.error); 375 EXPECT_TRUE(download_complete_result_.response.empty()); 376 } 377 378 } // namespace component_updater 379