OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
Sami
2017/06/05 16:50:31
Year += 5 and remove the (c)
Oleg Sushkov
2017/06/06 03:36:54
done
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
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. | |
Sami
2017/06/05 16:50:32
Not sure what "pure content context" means here? T
Oleg Sushkov
2017/06/06 03:36:54
deleted, disregard this is from the originating fi
| |
7 | |
8 #include <stddef.h> | |
9 #include <stdint.h> | |
10 #include <utility> | |
11 | |
12 #include "base/callback_helpers.h" | |
13 #include "base/files/file_path.h" | |
14 #include "base/files/file_util.h" | |
15 #include "base/files/scoped_temp_dir.h" | |
16 #include "base/macros.h" | |
17 #include "base/memory/ref_counted.h" | |
18 #include "base/message_loop/message_loop.h" | |
19 #include "base/threading/platform_thread.h" | |
20 #include "base/threading/sequenced_worker_pool.h" | |
21 #include "base/threading/thread_restrictions.h" | |
22 #include "content/browser/byte_stream.h" | |
23 #include "content/browser/download/download_file_factory.h" | |
24 #include "content/browser/download/download_file_impl.h" | |
25 #include "content/browser/download/download_item_impl.h" | |
26 #include "content/browser/download/download_manager_impl.h" | |
27 #include "content/browser/web_contents/web_contents_impl.h" | |
28 #include "content/public/test/browser_test_utils.h" | |
29 #include "content/public/test/content_browser_test.h" | |
30 #include "content/public/test/content_browser_test_utils.h" | |
31 #include "content/public/test/download_test_observer.h" | |
32 #include "content/public/test/test_utils.h" | |
33 #include "headless/lib/browser/headless_browser_context_impl.h" | |
34 #include "headless/lib/browser/headless_download_manager_delegate.h" | |
35 #include "headless/public/headless_browser.h" | |
36 #include "headless/test/headless_browser_test.h" | |
37 #include "net/dns/mock_host_resolver.h" | |
Sami
2017/06/05 16:50:31
Unused?
Oleg Sushkov
2017/06/06 03:36:54
its used: host_resolver()->AddRule(kOriginOne, rea
| |
38 #include "net/test/embedded_test_server/embedded_test_server.h" | |
39 #include "net/test/embedded_test_server/http_request.h" | |
40 #include "net/test/embedded_test_server/http_response.h" | |
41 #include "net/test/url_request/url_request_mock_http_job.h" | |
42 #include "net/test/url_request/url_request_slow_download_job.h" | |
43 #include "testing/gmock/include/gmock/gmock.h" | |
44 #include "testing/gtest/include/gtest/gtest.h" | |
45 #include "url/gurl.h" | |
46 | |
47 using namespace content; | |
48 | |
49 namespace net { | |
50 class NetLogWithSource; | |
51 } | |
52 | |
53 namespace headless { | |
54 | |
55 namespace { | |
56 | |
57 const std::string kOriginOne = "one.example"; | |
58 const std::string kOriginTwo = "two.example"; | |
59 | |
60 static DownloadManagerImpl* DownloadManagerForBrowser( | |
Sami
2017/06/05 16:50:32
nit: no use for |static| since this is an anonymou
Oleg Sushkov
2017/06/06 03:36:54
done
| |
61 HeadlessBrowser* browser) { | |
62 // We're in a content_browsertest; we know that the DownloadManager | |
63 // is a DownloadManagerImpl. | |
64 HeadlessBrowserContextImpl* ctx = | |
65 HeadlessBrowserContextImpl::From(browser->GetDefaultBrowserContext()); | |
66 | |
67 return static_cast<DownloadManagerImpl*>( | |
68 BrowserContext::GetDownloadManager(ctx)); | |
69 } | |
70 | |
71 class CountingDownloadFile : public DownloadFileImpl { | |
72 public: | |
73 CountingDownloadFile(std::unique_ptr<DownloadSaveInfo> save_info, | |
74 const base::FilePath& default_downloads_directory, | |
75 std::unique_ptr<ByteStreamReader> stream, | |
76 const net::NetLogWithSource& net_log, | |
77 base::WeakPtr<DownloadDestinationObserver> observer) | |
78 : DownloadFileImpl(std::move(save_info), | |
79 default_downloads_directory, | |
80 std::move(stream), | |
81 net_log, | |
82 observer) {} | |
83 | |
84 ~CountingDownloadFile() override { | |
85 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
86 active_files_--; | |
87 } | |
88 | |
89 void Initialize(const InitializeCallback& callback, | |
90 const CancelRequestCallback& cancel_request_callback, | |
91 const DownloadItem::ReceivedSlices& received_slices, | |
92 bool is_parallelizable) override { | |
93 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
94 active_files_++; | |
95 DownloadFileImpl::Initialize(callback, cancel_request_callback, | |
96 received_slices, is_parallelizable); | |
97 } | |
98 | |
99 static void GetNumberActiveFiles(int* result) { | |
100 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
101 *result = active_files_; | |
102 } | |
103 | |
104 // Can be called on any thread, and will block (running message loop) | |
105 // until data is returned. | |
106 static int GetNumberActiveFilesFromFileThread() { | |
107 int result = -1; | |
108 BrowserThread::PostTaskAndReply( | |
109 BrowserThread::FILE, FROM_HERE, | |
110 base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result), | |
111 base::MessageLoop::current()->QuitWhenIdleClosure()); | |
112 base::RunLoop().Run(); | |
113 DCHECK_NE(-1, result); | |
114 return result; | |
115 } | |
116 | |
117 private: | |
118 static int active_files_; | |
119 }; | |
120 | |
121 int CountingDownloadFile::active_files_ = 0; | |
122 | |
123 class CountingDownloadFileFactory : public DownloadFileFactory { | |
124 public: | |
125 CountingDownloadFileFactory() {} | |
126 ~CountingDownloadFileFactory() override {} | |
127 | |
128 // DownloadFileFactory interface. | |
129 DownloadFile* CreateFile( | |
130 std::unique_ptr<DownloadSaveInfo> save_info, | |
131 const base::FilePath& default_downloads_directory, | |
132 std::unique_ptr<ByteStreamReader> stream, | |
133 const net::NetLogWithSource& net_log, | |
134 base::WeakPtr<DownloadDestinationObserver> observer) override { | |
135 return new CountingDownloadFile(std::move(save_info), | |
136 default_downloads_directory, | |
137 std::move(stream), net_log, observer); | |
138 } | |
139 }; | |
140 | |
141 // Get the next created download. | |
142 class DownloadCreateObserver : DownloadManager::Observer { | |
143 public: | |
144 DownloadCreateObserver(DownloadManager* manager) | |
145 : manager_(manager), item_(NULL) { | |
Sami
2017/06/05 16:50:31
nit: NULL is so C++98, let's go with nullptr
Oleg Sushkov
2017/06/06 03:36:54
done, wart from originating file.
| |
146 manager_->AddObserver(this); | |
147 } | |
148 | |
149 ~DownloadCreateObserver() override { | |
150 if (manager_) | |
151 manager_->RemoveObserver(this); | |
152 manager_ = NULL; | |
153 } | |
154 | |
155 void ManagerGoingDown(DownloadManager* manager) override { | |
156 DCHECK_EQ(manager_, manager); | |
157 manager_->RemoveObserver(this); | |
158 manager_ = NULL; | |
159 } | |
160 | |
161 void OnDownloadCreated(DownloadManager* manager, | |
162 DownloadItem* download) override { | |
163 if (!item_) | |
164 item_ = download; | |
165 | |
166 if (!completion_closure_.is_null()) | |
167 base::ResetAndReturn(&completion_closure_).Run(); | |
168 } | |
169 | |
170 DownloadItem* WaitForFinished() { | |
171 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
172 if (!item_) { | |
173 base::RunLoop run_loop; | |
174 completion_closure_ = run_loop.QuitClosure(); | |
175 run_loop.Run(); | |
176 } | |
177 return item_; | |
178 } | |
179 | |
180 private: | |
181 DownloadManager* manager_; | |
182 DownloadItem* item_; | |
183 base::Closure completion_closure_; | |
184 }; | |
185 | |
186 bool IsDownloadInState(DownloadItem::DownloadState state, DownloadItem* item) { | |
187 return item->GetState() == state; | |
188 } | |
189 | |
190 class HeadlessDownloadContentTest : public HeadlessBrowserTest { | |
191 protected: | |
192 void SetUpOnMainThread() override { | |
193 base::ThreadRestrictions::SetIOAllowed(true); | |
194 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); | |
195 | |
196 headless::HeadlessBrowserContext::Builder context_builder = | |
197 browser()->CreateBrowserContextBuilder(); | |
198 headless::HeadlessBrowserContext* browser_context = context_builder.Build(); | |
199 browser()->SetDefaultBrowserContext(browser_context); | |
200 | |
201 test_delegate_.reset(new HeadlessDownloadManagerDelegate()); | |
202 test_delegate_->SetDownloadBehaviorForTesting( | |
203 downloads_directory_.GetPath()); | |
204 DownloadManager* manager = DownloadManagerForBrowser(browser()); | |
205 manager->GetDelegate()->Shutdown(); | |
206 manager->SetDelegate(test_delegate_.get()); | |
207 test_delegate_->SetDownloadManager(manager); | |
208 | |
209 BrowserThread::PostTask( | |
210 BrowserThread::IO, FROM_HERE, | |
211 base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler)); | |
212 base::FilePath mock_base(GetTestFilePath("download", "")); | |
213 BrowserThread::PostTask( | |
214 BrowserThread::IO, FROM_HERE, | |
215 base::Bind( | |
216 &net::URLRequestMockHTTPJob::AddUrlHandlers, mock_base, | |
217 make_scoped_refptr(content::BrowserThread::GetBlockingPool()))); | |
218 ASSERT_TRUE(embedded_test_server()->Start()); | |
219 const std::string real_host = | |
220 embedded_test_server()->host_port_pair().host(); | |
221 host_resolver()->AddRule(kOriginOne, real_host); | |
222 host_resolver()->AddRule(kOriginTwo, real_host); | |
223 } | |
224 | |
225 // Create a DownloadTestObserverTerminal that will wait for the | |
226 // specified number of downloads to finish. | |
227 DownloadTestObserver* CreateWaiter(HeadlessBrowser* browser, | |
228 int num_downloads) { | |
229 DownloadManager* download_manager = DownloadManagerForBrowser(browser); | |
230 return new DownloadTestObserverTerminal( | |
231 download_manager, num_downloads, | |
232 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); | |
233 } | |
234 | |
235 void WaitForCompletion(DownloadItem* download) { | |
236 DownloadUpdatedObserver( | |
237 download, base::Bind(&IsDownloadInState, DownloadItem::COMPLETE)) | |
238 .WaitForEvent(); | |
239 } | |
240 | |
241 // Note: Cannot be used with other alternative DownloadFileFactorys | |
242 void SetupEnsureNoPendingDownloads() { | |
243 DownloadManagerForBrowser(browser())->SetDownloadFileFactoryForTesting( | |
244 std::unique_ptr<DownloadFileFactory>( | |
245 new CountingDownloadFileFactory())); | |
246 } | |
247 | |
248 bool EnsureNoPendingDownloads() { | |
249 bool result = true; | |
250 BrowserThread::PostTask( | |
251 BrowserThread::IO, FROM_HERE, | |
252 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result)); | |
253 base::RunLoop().Run(); | |
254 return result && | |
255 (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0); | |
256 } | |
257 | |
258 HeadlessWebContents* CreateWebContentsForURL(HeadlessBrowser* browser, | |
259 const GURL& url) { | |
260 return browser->GetDefaultBrowserContext() | |
261 ->CreateWebContentsBuilder() | |
262 .SetInitialURL(url) | |
263 .Build(); | |
264 } | |
265 | |
266 // Checks that |path| is has |file_size| bytes, and matches the |value| | |
267 // string. | |
268 bool VerifyFile(const base::FilePath& path, | |
269 const std::string& value, | |
270 const int64_t file_size) { | |
271 std::string file_contents; | |
272 | |
273 { | |
274 base::ThreadRestrictions::ScopedAllowIO allow_io_during_test_verification; | |
275 bool read = base::ReadFileToString(path, &file_contents); | |
276 EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl; | |
277 if (!read) | |
278 return false; // Couldn't read the file. | |
279 } | |
280 | |
281 // Note: we don't handle really large files (more than size_t can hold) | |
282 // so we will fail in that case. | |
283 size_t expected_size = static_cast<size_t>(file_size); | |
284 | |
285 // Check the size. | |
286 EXPECT_EQ(expected_size, file_contents.size()); | |
287 if (expected_size != file_contents.size()) | |
288 return false; | |
289 | |
290 // Check the contents. | |
291 EXPECT_EQ(value, file_contents); | |
292 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) | |
293 return false; | |
294 | |
295 return true; | |
296 } | |
297 | |
298 // Start a download and return the item. | |
299 DownloadItem* StartDownloadAndReturnItem(HeadlessBrowser* browser, GURL url) { | |
300 std::unique_ptr<DownloadCreateObserver> observer( | |
301 new DownloadCreateObserver(DownloadManagerForBrowser(browser))); | |
302 | |
303 CreateWebContentsForURL(browser, url); | |
304 return observer->WaitForFinished(); | |
305 } | |
306 | |
307 private: | |
308 static void EnsureNoPendingDownloadJobsOnIO(bool* result) { | |
309 if (net::URLRequestSlowDownloadJob::NumberOutstandingRequests()) | |
310 *result = false; | |
311 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
312 base::MessageLoop::QuitWhenIdleClosure()); | |
313 } | |
314 | |
315 // Location of the downloads directory for these tests | |
316 base::ScopedTempDir downloads_directory_; | |
317 std::unique_ptr<HeadlessDownloadManagerDelegate> test_delegate_; | |
318 }; | |
319 | |
320 } // namespace | |
321 | |
322 IN_PROC_BROWSER_TEST_F(HeadlessDownloadContentTest, DownloadCancelled) { | |
323 base::ThreadRestrictions::SetIOAllowed(true); | |
324 SetupEnsureNoPendingDownloads(); | |
325 | |
326 // Create a download, wait until it's started, and confirm | |
327 // we're in the expected state. | |
328 DownloadItem* download = StartDownloadAndReturnItem( | |
329 browser(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl)); | |
330 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState()); | |
331 | |
332 // Cancel the download and wait for download system quiesce. | |
333 download->Cancel(true); | |
334 scoped_refptr<DownloadTestFlushObserver> flush_observer( | |
335 new DownloadTestFlushObserver(DownloadManagerForBrowser(browser()))); | |
336 flush_observer->WaitForFlush(); | |
337 | |
338 // Get the important info from other threads and check it. | |
339 EXPECT_TRUE(EnsureNoPendingDownloads()); | |
340 } | |
341 | |
342 // Check that downloading a single file works. | |
343 IN_PROC_BROWSER_TEST_F(HeadlessDownloadContentTest, SingleDownload) { | |
344 base::ThreadRestrictions::SetIOAllowed(true); | |
345 SetupEnsureNoPendingDownloads(); | |
346 | |
347 // Create a download, wait until it's started, and confirm | |
348 // we're in the expected state. | |
349 DownloadItem* download1 = StartDownloadAndReturnItem( | |
350 browser(), | |
351 GURL(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"))); | |
352 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState()); | |
353 | |
354 WaitForCompletion(download1); | |
355 ASSERT_EQ(DownloadItem::COMPLETE, download1->GetState()); | |
356 } | |
357 | |
358 // Check that downloading multiple (in this case, 2) files does not result in | |
359 // corrupted files. | |
360 IN_PROC_BROWSER_TEST_F(HeadlessDownloadContentTest, MultiDownload) { | |
361 SetupEnsureNoPendingDownloads(); | |
362 | |
363 // Create a download, wait until it's started, and confirm | |
364 // we're in the expected state. | |
365 DownloadItem* download1 = StartDownloadAndReturnItem( | |
366 browser(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl)); | |
367 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState()); | |
368 | |
369 // Start the second download and wait until it's done. | |
370 GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib")); | |
371 DownloadItem* download2 = StartDownloadAndReturnItem(browser(), url); | |
372 WaitForCompletion(download2); | |
373 | |
374 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState()); | |
375 ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState()); | |
376 | |
377 // Allow the first request to finish. | |
378 std::unique_ptr<DownloadTestObserver> observer2(CreateWaiter(browser(), 1)); | |
379 CreateWebContentsForURL( | |
380 browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl)); | |
381 observer2->WaitForFinished(); // Wait for the third request. | |
382 EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE)); | |
383 | |
384 // Get the important info from other threads and check it. | |
385 EXPECT_TRUE(EnsureNoPendingDownloads()); | |
386 | |
387 // The |DownloadItem|s should now be done and have the final file names. | |
388 // Verify that the files have the expected data and size. | |
389 // |file1| should be full of '*'s, and |file2| should be the same as the | |
390 // source file. | |
391 base::FilePath file1(download1->GetTargetFilePath()); | |
392 size_t file_size1 = net::URLRequestSlowDownloadJob::kFirstDownloadSize + | |
393 net::URLRequestSlowDownloadJob::kSecondDownloadSize; | |
394 std::string expected_contents(file_size1, '*'); | |
395 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1)); | |
396 | |
397 base::FilePath file2(download2->GetTargetFilePath()); | |
398 ASSERT_TRUE(base::ContentsEqual( | |
399 file2, GetTestFilePath("download", "download-test.lib"))); | |
400 } | |
401 | |
Sami
2017/06/05 16:50:32
Could we have a test that checks the ALLOW/DENY be
| |
402 } // namespace headless | |
OLD | NEW |