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" | |
11 #include "content/browser/download/download_item_impl.h" | 13 #include "content/browser/download/download_item_impl.h" |
12 #include "content/browser/download/download_manager_impl.h" | 14 #include "content/browser/download/download_manager_impl.h" |
15 #include "content/browser/power_save_blocker.h" | |
13 #include "content/browser/web_contents/web_contents_impl.h" | 16 #include "content/browser/web_contents/web_contents_impl.h" |
14 #include "content/public/test/download_test_observer.h" | 17 #include "content/public/test/download_test_observer.h" |
18 #include "content/public/test/test_utils.h" | |
15 #include "content/shell/shell.h" | 19 #include "content/shell/shell.h" |
16 #include "content/shell/shell_browser_context.h" | 20 #include "content/shell/shell_browser_context.h" |
17 #include "content/shell/shell_download_manager_delegate.h" | 21 #include "content/shell/shell_download_manager_delegate.h" |
18 #include "content/test/content_browser_test.h" | 22 #include "content/test/content_browser_test.h" |
19 #include "content/test/content_browser_test_utils.h" | 23 #include "content/test/content_browser_test_utils.h" |
20 #include "content/test/net/url_request_mock_http_job.h" | 24 #include "content/test/net/url_request_mock_http_job.h" |
21 #include "content/test/net/url_request_slow_download_job.h" | 25 #include "content/test/net/url_request_slow_download_job.h" |
22 #include "googleurl/src/gurl.h" | 26 #include "googleurl/src/gurl.h" |
23 | 27 |
24 namespace content { | 28 namespace content { |
25 | 29 |
26 namespace { | 30 namespace { |
27 | 31 |
28 static DownloadManager* DownloadManagerForShell(Shell* shell) { | 32 class DownloadFileWithDelayFactory; |
29 return BrowserContext::GetDownloadManager( | 33 |
30 shell->web_contents()->GetBrowserContext()); | 34 static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) { |
35 // We're in a content_browsertest; we know that the DownloadManager | |
36 // is a DownloadManagerImpl. | |
37 return static_cast<DownloadManagerImpl*>( | |
38 BrowserContext::GetDownloadManager( | |
39 shell->web_contents()->GetBrowserContext())); | |
40 } | |
41 | |
42 class DownloadFileWithDelay : public DownloadFileImpl { | |
43 public: | |
44 DownloadFileWithDelay( | |
45 const content::DownloadSaveInfo& save_info, | |
46 const GURL& url, | |
47 const GURL& referrer_url, | |
48 int64 received_bytes, | |
49 bool calculate_hash, | |
50 scoped_ptr<content::ByteStreamReader> stream, | |
51 const net::BoundNetLog& bound_net_log, | |
52 scoped_ptr<content::PowerSaveBlocker> power_save_blocker, | |
53 base::WeakPtr<content::DownloadDestinationObserver> observer, | |
54 base::WeakPtr<DownloadFileWithDelayFactory> owner); | |
55 | |
benjhayden
2012/09/12 21:01:01
Don't you need a virtual destructor?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
56 // Wraps DownloadFileImpl::Rename and intercepts the return callback, | |
57 // storing it in the factory that produced this object for later | |
58 // retrieval. | |
59 virtual void Rename(const FilePath& full_path, | |
60 bool overwrite_existing_file, | |
61 const RenameCompletionCallback& callback) OVERRIDE; | |
62 | |
63 // Wraps DownloadFileImpl::Detach and intercepts the return callback, | |
64 // storing it in the factory that produced this object for later | |
benjhayden
2012/09/12 21:01:01
double space
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
65 // retrieval. | |
66 virtual void Detach(base::Closure callback) OVERRIDE; | |
67 | |
68 private: | |
69 // Must be called on the UI thread. | |
70 static void RenameCallbackWrapper( | |
71 DownloadFileWithDelayFactory* factory, | |
72 const RenameCompletionCallback& original_callback, | |
73 content::DownloadInterruptReason reason, | |
74 const FilePath& path); | |
75 | |
76 // Must be called on the UI thread. | |
benjhayden
2012/09/12 21:01:01
Instead of these comments, can you just have the D
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
I don't consider the two equivalent; one's interfa
| |
77 static void DetachCallbackWrapper( | |
78 DownloadFileWithDelayFactory* factory, | |
79 const base::Closure& original_callback); | |
80 | |
81 // Must only be accessed on the FILE thread; must be used only on the | |
benjhayden
2012/09/12 21:01:01
What's the difference between access and use?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
The variable must be read on the FILE thread, and
| |
82 // UI thread. (This object lives on the file thread, and the | |
83 // DownloadFileWithDelayFactory lives on the UI thread). | |
84 base::WeakPtr<DownloadFileWithDelayFactory> owner_; | |
85 }; | |
86 | |
87 // All routines on this class must be called on the UI thread. | |
88 class DownloadFileWithDelayFactory : public DownloadFileFactory { | |
89 public: | |
90 DownloadFileWithDelayFactory(); | |
91 virtual ~DownloadFileWithDelayFactory(); | |
92 | |
93 // DownloadFileFactory interface. | |
94 virtual DownloadFile* CreateFile( | |
95 const content::DownloadSaveInfo& save_info, | |
96 GURL url, | |
97 GURL referrer_url, | |
98 int64 received_bytes, | |
99 bool calculate_hash, | |
100 scoped_ptr<content::ByteStreamReader> stream, | |
101 const net::BoundNetLog& bound_net_log, | |
102 base::WeakPtr<content::DownloadDestinationObserver> observer) OVERRIDE; | |
103 | |
104 void PostRenameCallback(base::Closure callback); | |
benjhayden
2012/09/12 21:01:01
s/Post/Add/g ?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
105 void PostDetachCallback(base::Closure callback); | |
106 void GetRenameCallbacks(std::vector<base::Closure>* results); | |
benjhayden
2012/09/12 21:01:01
s/Get/GetAll/g ?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
107 void GetDetachCallbacks(std::vector<base::Closure>* results); | |
108 | |
109 // Do not return until either GetRenameCallbacks() or GetDetachCallbacks() | |
110 // will return a non-empty list. | |
111 void WaitForSomeCallback(); | |
112 | |
113 private: | |
114 base::WeakPtrFactory<DownloadFileWithDelayFactory> factory_; | |
benjhayden
2012/09/12 21:01:01
weak_ptr_factor_?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
115 std::vector<base::Closure> rename_callbacks_; | |
116 std::vector<base::Closure> detach_callbacks_; | |
117 bool waiting_; | |
118 }; | |
benjhayden
2012/09/12 21:01:01
DISALLOW_COPY_AND_ASSIGN?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Done.
| |
119 | |
120 DownloadFileWithDelay::DownloadFileWithDelay( | |
benjhayden
2012/09/12 21:01:01
Since we're in a test, would you mind defining the
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
I started out doing that. The problem is that the
| |
121 const content::DownloadSaveInfo& save_info, | |
122 const GURL& url, | |
123 const GURL& referrer_url, | |
124 int64 received_bytes, | |
125 bool calculate_hash, | |
126 scoped_ptr<content::ByteStreamReader> stream, | |
127 const net::BoundNetLog& bound_net_log, | |
128 scoped_ptr<content::PowerSaveBlocker> power_save_blocker, | |
129 base::WeakPtr<content::DownloadDestinationObserver> observer, | |
130 base::WeakPtr<DownloadFileWithDelayFactory> owner) | |
131 : DownloadFileImpl( | |
132 save_info, url, referrer_url, received_bytes, calculate_hash, | |
133 stream.Pass(), bound_net_log, power_save_blocker.Pass(), | |
134 observer), | |
135 owner_(owner) {} | |
136 | |
137 void DownloadFileWithDelay::Rename(const FilePath& full_path, | |
138 bool overwrite_existing_file, | |
139 const RenameCompletionCallback& callback) { | |
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
141 DownloadFileImpl::Rename( | |
142 full_path, overwrite_existing_file, | |
143 base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, | |
144 owner_, callback)); | |
145 } | |
146 | |
147 void DownloadFileWithDelay::Detach(base::Closure callback) { | |
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
149 DownloadFileImpl::Detach( | |
150 base::Bind(DownloadFileWithDelay::DetachCallbackWrapper, | |
151 owner_, callback)); | |
152 } | |
153 | |
154 // static | |
155 void DownloadFileWithDelay::RenameCallbackWrapper( | |
156 DownloadFileWithDelayFactory* factory, | |
157 const RenameCompletionCallback& original_callback, | |
158 content::DownloadInterruptReason reason, | |
159 const FilePath& path) { | |
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
161 factory->PostRenameCallback(base::Bind(original_callback, reason, path)); | |
162 } | |
163 | |
164 // static | |
165 void DownloadFileWithDelay::DetachCallbackWrapper( | |
166 DownloadFileWithDelayFactory* factory, | |
167 const base::Closure& original_callback) { | |
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
169 factory->PostDetachCallback(original_callback); | |
170 } | |
171 | |
172 DownloadFileWithDelayFactory::DownloadFileWithDelayFactory() | |
173 : factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | |
174 waiting_(false) {} | |
175 DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {} | |
176 | |
177 DownloadFile* DownloadFileWithDelayFactory::CreateFile( | |
178 const content::DownloadSaveInfo& save_info, | |
179 GURL url, | |
180 GURL referrer_url, | |
181 int64 received_bytes, | |
182 bool calculate_hash, | |
183 scoped_ptr<content::ByteStreamReader> stream, | |
184 const net::BoundNetLog& bound_net_log, | |
185 base::WeakPtr<content::DownloadDestinationObserver> observer) { | |
186 scoped_ptr<content::PowerSaveBlocker> psb( | |
187 new content::PowerSaveBlocker( | |
188 content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, | |
189 "Download in progress")); | |
190 return new DownloadFileWithDelay( | |
191 save_info, url, referrer_url, received_bytes, calculate_hash, | |
192 stream.Pass(), bound_net_log, psb.Pass(), observer, | |
193 factory_.GetWeakPtr()); | |
194 } | |
195 | |
196 void DownloadFileWithDelayFactory::PostRenameCallback(base::Closure callback) { | |
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
198 rename_callbacks_.push_back(callback); | |
199 if (waiting_) | |
200 MessageLoopForUI::current()->Quit(); | |
201 } | |
202 | |
203 void DownloadFileWithDelayFactory::PostDetachCallback(base::Closure callback) { | |
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
205 detach_callbacks_.push_back(callback); | |
206 if (waiting_) | |
207 MessageLoopForUI::current()->Quit(); | |
208 } | |
209 | |
210 void DownloadFileWithDelayFactory::GetRenameCallbacks( | |
211 std::vector<base::Closure>* results) { | |
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
213 results->swap(rename_callbacks_); | |
214 } | |
215 | |
216 void DownloadFileWithDelayFactory::GetDetachCallbacks( | |
217 std::vector<base::Closure>* results) { | |
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
219 results->swap(detach_callbacks_); | |
220 } | |
221 | |
222 void DownloadFileWithDelayFactory::WaitForSomeCallback() { | |
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
224 | |
225 while (rename_callbacks_.empty() && detach_callbacks_.empty()) { | |
benjhayden
2012/09/12 21:01:01
'while' or 'if'?
Randy Smith (Not in Mondays)
2012/09/13 20:15:12
Presuming comment means you prefer 'if'; done.
(T
| |
226 waiting_ = true; | |
227 RunMessageLoop(); | |
228 waiting_ = false; | |
229 } | |
31 } | 230 } |
32 | 231 |
33 } // namespace | 232 } // namespace |
34 | 233 |
35 class DownloadContentTest : public ContentBrowserTest { | 234 class DownloadContentTest : public ContentBrowserTest { |
36 protected: | 235 protected: |
37 virtual void SetUpOnMainThread() OVERRIDE { | 236 virtual void SetUpOnMainThread() OVERRIDE { |
38 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); | 237 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); |
39 | 238 |
40 ShellDownloadManagerDelegate* delegate = | 239 ShellDownloadManagerDelegate* delegate = |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); | |
429 download_manager->SetDownloadFileFactoryForTesting( | |
430 scoped_ptr<content::DownloadFileFactory>(file_factory).Pass()); | |
431 | |
432 // Create a download | |
433 FilePath file(FILE_PATH_LITERAL("download-test.lib")); | |
434 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); | |
435 | |
436 // Wait until the first (intermediate file) rename and execute the callback. | |
437 file_factory->WaitForSomeCallback(); | |
438 std::vector<base::Closure> callbacks; | |
439 file_factory->GetDetachCallbacks(&callbacks); | |
440 ASSERT_TRUE(callbacks.empty()); | |
441 file_factory->GetRenameCallbacks(&callbacks); | |
442 ASSERT_EQ(1u, callbacks.size()); | |
443 callbacks[0].Run(); | |
444 callbacks.clear(); | |
445 | |
446 // Wait until the second (final) rename callback is posted. | |
447 file_factory->WaitForSomeCallback(); | |
448 file_factory->GetDetachCallbacks(&callbacks); | |
449 ASSERT_TRUE(callbacks.empty()); | |
450 file_factory->GetRenameCallbacks(&callbacks); | |
451 ASSERT_EQ(1u, callbacks.size()); | |
452 | |
453 // Cancel it. | |
454 std::vector<DownloadItem*> items; | |
455 download_manager->GetAllDownloads(&items); | |
456 ASSERT_EQ(1u, items.size()); | |
457 items[0]->Cancel(true); | |
458 RunAllPendingInMessageLoop(); | |
459 | |
460 // Check state. | |
461 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); | |
462 | |
463 // Run final rename callback. | |
464 callbacks[0].Run(); | |
465 callbacks.clear(); | |
466 | |
467 // Check state. | |
468 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); | |
469 } | |
470 | |
471 // Try to cancel just after we release the download file, by delaying | |
472 // release. | |
473 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) { | |
474 // Setup new factory. | |
475 DownloadFileWithDelayFactory* file_factory = | |
476 new DownloadFileWithDelayFactory(); | |
477 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); | |
478 download_manager->SetDownloadFileFactoryForTesting( | |
479 scoped_ptr<content::DownloadFileFactory>(file_factory).Pass()); | |
480 | |
481 // Create a download | |
482 FilePath file(FILE_PATH_LITERAL("download-test.lib")); | |
483 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); | |
484 | |
485 // Wait until the first (intermediate file) rename and execute the callback. | |
486 file_factory->WaitForSomeCallback(); | |
487 std::vector<base::Closure> callbacks; | |
488 file_factory->GetDetachCallbacks(&callbacks); | |
489 ASSERT_TRUE(callbacks.empty()); | |
490 file_factory->GetRenameCallbacks(&callbacks); | |
491 ASSERT_EQ(1u, callbacks.size()); | |
492 callbacks[0].Run(); | |
493 callbacks.clear(); | |
494 | |
495 // Wait until the second (final) rename callback is posted. | |
496 file_factory->WaitForSomeCallback(); | |
497 file_factory->GetDetachCallbacks(&callbacks); | |
498 ASSERT_TRUE(callbacks.empty()); | |
499 file_factory->GetRenameCallbacks(&callbacks); | |
500 ASSERT_EQ(1u, callbacks.size()); | |
501 | |
502 // Call it. | |
503 callbacks[0].Run(); | |
504 callbacks.clear(); | |
505 | |
506 // Confirm download now complete. | |
507 std::vector<DownloadItem*> items; | |
508 download_manager->GetAllDownloads(&items); | |
509 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); | |
510 | |
511 // Cancel the download; confirm cancel fails. | |
512 ASSERT_EQ(1u, items.size()); | |
513 items[0]->Cancel(true); | |
514 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); | |
515 RunAllPendingInMessageLoop(); | |
516 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); | |
517 | |
518 // Confirm detach callback and run it. | |
519 file_factory->WaitForSomeCallback(); | |
520 file_factory->GetRenameCallbacks(&callbacks); | |
521 ASSERT_TRUE(callbacks.empty()); | |
522 file_factory->GetDetachCallbacks(&callbacks); | |
523 ASSERT_EQ(1u, callbacks.size()); | |
524 callbacks[0].Run(); | |
525 callbacks.clear(); | |
526 } | |
527 | |
223 } // namespace content | 528 } // namespace content |
OLD | NEW |