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

Side by Side Diff: headless/lib/headless_download_browsertest.cc

Issue 2886693002: initial version of the headless download manager delegate
Patch Set: initial version of the headless download manager delegate Created 3 years, 6 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698