OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file contains download browser tests that are known to be runnable | 5 // This file contains download browser tests that are known to be runnable |
6 // in a pure content context. Over time tests should be migrated here. | 6 // in a pure content context. Over time tests should be migrated here. |
7 | 7 |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/scoped_temp_dir.h" | 10 #include "base/scoped_temp_dir.h" |
| 11 #include "content/browser/download/download_file_factory.h" |
| 12 #include "content/browser/download/download_file_impl.h" |
| 13 #include "content/browser/download/download_file_manager.h" |
11 #include "content/browser/download/download_item_impl.h" | 14 #include "content/browser/download/download_item_impl.h" |
12 #include "content/browser/download/download_manager_impl.h" | 15 #include "content/browser/download/download_manager_impl.h" |
| 16 #include "content/browser/power_save_blocker.h" |
| 17 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" |
13 #include "content/browser/web_contents/web_contents_impl.h" | 18 #include "content/browser/web_contents/web_contents_impl.h" |
14 #include "content/public/test/download_test_observer.h" | 19 #include "content/public/test/download_test_observer.h" |
| 20 #include "content/public/test/test_utils.h" |
15 #include "content/shell/shell.h" | 21 #include "content/shell/shell.h" |
16 #include "content/shell/shell_browser_context.h" | 22 #include "content/shell/shell_browser_context.h" |
17 #include "content/shell/shell_download_manager_delegate.h" | 23 #include "content/shell/shell_download_manager_delegate.h" |
18 #include "content/test/content_browser_test.h" | 24 #include "content/test/content_browser_test.h" |
19 #include "content/test/content_browser_test_utils.h" | 25 #include "content/test/content_browser_test_utils.h" |
20 #include "content/test/net/url_request_mock_http_job.h" | 26 #include "content/test/net/url_request_mock_http_job.h" |
21 #include "content/test/net/url_request_slow_download_job.h" | 27 #include "content/test/net/url_request_slow_download_job.h" |
22 #include "googleurl/src/gurl.h" | 28 #include "googleurl/src/gurl.h" |
23 | 29 |
24 namespace content { | 30 namespace content { |
25 | 31 |
26 namespace { | 32 namespace { |
27 | 33 |
28 static DownloadManager* DownloadManagerForShell(Shell* shell) { | 34 class DownloadFileWithDelayFactory; |
29 return BrowserContext::GetDownloadManager( | 35 |
30 shell->web_contents()->GetBrowserContext()); | 36 static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) { |
| 37 // We're in a content_browsertest; we know that the DownloadManager |
| 38 // is a DownloadManagerImpl. |
| 39 return static_cast<DownloadManagerImpl*>( |
| 40 BrowserContext::GetDownloadManager( |
| 41 shell->web_contents()->GetBrowserContext())); |
| 42 } |
| 43 |
| 44 class DownloadFileWithDelay : public DownloadFileImpl { |
| 45 public: |
| 46 DownloadFileWithDelay( |
| 47 const DownloadCreateInfo* info, |
| 48 scoped_ptr<content::ByteStreamReader> stream, |
| 49 DownloadRequestHandleInterface* request_handle, |
| 50 scoped_refptr<content::DownloadManager> download_manager, |
| 51 bool calculate_hash, |
| 52 scoped_ptr<content::PowerSaveBlocker> power_save_blocker, |
| 53 const net::BoundNetLog& bound_net_log, |
| 54 // |owner| is required to outlive the DownloadFileWithDelay. |
| 55 DownloadFileWithDelayFactory* owner); |
| 56 |
| 57 virtual ~DownloadFileWithDelay(); |
| 58 |
| 59 // Wraps DownloadFileImpl::Rename and intercepts the return callback, |
| 60 // storing it in the factory that produced this object for later |
| 61 // retrieval. |
| 62 virtual void Rename(const FilePath& full_path, |
| 63 bool overwrite_existing_file, |
| 64 const RenameCompletionCallback& callback) OVERRIDE; |
| 65 |
| 66 // Wraps DownloadFileImpl::Detach and intercepts the return callback, |
| 67 // storing it in the factory that produced this object for later |
| 68 // retrieval. |
| 69 virtual void Detach(base::Closure callback) OVERRIDE; |
| 70 |
| 71 private: |
| 72 static void RenameCallbackWrapper( |
| 73 DownloadFileWithDelayFactory* factory, |
| 74 const RenameCompletionCallback& original_callback, |
| 75 content::DownloadInterruptReason reason, |
| 76 const FilePath& path); |
| 77 |
| 78 static void DetachCallbackWrapper( |
| 79 DownloadFileWithDelayFactory* factory, |
| 80 const base::Closure& original_callback); |
| 81 |
| 82 // May only be used on the UI thread. |
| 83 DownloadFileWithDelayFactory* owner_; |
| 84 |
| 85 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay); |
| 86 }; |
| 87 |
| 88 class DownloadFileWithDelayFactory : public DownloadFileFactory { |
| 89 public: |
| 90 DownloadFileWithDelayFactory(); |
| 91 virtual ~DownloadFileWithDelayFactory(); |
| 92 |
| 93 // DownloadFileFactory interface. |
| 94 virtual content::DownloadFile* CreateFile( |
| 95 DownloadCreateInfo* info, |
| 96 scoped_ptr<content::ByteStreamReader> stream, |
| 97 DownloadManager* download_manager, |
| 98 bool calculate_hash, |
| 99 const net::BoundNetLog& bound_net_log) OVERRIDE; |
| 100 |
| 101 // Must all be called on the UI thread. |
| 102 void AddRenameCallback(base::Closure callback); |
| 103 void AddDetachCallback(base::Closure callback); |
| 104 void GetAllRenameCallbacks(std::vector<base::Closure>* results); |
| 105 void GetAllDetachCallbacks(std::vector<base::Closure>* results); |
| 106 |
| 107 // Do not return until either GetAllRenameCallbacks() or |
| 108 // GetAllDetachCallbacks() will return a non-empty list. |
| 109 void WaitForSomeCallback(); |
| 110 |
| 111 private: |
| 112 std::vector<base::Closure> rename_callbacks_; |
| 113 std::vector<base::Closure> detach_callbacks_; |
| 114 bool waiting_; |
| 115 |
| 116 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory); |
| 117 }; |
| 118 |
| 119 DownloadFileWithDelay::DownloadFileWithDelay( |
| 120 const DownloadCreateInfo* info, |
| 121 scoped_ptr<content::ByteStreamReader> stream, |
| 122 DownloadRequestHandleInterface* request_handle, |
| 123 scoped_refptr<content::DownloadManager> download_manager, |
| 124 bool calculate_hash, |
| 125 scoped_ptr<content::PowerSaveBlocker> power_save_blocker, |
| 126 const net::BoundNetLog& bound_net_log, |
| 127 DownloadFileWithDelayFactory* owner) |
| 128 : DownloadFileImpl(info, stream.Pass(), request_handle, download_manager, |
| 129 calculate_hash, power_save_blocker.Pass(), |
| 130 bound_net_log), |
| 131 owner_(owner) {} |
| 132 |
| 133 DownloadFileWithDelay::~DownloadFileWithDelay() {} |
| 134 |
| 135 void DownloadFileWithDelay::Rename(const FilePath& full_path, |
| 136 bool overwrite_existing_file, |
| 137 const RenameCompletionCallback& callback) { |
| 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 139 DownloadFileImpl::Rename( |
| 140 full_path, overwrite_existing_file, |
| 141 base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, |
| 142 base::Unretained(owner_), callback)); |
| 143 } |
| 144 |
| 145 void DownloadFileWithDelay::Detach(base::Closure callback) { |
| 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 147 DownloadFileImpl::Detach( |
| 148 base::Bind(DownloadFileWithDelay::DetachCallbackWrapper, |
| 149 base::Unretained(owner_), callback)); |
| 150 } |
| 151 |
| 152 // static |
| 153 void DownloadFileWithDelay::RenameCallbackWrapper( |
| 154 DownloadFileWithDelayFactory* factory, |
| 155 const RenameCompletionCallback& original_callback, |
| 156 content::DownloadInterruptReason reason, |
| 157 const FilePath& path) { |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 159 factory->AddRenameCallback(base::Bind(original_callback, reason, path)); |
| 160 } |
| 161 |
| 162 // static |
| 163 void DownloadFileWithDelay::DetachCallbackWrapper( |
| 164 DownloadFileWithDelayFactory* factory, |
| 165 const base::Closure& original_callback) { |
| 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 167 factory->AddDetachCallback(original_callback); |
| 168 } |
| 169 |
| 170 DownloadFileWithDelayFactory::DownloadFileWithDelayFactory() |
| 171 : waiting_(false) {} |
| 172 DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {} |
| 173 |
| 174 DownloadFile* DownloadFileWithDelayFactory::CreateFile( |
| 175 DownloadCreateInfo* info, |
| 176 scoped_ptr<content::ByteStreamReader> stream, |
| 177 DownloadManager* download_manager, |
| 178 bool calculate_hash, |
| 179 const net::BoundNetLog& bound_net_log) { |
| 180 |
| 181 return new DownloadFileWithDelay( |
| 182 info, stream.Pass(), new DownloadRequestHandle(info->request_handle), |
| 183 download_manager, calculate_hash, |
| 184 scoped_ptr<content::PowerSaveBlocker>( |
| 185 new content::PowerSaveBlocker( |
| 186 content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, |
| 187 "Download in progress")).Pass(), |
| 188 bound_net_log, this); |
| 189 } |
| 190 |
| 191 void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) { |
| 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 193 rename_callbacks_.push_back(callback); |
| 194 if (waiting_) |
| 195 MessageLoopForUI::current()->Quit(); |
| 196 } |
| 197 |
| 198 void DownloadFileWithDelayFactory::AddDetachCallback(base::Closure callback) { |
| 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 200 detach_callbacks_.push_back(callback); |
| 201 if (waiting_) |
| 202 MessageLoopForUI::current()->Quit(); |
| 203 } |
| 204 |
| 205 void DownloadFileWithDelayFactory::GetAllRenameCallbacks( |
| 206 std::vector<base::Closure>* results) { |
| 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 208 results->swap(rename_callbacks_); |
| 209 } |
| 210 |
| 211 void DownloadFileWithDelayFactory::GetAllDetachCallbacks( |
| 212 std::vector<base::Closure>* results) { |
| 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 214 results->swap(detach_callbacks_); |
| 215 } |
| 216 |
| 217 void DownloadFileWithDelayFactory::WaitForSomeCallback() { |
| 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 219 |
| 220 if (rename_callbacks_.empty() && detach_callbacks_.empty()) { |
| 221 waiting_ = true; |
| 222 RunMessageLoop(); |
| 223 waiting_ = false; |
| 224 } |
31 } | 225 } |
32 | 226 |
33 } // namespace | 227 } // namespace |
34 | 228 |
35 class DownloadContentTest : public ContentBrowserTest { | 229 class DownloadContentTest : public ContentBrowserTest { |
36 protected: | 230 protected: |
37 virtual void SetUpOnMainThread() OVERRIDE { | 231 virtual void SetUpOnMainThread() OVERRIDE { |
38 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); | 232 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); |
39 | 233 |
40 ShellDownloadManagerDelegate* delegate = | 234 ShellDownloadManagerDelegate* delegate = |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 return false; | 301 return false; |
108 | 302 |
109 // Check the contents. | 303 // Check the contents. |
110 EXPECT_EQ(value, file_contents); | 304 EXPECT_EQ(value, file_contents); |
111 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) | 305 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) |
112 return false; | 306 return false; |
113 | 307 |
114 return true; | 308 return true; |
115 } | 309 } |
116 | 310 |
| 311 DownloadFileManager* GetDownloadFileManager() { |
| 312 ResourceDispatcherHostImpl* rdh(ResourceDispatcherHostImpl::Get()); |
| 313 return rdh->download_file_manager(); |
| 314 } |
| 315 |
117 private: | 316 private: |
118 static void EnsureNoPendingDownloadJobsOnIO(bool* result) { | 317 static void EnsureNoPendingDownloadJobsOnIO(bool* result) { |
119 if (URLRequestSlowDownloadJob::NumberOutstandingRequests()) | 318 if (URLRequestSlowDownloadJob::NumberOutstandingRequests()) |
120 *result = false; | 319 *result = false; |
121 BrowserThread::PostTask( | 320 BrowserThread::PostTask( |
122 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure()); | 321 BrowserThread::UI, FROM_HERE, MessageLoop::QuitClosure()); |
123 } | 322 } |
124 | 323 |
125 // Location of the downloads directory for these tests | 324 // Location of the downloads directory for these tests |
126 ScopedTempDir downloads_directory_; | 325 ScopedTempDir downloads_directory_; |
127 }; | 326 }; |
128 | 327 |
129 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) { | 328 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) { |
130 // TODO(rdsmith): Fragile code warning! The code below relies on the | 329 // TODO(rdsmith): Fragile code warning! The code below relies on |
131 // DownloadTestObserverInProgress only finishing when the new download | 330 // the DownloadTestObserverInProgress only finishing when the new |
132 // has reached the state of being entered into the history and being | 331 // download has reached the state of being entered into the history |
133 // user-visible (that's what's required for the Remove to be valid and | 332 // and being user-visible (that's what's required for the Remove to |
134 // for the download shelf to be visible). By the pure semantics of | 333 // be valid). By the pure semantics of |
135 // DownloadTestObserverInProgress, that's not guaranteed; DownloadItems | 334 // DownloadTestObserverInProgress, that's not guaranteed; |
136 // are created in the IN_PROGRESS state and made known to the DownloadManager | 335 // DownloadItems are created in the IN_PROGRESS state and made known |
137 // immediately, so any ModelChanged event on the DownloadManager after | 336 // to the DownloadManager immediately, so any ModelChanged event on |
138 // navigation would allow the observer to return. However, the only | 337 // the DownloadManager after navigation would allow the observer to |
139 // ModelChanged() event the code will currently fire is in | 338 // return. However, the only ModelChanged() event the code will |
140 // OnCreateDownloadEntryComplete, at which point the download item will | 339 // currently fire is in OnCreateDownloadEntryComplete, at which |
141 // be in the state we need. | 340 // point the download item will be in the state we need. |
142 // The right way to fix this is to create finer grained states on the | 341 // The right way to fix this is to create finer grained states on the |
143 // DownloadItem, and wait for the state that indicates the item has been | 342 // DownloadItem, and wait for the state that indicates the item has been |
144 // entered in the history and made visible in the UI. | 343 // entered in the history and made visible in the UI. |
145 | 344 |
146 // Create a download, wait until it's started, and confirm | 345 // Create a download, wait until it's started, and confirm |
147 // we're in the expected state. | 346 // we're in the expected state. |
148 scoped_ptr<DownloadTestObserver> observer(CreateInProgressWaiter(shell(), 1)); | 347 scoped_ptr<DownloadTestObserver> observer(CreateInProgressWaiter(shell(), 1)); |
149 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); | 348 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); |
150 observer->WaitForFinished(); | 349 observer->WaitForFinished(); |
151 | 350 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize + | 412 size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize + |
214 URLRequestSlowDownloadJob::kSecondDownloadSize; | 413 URLRequestSlowDownloadJob::kSecondDownloadSize; |
215 std::string expected_contents(file_size1, '*'); | 414 std::string expected_contents(file_size1, '*'); |
216 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1)); | 415 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1)); |
217 | 416 |
218 FilePath file2(download2->GetFullPath()); | 417 FilePath file2(download2->GetFullPath()); |
219 ASSERT_TRUE(file_util::ContentsEqual( | 418 ASSERT_TRUE(file_util::ContentsEqual( |
220 file2, GetTestFilePath("download", "download-test.lib"))); | 419 file2, GetTestFilePath("download", "download-test.lib"))); |
221 } | 420 } |
222 | 421 |
| 422 // Try to cancel just before we release the download file, by delaying final |
| 423 // rename callback. |
| 424 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) { |
| 425 // Setup new factory. |
| 426 DownloadFileWithDelayFactory* file_factory = |
| 427 new DownloadFileWithDelayFactory(); |
| 428 GetDownloadFileManager()->SetFileFactoryForTesting( |
| 429 scoped_ptr<content::DownloadFileFactory>(file_factory).Pass()); |
| 430 |
| 431 // Create a download |
| 432 FilePath file(FILE_PATH_LITERAL("download-test.lib")); |
| 433 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); |
| 434 |
| 435 // Wait until the first (intermediate file) rename and execute the callback. |
| 436 file_factory->WaitForSomeCallback(); |
| 437 std::vector<base::Closure> callbacks; |
| 438 file_factory->GetAllDetachCallbacks(&callbacks); |
| 439 ASSERT_TRUE(callbacks.empty()); |
| 440 file_factory->GetAllRenameCallbacks(&callbacks); |
| 441 ASSERT_EQ(1u, callbacks.size()); |
| 442 callbacks[0].Run(); |
| 443 callbacks.clear(); |
| 444 |
| 445 // Wait until the second (final) rename callback is posted. |
| 446 file_factory->WaitForSomeCallback(); |
| 447 file_factory->GetAllDetachCallbacks(&callbacks); |
| 448 ASSERT_TRUE(callbacks.empty()); |
| 449 file_factory->GetAllRenameCallbacks(&callbacks); |
| 450 ASSERT_EQ(1u, callbacks.size()); |
| 451 |
| 452 // Cancel it. |
| 453 std::vector<DownloadItem*> items; |
| 454 DownloadManagerForShell(shell())->GetAllDownloads(&items); |
| 455 ASSERT_EQ(1u, items.size()); |
| 456 items[0]->Cancel(true); |
| 457 RunAllPendingInMessageLoop(); |
| 458 |
| 459 // Check state. |
| 460 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); |
| 461 |
| 462 // Run final rename callback. |
| 463 callbacks[0].Run(); |
| 464 callbacks.clear(); |
| 465 |
| 466 // Check state. |
| 467 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); |
| 468 } |
| 469 |
| 470 // Try to cancel just after we release the download file, by delaying |
| 471 // release. |
| 472 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) { |
| 473 // Setup new factory. |
| 474 // Setup new factory. |
| 475 DownloadFileWithDelayFactory* file_factory = |
| 476 new DownloadFileWithDelayFactory(); |
| 477 GetDownloadFileManager()->SetFileFactoryForTesting( |
| 478 scoped_ptr<content::DownloadFileFactory>(file_factory).Pass()); |
| 479 |
| 480 // Create a download |
| 481 FilePath file(FILE_PATH_LITERAL("download-test.lib")); |
| 482 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); |
| 483 |
| 484 // Wait until the first (intermediate file) rename and execute the callback. |
| 485 file_factory->WaitForSomeCallback(); |
| 486 std::vector<base::Closure> callbacks; |
| 487 file_factory->GetAllDetachCallbacks(&callbacks); |
| 488 ASSERT_TRUE(callbacks.empty()); |
| 489 file_factory->GetAllRenameCallbacks(&callbacks); |
| 490 ASSERT_EQ(1u, callbacks.size()); |
| 491 callbacks[0].Run(); |
| 492 callbacks.clear(); |
| 493 |
| 494 // Wait until the second (final) rename callback is posted. |
| 495 file_factory->WaitForSomeCallback(); |
| 496 file_factory->GetAllDetachCallbacks(&callbacks); |
| 497 ASSERT_TRUE(callbacks.empty()); |
| 498 file_factory->GetAllRenameCallbacks(&callbacks); |
| 499 ASSERT_EQ(1u, callbacks.size()); |
| 500 |
| 501 // Call it. |
| 502 callbacks[0].Run(); |
| 503 callbacks.clear(); |
| 504 |
| 505 // Confirm download isn't complete yet. |
| 506 std::vector<DownloadItem*> items; |
| 507 DownloadManagerForShell(shell())->GetAllDownloads(&items); |
| 508 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); |
| 509 |
| 510 // Cancel the download; confirm cancel fails anyway. |
| 511 ASSERT_EQ(1u, items.size()); |
| 512 items[0]->Cancel(true); |
| 513 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); |
| 514 RunAllPendingInMessageLoop(); |
| 515 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); |
| 516 |
| 517 // Confirm detach callback and run it. |
| 518 file_factory->WaitForSomeCallback(); |
| 519 file_factory->GetAllRenameCallbacks(&callbacks); |
| 520 ASSERT_TRUE(callbacks.empty()); |
| 521 file_factory->GetAllDetachCallbacks(&callbacks); |
| 522 ASSERT_EQ(1u, callbacks.size()); |
| 523 callbacks[0].Run(); |
| 524 callbacks.clear(); |
| 525 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); |
| 526 } |
| 527 |
223 } // namespace content | 528 } // namespace content |
OLD | NEW |