Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(811)

Side by Side Diff: content/browser/download/download_browsertest.cc

Issue 10912173: Replace the DownloadFileManager with direct ownership of DownloadFileImpl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync to LKGR (r156083) Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698