download_browsertest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright 2020 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. #include "weblayer/test/weblayer_browser_test.h"
  5. #include "base/files/file_util.h"
  6. #include "base/files/scoped_temp_dir.h"
  7. #include "base/path_service.h"
  8. #include "base/run_loop.h"
  9. #include "base/test/bind.h"
  10. #include "base/threading/thread_restrictions.h"
  11. #include "build/build_config.h"
  12. #include "content/public/browser/download_manager.h"
  13. #include "content/public/browser/web_contents.h"
  14. #include "content/public/test/slow_download_http_response.h"
  15. #include "net/test/embedded_test_server/embedded_test_server.h"
  16. #include "weblayer/browser/browser_context_impl.h"
  17. #include "weblayer/browser/download_manager_delegate_impl.h"
  18. #include "weblayer/browser/profile_impl.h"
  19. #include "weblayer/browser/tab_impl.h"
  20. #include "weblayer/public/download.h"
  21. #include "weblayer/public/download_delegate.h"
  22. #include "weblayer/public/navigation_controller.h"
  23. #include "weblayer/shell/browser/shell.h"
  24. #include "weblayer/test/test_navigation_observer.h"
  25. #include "weblayer/test/weblayer_browser_test_utils.h"
  26. namespace weblayer {
  27. namespace {
  28. class DownloadBrowserTest : public WebLayerBrowserTest,
  29. public DownloadDelegate {
  30. public:
  31. DownloadBrowserTest() = default;
  32. ~DownloadBrowserTest() override = default;
  33. void SetUpOnMainThread() override {
  34. embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
  35. &content::SlowDownloadHttpResponse::HandleSlowDownloadRequest));
  36. ASSERT_TRUE(embedded_test_server()->Start());
  37. allow_run_loop_ = std::make_unique<base::RunLoop>();
  38. started_run_loop_ = std::make_unique<base::RunLoop>();
  39. intercept_run_loop_ = std::make_unique<base::RunLoop>();
  40. completed_run_loop_ = std::make_unique<base::RunLoop>();
  41. failed_run_loop_ = std::make_unique<base::RunLoop>();
  42. Tab* tab = shell()->tab();
  43. TabImpl* tab_impl = static_cast<TabImpl*>(tab);
  44. tab_impl->profile()->SetDownloadDelegate(this);
  45. auto* browser_context = tab_impl->web_contents()->GetBrowserContext();
  46. auto* download_manager_delegate =
  47. browser_context->GetDownloadManager()->GetDelegate();
  48. static_cast<DownloadManagerDelegateImpl*>(download_manager_delegate)
  49. ->set_download_dropped_closure_for_testing(base::BindRepeating(
  50. &DownloadBrowserTest::DownloadDropped, base::Unretained(this)));
  51. }
  52. void WaitForAllow() { allow_run_loop_->Run(); }
  53. void WaitForIntercept() { intercept_run_loop_->Run(); }
  54. void WaitForStarted() { started_run_loop_->Run(); }
  55. void WaitForCompleted() { completed_run_loop_->Run(); }
  56. void WaitForFailed() { failed_run_loop_->Run(); }
  57. void set_intercept() { intercept_ = true; }
  58. void set_disallow() { allow_ = false; }
  59. void set_started_callback(
  60. base::OnceCallback<void(Download* download)> callback) {
  61. started_callback_ = std::move(callback);
  62. }
  63. void set_failed_callback(
  64. base::OnceCallback<void(Download* download)> callback) {
  65. failed_callback_ = std::move(callback);
  66. }
  67. bool started() { return started_; }
  68. base::FilePath download_location() { return download_location_; }
  69. int64_t total_bytes() { return total_bytes_; }
  70. DownloadError download_state() { return download_state_; }
  71. std::string mime_type() { return mime_type_; }
  72. int completed_count() { return completed_count_; }
  73. int failed_count() { return failed_count_; }
  74. int download_dropped_count() { return download_dropped_count_; }
  75. private:
  76. // DownloadDelegate implementation:
  77. void AllowDownload(Tab* tab,
  78. const GURL& url,
  79. const std::string& request_method,
  80. absl::optional<url::Origin> request_initiator,
  81. AllowDownloadCallback callback) override {
  82. std::move(callback).Run(allow_);
  83. allow_run_loop_->Quit();
  84. }
  85. bool InterceptDownload(const GURL& url,
  86. const std::string& user_agent,
  87. const std::string& content_disposition,
  88. const std::string& mime_type,
  89. int64_t content_length) override {
  90. intercept_run_loop_->Quit();
  91. return intercept_;
  92. }
  93. void DownloadStarted(Download* download) override {
  94. started_ = true;
  95. started_run_loop_->Quit();
  96. CHECK_EQ(download->GetState(), DownloadState::kInProgress);
  97. if (started_callback_)
  98. std::move(started_callback_).Run(download);
  99. }
  100. void DownloadCompleted(Download* download) override {
  101. completed_count_++;
  102. download_location_ = download->GetLocation();
  103. total_bytes_ = download->GetTotalBytes();
  104. download_state_ = download->GetError();
  105. mime_type_ = download->GetMimeType();
  106. CHECK_EQ(download->GetReceivedBytes(), total_bytes_);
  107. CHECK_EQ(download->GetState(), DownloadState::kComplete);
  108. completed_run_loop_->Quit();
  109. }
  110. void DownloadFailed(Download* download) override {
  111. failed_count_++;
  112. download_state_ = download->GetError();
  113. failed_run_loop_->Quit();
  114. if (failed_callback_)
  115. std::move(failed_callback_).Run(download);
  116. }
  117. void DownloadDropped() { download_dropped_count_++; }
  118. bool intercept_ = false;
  119. bool allow_ = true;
  120. bool started_ = false;
  121. base::OnceCallback<void(Download* download)> started_callback_;
  122. base::OnceCallback<void(Download* download)> failed_callback_;
  123. base::FilePath download_location_;
  124. int64_t total_bytes_ = 0;
  125. DownloadError download_state_ = DownloadError::kNoError;
  126. std::string mime_type_;
  127. int completed_count_ = 0;
  128. int failed_count_ = 0;
  129. int download_dropped_count_ = 0;
  130. std::unique_ptr<base::RunLoop> allow_run_loop_;
  131. std::unique_ptr<base::RunLoop> intercept_run_loop_;
  132. std::unique_ptr<base::RunLoop> started_run_loop_;
  133. std::unique_ptr<base::RunLoop> completed_run_loop_;
  134. std::unique_ptr<base::RunLoop> failed_run_loop_;
  135. };
  136. } // namespace
  137. // Ensures that if the delegate disallows the downloads then WebLayer
  138. // doesn't download it.
  139. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, DisallowNoDownload) {
  140. set_disallow();
  141. GURL url(embedded_test_server()->GetURL("/content-disposition.html"));
  142. // Downloads always count as failed navigations.
  143. TestNavigationObserver observer(
  144. url, TestNavigationObserver::NavigationEvent::kFailure, shell());
  145. shell()->tab()->GetNavigationController()->Navigate(url);
  146. observer.Wait();
  147. WaitForAllow();
  148. EXPECT_FALSE(started());
  149. EXPECT_EQ(completed_count(), 0);
  150. EXPECT_EQ(failed_count(), 0);
  151. EXPECT_EQ(download_dropped_count(), 1);
  152. }
  153. // Ensures that if the delegate chooses to intercept downloads then WebLayer
  154. // doesn't download it.
  155. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, InterceptNoDownload) {
  156. set_intercept();
  157. GURL url(embedded_test_server()->GetURL("/content-disposition.html"));
  158. shell()->tab()->GetNavigationController()->Navigate(url);
  159. WaitForIntercept();
  160. EXPECT_FALSE(started());
  161. EXPECT_EQ(completed_count(), 0);
  162. EXPECT_EQ(failed_count(), 0);
  163. EXPECT_EQ(download_dropped_count(), 1);
  164. }
  165. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Basic) {
  166. GURL url(embedded_test_server()->GetURL("/content-disposition.html"));
  167. shell()->tab()->GetNavigationController()->Navigate(url);
  168. WaitForCompleted();
  169. EXPECT_TRUE(started());
  170. EXPECT_EQ(completed_count(), 1);
  171. EXPECT_EQ(failed_count(), 0);
  172. EXPECT_EQ(download_dropped_count(), 0);
  173. EXPECT_EQ(download_state(), DownloadError::kNoError);
  174. EXPECT_EQ(mime_type(), "text/html");
  175. // Check that the size on disk matches what's expected.
  176. {
  177. base::ScopedAllowBlockingForTesting allow_blocking;
  178. int64_t downloaded_file_size, original_file_size;
  179. EXPECT_TRUE(base::GetFileSize(download_location(), &downloaded_file_size));
  180. base::FilePath test_data_dir;
  181. CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
  182. EXPECT_TRUE(base::GetFileSize(
  183. test_data_dir.Append(base::FilePath(
  184. FILE_PATH_LITERAL("weblayer/test/data/content-disposition.html"))),
  185. &original_file_size));
  186. EXPECT_EQ(downloaded_file_size, total_bytes());
  187. }
  188. // Ensure browser tests don't write to the default machine download directory
  189. // to avoid filing it up.
  190. EXPECT_NE(BrowserContextImpl::GetDefaultDownloadDirectory(),
  191. download_location().DirName());
  192. }
  193. // Test consistently failing on android: crbug.com/1273105
  194. #if BUILDFLAG(IS_ANDROID)
  195. #define MAYBE_OverrideDownloadDirectory DISABLED_OverrideDownloadDirectory
  196. #else
  197. #define MAYBE_OverrideDownloadDirectory OverrideDownloadDirectory
  198. #endif
  199. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, MAYBE_OverrideDownloadDirectory) {
  200. base::ScopedAllowBlockingForTesting allow_blocking;
  201. base::ScopedTempDir download_dir;
  202. ASSERT_TRUE(download_dir.CreateUniqueTempDir());
  203. TabImpl* tab_impl = static_cast<TabImpl*>(shell()->tab());
  204. auto* browser_context = tab_impl->web_contents()->GetBrowserContext();
  205. auto* browser_context_impl =
  206. static_cast<BrowserContextImpl*>(browser_context);
  207. browser_context_impl->profile_impl()->SetDownloadDirectory(
  208. download_dir.GetPath());
  209. GURL url(embedded_test_server()->GetURL("/content-disposition.html"));
  210. shell()->tab()->GetNavigationController()->Navigate(url);
  211. WaitForCompleted();
  212. EXPECT_EQ(completed_count(), 1);
  213. EXPECT_EQ(failed_count(), 0);
  214. EXPECT_EQ(download_dir.GetPath(), download_location().DirName());
  215. }
  216. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Cancel) {
  217. set_started_callback(base::BindLambdaForTesting([&](Download* download) {
  218. download->Cancel();
  219. // Also allow the download to complete.
  220. GURL url = embedded_test_server()->GetURL(
  221. content::SlowDownloadHttpResponse::kFinishSlowResponseUrl);
  222. shell()->tab()->GetNavigationController()->Navigate(url);
  223. }));
  224. set_failed_callback(base::BindLambdaForTesting([](Download* download) {
  225. CHECK_EQ(download->GetState(), DownloadState::kCancelled);
  226. }));
  227. // Create a request that doesn't complete right away to avoid flakiness.
  228. GURL url(embedded_test_server()->GetURL(
  229. content::SlowDownloadHttpResponse::kKnownSizeUrl));
  230. shell()->tab()->GetNavigationController()->Navigate(url);
  231. WaitForFailed();
  232. EXPECT_EQ(completed_count(), 0);
  233. EXPECT_EQ(failed_count(), 1);
  234. EXPECT_EQ(download_dropped_count(), 0);
  235. EXPECT_EQ(download_state(), DownloadError::kCancelled);
  236. }
  237. // TODO(crbug.com/1314060): Flaky on Windows and Linux.
  238. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
  239. #define MAYBE_PauseResume DISABLED_PauseResume
  240. #else
  241. #define MAYBE_PauseResume PauseResume
  242. #endif
  243. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, MAYBE_PauseResume) {
  244. // Add an initial navigation to avoid the tab being deleted if the first
  245. // navigation is a download, since we use the tab for convenience in the
  246. // lambda.
  247. OneShotNavigationObserver observer(shell());
  248. shell()->tab()->GetNavigationController()->Navigate(GURL("about:blank"));
  249. observer.WaitForNavigation();
  250. set_started_callback(base::BindLambdaForTesting([&](Download* download) {
  251. download->Pause();
  252. GURL url = embedded_test_server()->GetURL(
  253. content::SlowDownloadHttpResponse::kFinishSlowResponseUrl);
  254. base::SequencedTaskRunnerHandle::Get()->PostTask(
  255. FROM_HERE, base::BindOnce(
  256. [](Download* download, Shell* shell, const GURL& url) {
  257. CHECK_EQ(download->GetState(), DownloadState::kPaused);
  258. download->Resume();
  259. // Also allow the download to complete.
  260. shell->tab()->GetNavigationController()->Navigate(url);
  261. },
  262. download, shell(), url));
  263. }));
  264. // Create a request that doesn't complete right away to avoid flakiness.
  265. GURL url(embedded_test_server()->GetURL(
  266. content::SlowDownloadHttpResponse::kKnownSizeUrl));
  267. shell()->tab()->GetNavigationController()->Navigate(url);
  268. WaitForCompleted();
  269. EXPECT_EQ(completed_count(), 1);
  270. EXPECT_EQ(failed_count(), 0);
  271. EXPECT_EQ(download_dropped_count(), 0);
  272. }
  273. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, NetworkError) {
  274. set_failed_callback(base::BindLambdaForTesting([](Download* download) {
  275. CHECK_EQ(download->GetState(), DownloadState::kFailed);
  276. }));
  277. // Create a request that doesn't complete right away.
  278. GURL url(embedded_test_server()->GetURL(
  279. content::SlowDownloadHttpResponse::kKnownSizeUrl));
  280. shell()->tab()->GetNavigationController()->Navigate(url);
  281. WaitForStarted();
  282. EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
  283. WaitForFailed();
  284. EXPECT_EQ(completed_count(), 0);
  285. EXPECT_EQ(failed_count(), 1);
  286. EXPECT_EQ(download_dropped_count(), 0);
  287. EXPECT_EQ(download_state(), DownloadError::kConnectivityError);
  288. }
  289. IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, PendingOnExist) {
  290. // Create a request that doesn't complete right away.
  291. GURL url(embedded_test_server()->GetURL(
  292. content::SlowDownloadHttpResponse::kKnownSizeUrl));
  293. shell()->tab()->GetNavigationController()->Navigate(url);
  294. WaitForStarted();
  295. // If this test crashes later then there'd be a regression.
  296. }
  297. } // namespace weblayer