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

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

Powered by Google App Engine
This is Rietveld 408576698