Chromium Code Reviews| 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 |