Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / streams_private / streams_private_apitest.cc
blob01b690ef1c1e131a172a5d4bfb15adf1cf4ad12f
1 // Copyright (c) 2012 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.
5 #include "base/command_line.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/download/download_prefs.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/common/extensions/api/streams_private.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/test/base/test_switches.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/download_item.h"
18 #include "content/public/browser/download_manager.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/resource_controller.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/test/download_test_observer.h"
23 #include "extensions/browser/event_router.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/manifest_handlers/mime_types_handler.h"
26 #include "extensions/test/result_catcher.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
29 #include "net/test/embedded_test_server/http_request.h"
30 #include "net/test/embedded_test_server/http_response.h"
31 #include "testing/gmock/include/gmock/gmock.h"
33 using content::BrowserContext;
34 using content::BrowserThread;
35 using content::DownloadItem;
36 using content::DownloadManager;
37 using content::DownloadUrlParameters;
38 using content::ResourceController;
39 using content::WebContents;
40 using extensions::Event;
41 using extensions::ExtensionSystem;
42 using extensions::ResultCatcher;
43 using net::test_server::BasicHttpResponse;
44 using net::test_server::HttpRequest;
45 using net::test_server::HttpResponse;
46 using net::test_server::EmbeddedTestServer;
47 using testing::_;
49 namespace streams_private = extensions::api::streams_private;
51 namespace {
53 // Test server's request handler.
54 // Returns response that should be sent by the test server.
55 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
56 scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse());
58 // For relative path "/doc_path.doc", return success response with MIME type
59 // "application/msword".
60 if (request.relative_url == "/doc_path.doc") {
61 response->set_code(net::HTTP_OK);
62 response->set_content_type("application/msword");
63 return response.Pass();
66 // For relative path "/spreadsheet_path.xls", return success response with
67 // MIME type "application/xls".
68 if (request.relative_url == "/spreadsheet_path.xls") {
69 response->set_code(net::HTTP_OK);
70 response->set_content_type("application/msexcel");
71 // Test that multiple headers with the same name are merged.
72 response->AddCustomHeader("Test-Header", "part1");
73 response->AddCustomHeader("Test-Header", "part2");
74 return response.Pass();
77 // For relative path "/text_path_attch.txt", return success response with
78 // MIME type "text/plain" and content "txt content". Also, set content
79 // disposition to be attachment.
80 if (request.relative_url == "/text_path_attch.txt") {
81 response->set_code(net::HTTP_OK);
82 response->set_content("txt content");
83 response->set_content_type("text/plain");
84 response->AddCustomHeader("Content-Disposition",
85 "attachment; filename=test_path.txt");
86 return response.Pass();
89 // For relative path "/test_path_attch.txt", return success response with
90 // MIME type "text/plain" and content "txt content".
91 if (request.relative_url == "/text_path.txt") {
92 response->set_code(net::HTTP_OK);
93 response->set_content("txt content");
94 response->set_content_type("text/plain");
95 return response.Pass();
98 // A random HTML file to navigate to.
99 if (request.relative_url == "/index.html") {
100 response->set_code(net::HTTP_OK);
101 response->set_content("html content");
102 response->set_content_type("text/html");
103 return response.Pass();
106 // RTF files for testing chrome.streamsPrivate.abort().
107 if (request.relative_url == "/abort.rtf" ||
108 request.relative_url == "/no_abort.rtf") {
109 response->set_code(net::HTTP_OK);
110 response->set_content_type("application/rtf");
111 return response.Pass();
114 // Respond to /favicon.ico for navigating to the page.
115 if (request.relative_url == "/favicon.ico") {
116 response->set_code(net::HTTP_NOT_FOUND);
117 return response.Pass();
120 // No other requests should be handled in the tests.
121 EXPECT_TRUE(false) << "NOTREACHED!";
122 response->set_code(net::HTTP_NOT_FOUND);
123 return response.Pass();
126 // Tests to verify that resources are correctly intercepted by
127 // StreamsResourceThrottle.
128 // The test extension expects the resources that should be handed to the
129 // extension to have MIME type 'application/msword' and the resources that
130 // should be downloaded by the browser to have MIME type 'text/plain'.
131 class StreamsPrivateApiTest : public ExtensionApiTest {
132 public:
133 StreamsPrivateApiTest() {}
135 ~StreamsPrivateApiTest() override {}
137 void SetUpOnMainThread() override {
138 // Init test server.
139 test_server_.reset(new EmbeddedTestServer);
140 ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
141 test_server_->RegisterRequestHandler(base::Bind(&HandleRequest));
143 ExtensionApiTest::SetUpOnMainThread();
146 void TearDownOnMainThread() override {
147 // Tear down the test server.
148 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
149 test_server_.reset();
150 ExtensionApiTest::TearDownOnMainThread();
153 void InitializeDownloadSettings() {
154 ASSERT_TRUE(browser());
155 ASSERT_TRUE(downloads_dir_.CreateUniqueTempDir());
157 // Setup default downloads directory to the scoped tmp directory created for
158 // the test.
159 browser()->profile()->GetPrefs()->SetFilePath(
160 prefs::kDownloadDefaultDirectory, downloads_dir_.path());
161 // Ensure there are no prompts for download during the test.
162 browser()->profile()->GetPrefs()->SetBoolean(
163 prefs::kPromptForDownload, false);
165 DownloadManager* manager = GetDownloadManager();
166 DownloadPrefs::FromDownloadManager(manager)->ResetAutoOpen();
167 manager->RemoveAllDownloads();
170 // Sends onExecuteContentHandler event with the MIME type "test/done" to the
171 // test extension.
172 // The test extension calls 'chrome.test.notifySuccess' when it receives the
173 // event with the "test/done" MIME type (unless the 'chrome.test.notifyFail'
174 // has already been called).
175 void SendDoneEvent() {
176 streams_private::StreamInfo info;
177 info.mime_type = "test/done";
178 info.original_url = "http://foo";
179 info.stream_url = "blob://bar";
180 info.tab_id = 10;
181 info.expected_content_size = 20;
183 scoped_ptr<Event> event(
184 new Event(streams_private::OnExecuteMimeTypeHandler::kEventName,
185 streams_private::OnExecuteMimeTypeHandler::Create(info)));
187 extensions::EventRouter::Get(browser()->profile())
188 ->DispatchEventToExtension(test_extension_id_, event.Pass());
191 // Loads the test extension and set's up its file_browser_handler to handle
192 // 'application/msword' and 'text/plain' MIME types.
193 // The extension will notify success when it detects an event with the MIME
194 // type 'application/msword' and notify fail when it detects an event with the
195 // MIME type 'text/plain'.
196 const extensions::Extension* LoadTestExtension() {
197 // The test extension id is set by the key value in the manifest.
198 test_extension_id_ = "oickdpebdnfbgkcaoklfcdhjniefkcji";
200 const extensions::Extension* extension = LoadExtension(
201 test_data_dir_.AppendASCII("streams_private/handle_mime_type"));
202 if (!extension)
203 return NULL;
205 MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
206 if (!handler) {
207 message_ = "No mime type handlers defined.";
208 return NULL;
211 DCHECK_EQ(test_extension_id_, extension->id());
213 return extension;
216 // Returns the download manager for the current browser.
217 DownloadManager* GetDownloadManager() const {
218 DownloadManager* download_manager =
219 BrowserContext::GetDownloadManager(browser()->profile());
220 EXPECT_TRUE(download_manager);
221 return download_manager;
224 // Deletes the download and waits until it's flushed.
225 // The |manager| should have |download| in its list of downloads.
226 void DeleteDownloadAndWaitForFlush(DownloadItem* download,
227 DownloadManager* manager) {
228 scoped_refptr<content::DownloadTestFlushObserver> flush_observer(
229 new content::DownloadTestFlushObserver(manager));
230 download->Remove();
231 flush_observer->WaitForFlush();
234 protected:
235 std::string test_extension_id_;
236 // The HTTP server used in the tests.
237 scoped_ptr<EmbeddedTestServer> test_server_;
238 base::ScopedTempDir downloads_dir_;
241 // Tests that navigating to a resource with a MIME type handleable by an
242 // installed, white-listed extension invokes the extension's
243 // onExecuteContentHandler event (and does not start a download).
244 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Navigate) {
245 #if defined(OS_WIN) && defined(USE_ASH)
246 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
247 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
248 switches::kAshBrowserTests))
249 return;
250 #endif
252 ASSERT_TRUE(LoadTestExtension()) << message_;
254 ResultCatcher catcher;
256 ui_test_utils::NavigateToURL(browser(),
257 test_server_->GetURL("/doc_path.doc"));
259 // Wait for the response from the test server.
260 base::MessageLoop::current()->RunUntilIdle();
262 // There should be no downloads started by the navigation.
263 DownloadManager* download_manager = GetDownloadManager();
264 std::vector<DownloadItem*> downloads;
265 download_manager->GetAllDownloads(&downloads);
266 ASSERT_EQ(0u, downloads.size());
268 // The test extension should receive onExecuteContentHandler event with MIME
269 // type 'application/msword' (and call chrome.test.notifySuccess).
270 EXPECT_TRUE(catcher.GetNextResult());
273 // Tests that navigating to a file URL also intercepts despite there being no
274 // HTTP headers. This is a regression test for https://crbug.com/416433.
275 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, FileURL) {
276 #if defined(OS_WIN) && defined(USE_ASH)
277 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
278 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
279 switches::kAshBrowserTests))
280 return;
281 #endif
283 ASSERT_TRUE(LoadTestExtension()) << message_;
285 ResultCatcher catcher;
287 ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(
288 base::FilePath(FILE_PATH_LITERAL("downloads")),
289 base::FilePath(FILE_PATH_LITERAL("Picture_1.doc"))));
291 // There should be no downloads started by the navigation.
292 DownloadManager* download_manager = GetDownloadManager();
293 std::vector<DownloadItem*> downloads;
294 download_manager->GetAllDownloads(&downloads);
295 ASSERT_EQ(0u, downloads.size());
297 // The test extension should receive onExecuteContentHandler event with MIME
298 // type 'application/msword' (and call chrome.test.notifySuccess).
299 EXPECT_TRUE(catcher.GetNextResult());
302 // Tests that navigating cross-site to a resource with a MIME type handleable by
303 // an installed, white-listed extension invokes the extension's
304 // onExecuteContentHandler event (and does not start a download).
305 // Regression test for http://crbug.com/342999.
306 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, NavigateCrossSite) {
307 #if defined(OS_WIN) && defined(USE_ASH)
308 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
309 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
310 switches::kAshBrowserTests))
311 return;
312 #endif
314 ASSERT_TRUE(LoadTestExtension()) << message_;
316 ResultCatcher catcher;
318 // Navigate to a URL on a different hostname.
319 static const char kInitialHost[] = "www.example.com";
320 host_resolver()->AddRule(kInitialHost, "127.0.0.1");
321 GURL::Replacements replacements;
322 replacements.SetHostStr(kInitialHost);
323 GURL initial_url =
324 test_server_->GetURL("/index.html").ReplaceComponents(replacements);
325 ui_test_utils::NavigateToURL(browser(), initial_url);
327 // Now navigate to the doc file; the extension should pick it up normally.
328 ui_test_utils::NavigateToURL(browser(),
329 test_server_->GetURL("/doc_path.doc"));
331 // Wait for the response from the test server.
332 base::MessageLoop::current()->RunUntilIdle();
334 // There should be no downloads started by the navigation.
335 DownloadManager* download_manager = GetDownloadManager();
336 std::vector<DownloadItem*> downloads;
337 download_manager->GetAllDownloads(&downloads);
338 ASSERT_EQ(0u, downloads.size());
340 // The test extension should receive onExecuteContentHandler event with MIME
341 // type 'application/msword' (and call chrome.test.notifySuccess).
342 EXPECT_TRUE(catcher.GetNextResult());
345 // Tests that navigation to an attachment starts a download, even if there is an
346 // extension with a file browser handler that can handle the attachment's MIME
347 // type.
348 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, NavigateToAnAttachment) {
349 InitializeDownloadSettings();
351 ASSERT_TRUE(LoadTestExtension()) << message_;
353 ResultCatcher catcher;
355 // The test should start a download.
356 DownloadManager* download_manager = GetDownloadManager();
357 scoped_ptr<content::DownloadTestObserver> download_observer(
358 new content::DownloadTestObserverInProgress(download_manager, 1));
360 ui_test_utils::NavigateToURL(browser(),
361 test_server_->GetURL("/text_path_attch.txt"));
363 // Wait for the download to start.
364 download_observer->WaitForFinished();
366 // There should be one download started by the navigation.
367 DownloadManager::DownloadVector downloads;
368 download_manager->GetAllDownloads(&downloads);
369 ASSERT_EQ(1u, downloads.size());
371 // Cancel and delete the download started in the test.
372 DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
374 // The test extension should not receive any events by now. Send it an event
375 // with MIME type "test/done", so it stops waiting for the events. (If there
376 // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
377 // fail regardless of the sent event; chrome.test.notifySuccess will not be
378 // called by the extension).
379 SendDoneEvent();
380 EXPECT_TRUE(catcher.GetNextResult());
383 // Tests that direct download requests don't get intercepted by
384 // StreamsResourceThrottle, even if there is an extension with a file
385 // browser handler that can handle the download's MIME type.
386 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, DirectDownload) {
387 InitializeDownloadSettings();
389 ASSERT_TRUE(LoadTestExtension()) << message_;
391 ResultCatcher catcher;
393 DownloadManager* download_manager = GetDownloadManager();
394 scoped_ptr<content::DownloadTestObserver> download_observer(
395 new content::DownloadTestObserverInProgress(download_manager, 1));
397 // The resource's URL on the test server.
398 GURL url = test_server_->GetURL("/text_path.txt");
400 // The download's target file path.
401 base::FilePath target_path =
402 downloads_dir_.path().Append(FILE_PATH_LITERAL("download_target.txt"));
404 // Set the downloads parameters.
405 content::WebContents* web_contents =
406 browser()->tab_strip_model()->GetActiveWebContents();
407 ASSERT_TRUE(web_contents);
408 scoped_ptr<DownloadUrlParameters> params(
409 DownloadUrlParameters::FromWebContents(web_contents, url));
410 params->set_file_path(target_path);
412 // Start download of the URL with a path "/text_path.txt" on the test server.
413 download_manager->DownloadUrl(params.Pass());
415 // Wait for the download to start.
416 download_observer->WaitForFinished();
418 // There should have been one download.
419 std::vector<DownloadItem*> downloads;
420 download_manager->GetAllDownloads(&downloads);
421 ASSERT_EQ(1u, downloads.size());
423 // Cancel and delete the download statred in the test.
424 DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
426 // The test extension should not receive any events by now. Send it an event
427 // with MIME type "test/done", so it stops waiting for the events. (If there
428 // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
429 // fail regardless of the sent event; chrome.test.notifySuccess will not be
430 // called by the extension).
431 SendDoneEvent();
432 EXPECT_TRUE(catcher.GetNextResult());
435 // Tests that response headers are correctly passed to the API and that multiple
436 // repsonse headers with the same name are merged correctly.
437 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Headers) {
438 #if defined(OS_WIN) && defined(USE_ASH)
439 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
440 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
441 switches::kAshBrowserTests))
442 return;
443 #endif
445 ASSERT_TRUE(LoadTestExtension()) << message_;
447 ResultCatcher catcher;
449 ui_test_utils::NavigateToURL(browser(),
450 test_server_->GetURL("/spreadsheet_path.xls"));
452 // Wait for the response from the test server.
453 base::MessageLoop::current()->RunUntilIdle();
455 // There should be no downloads started by the navigation.
456 DownloadManager* download_manager = GetDownloadManager();
457 std::vector<DownloadItem*> downloads;
458 download_manager->GetAllDownloads(&downloads);
459 ASSERT_EQ(0u, downloads.size());
461 // The test extension should receive onExecuteContentHandler event with MIME
462 // type 'application/msexcel' (and call chrome.test.notifySuccess).
463 EXPECT_TRUE(catcher.GetNextResult());
466 // Tests that chrome.streamsPrivate.abort() works correctly.
467 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Abort) {
468 #if defined(OS_WIN) && defined(USE_ASH)
469 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
470 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
471 switches::kAshBrowserTests))
472 return;
473 #endif
475 ASSERT_TRUE(LoadTestExtension()) << message_;
477 ResultCatcher catcher;
478 ui_test_utils::NavigateToURL(browser(),
479 test_server_->GetURL("/no_abort.rtf"));
480 base::MessageLoop::current()->RunUntilIdle();
481 EXPECT_TRUE(catcher.GetNextResult());
483 ui_test_utils::NavigateToURL(browser(),
484 test_server_->GetURL("/abort.rtf"));
485 base::MessageLoop::current()->RunUntilIdle();
486 EXPECT_TRUE(catcher.GetNextResult());
489 } // namespace