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/basictypes.h"
6 #include "base/command_line.h"
7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/browser/extensions/tab_helper.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
17 #include "chrome/browser/ui/tabs/tab_utils.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/chrome_version_info.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/test_utils.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/common/switches.h"
26 #include "extensions/test/extension_test_message_listener.h"
27 #include "extensions/test/result_catcher.h"
30 #include "base/win/windows_version.h"
33 namespace extensions
{
37 const char kExtensionId
[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
39 class TabCaptureApiTest
: public ExtensionApiTest
{
41 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
42 ExtensionApiTest::SetUpCommandLine(command_line
);
43 // Specify smallish window size to make testing of tab capture less CPU
45 command_line
->AppendSwitchASCII(::switches::kWindowSize
, "300,300");
46 command_line
->AppendSwitch(::switches::kEnableTabAudioMuting
);
49 void AddExtensionToCommandLineWhitelist() {
50 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
51 switches::kWhitelistedExtensionID
, kExtensionId
);
55 void SimulateMouseClickInCurrentTab() {
56 content::SimulateMouseClick(
57 browser()->tab_strip_model()->GetActiveWebContents(),
59 blink::WebMouseEvent::ButtonLeft
);
63 class TabCaptureApiPixelTest
: public TabCaptureApiTest
{
65 void SetUp() override
{
66 if (!IsTooIntensiveForThisPlatform())
68 TabCaptureApiTest::SetUp();
72 bool IsTooIntensiveForThisPlatform() const {
74 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
78 // The tests are too slow to succeed with OSMesa on the bots.
85 // TODO(miu): Look into enabling these tests for the Debug build bots once
86 // they prove to be stable again on the Release bots.
87 // http://crbug.com/396413
88 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
89 "run-tab-capture-api-pixel-tests");
94 // Tests API behaviors, including info queries, and constraints violations.
95 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, ApiTests
) {
96 AddExtensionToCommandLineWhitelist();
97 ASSERT_TRUE(RunExtensionSubtest("tab_capture", "api_tests.html")) << message_
;
100 // Tests that tab capture video frames can be received in a VIDEO element.
101 IN_PROC_BROWSER_TEST_F(TabCaptureApiPixelTest
, EndToEndWithoutRemoting
) {
102 if (IsTooIntensiveForThisPlatform()) {
103 LOG(WARNING
) << "Skipping this CPU-intensive test on this platform/build.";
106 AddExtensionToCommandLineWhitelist();
107 ASSERT_TRUE(RunExtensionSubtest(
108 "tab_capture", "end_to_end.html?method=local&colorDeviation=10"))
112 // Tests that video frames are captured, transported via WebRTC, and finally
113 // received in a VIDEO element. More allowance is provided for color deviation
114 // because of the additional layers of video processing performed within
116 IN_PROC_BROWSER_TEST_F(TabCaptureApiPixelTest
, EndToEndThroughWebRTC
) {
117 if (IsTooIntensiveForThisPlatform()) {
118 LOG(WARNING
) << "Skipping this CPU-intensive test on this platform/build.";
121 AddExtensionToCommandLineWhitelist();
122 ASSERT_TRUE(RunExtensionSubtest(
123 "tab_capture", "end_to_end.html?method=webrtc&colorDeviation=50"))
127 // http://crbug.com/177163
128 #if defined(OS_WIN) && !defined(NDEBUG)
129 #define MAYBE_GetUserMediaTest DISABLED_GetUserMediaTest
131 #define MAYBE_GetUserMediaTest GetUserMediaTest
133 // Tests that getUserMedia() is NOT a way to start tab capture.
134 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_GetUserMediaTest
) {
135 ExtensionTestMessageListener
listener("ready", true);
137 ASSERT_TRUE(RunExtensionSubtest("tab_capture", "get_user_media_test.html"))
140 EXPECT_TRUE(listener
.WaitUntilSatisfied());
142 content::OpenURLParams
params(GURL("about:blank"), content::Referrer(),
144 ui::PAGE_TRANSITION_LINK
, false);
145 content::WebContents
* web_contents
= browser()->OpenURL(params
);
147 content::RenderFrameHost
* const main_frame
= web_contents
->GetMainFrame();
148 ASSERT_TRUE(main_frame
);
149 listener
.Reply(base::StringPrintf("web-contents-media-stream://%i:%i",
150 main_frame
->GetProcess()->GetID(),
151 main_frame
->GetRoutingID()));
153 ResultCatcher catcher
;
154 catcher
.RestrictToBrowserContext(browser()->profile());
155 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
158 // http://crbug.com/177163
159 #if defined(OS_WIN) && !defined(NDEBUG)
160 #define MAYBE_ActiveTabPermission DISABLED_ActiveTabPermission
162 #define MAYBE_ActiveTabPermission ActiveTabPermission
164 // Make sure tabCapture.capture only works if the tab has been granted
165 // permission via an extension icon click or the extension is whitelisted.
166 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_ActiveTabPermission
) {
167 ExtensionTestMessageListener
before_open_tab("ready1", true);
168 ExtensionTestMessageListener
before_grant_permission("ready2", true);
169 ExtensionTestMessageListener
before_open_new_tab("ready3", true);
170 ExtensionTestMessageListener
before_whitelist_extension("ready4", true);
172 ASSERT_TRUE(RunExtensionSubtest("tab_capture",
173 "active_tab_permission_test.html"))
176 // Open a new tab and make sure capture is denied.
177 EXPECT_TRUE(before_open_tab
.WaitUntilSatisfied());
178 content::OpenURLParams
params(GURL("http://google.com"), content::Referrer(),
180 ui::PAGE_TRANSITION_LINK
, false);
181 content::WebContents
* web_contents
= browser()->OpenURL(params
);
182 before_open_tab
.Reply("");
184 // Grant permission and make sure capture succeeds.
185 EXPECT_TRUE(before_grant_permission
.WaitUntilSatisfied());
186 const Extension
* extension
= ExtensionRegistry::Get(
187 web_contents
->GetBrowserContext())->enabled_extensions().GetByID(
189 TabHelper::FromWebContents(web_contents
)
190 ->active_tab_permission_granter()->GrantIfRequested(extension
);
191 before_grant_permission
.Reply("");
193 // Open a new tab and make sure capture is denied.
194 EXPECT_TRUE(before_open_new_tab
.WaitUntilSatisfied());
195 browser()->OpenURL(params
);
196 before_open_new_tab
.Reply("");
198 // Add extension to whitelist and make sure capture succeeds.
199 EXPECT_TRUE(before_whitelist_extension
.WaitUntilSatisfied());
200 AddExtensionToCommandLineWhitelist();
201 before_whitelist_extension
.Reply("");
203 ResultCatcher catcher
;
204 catcher
.RestrictToBrowserContext(browser()->profile());
205 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
208 // http://crbug.com/177163
209 #if defined(OS_WIN) && !defined(NDEBUG)
210 #define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
212 #define MAYBE_FullscreenEvents FullscreenEvents
214 // Tests that fullscreen transitions during a tab capture session dispatch
215 // events to the onStatusChange listener. The test loads a page that toggles
216 // fullscreen mode, using the Fullscreen Javascript API, in response to mouse
218 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_FullscreenEvents
) {
219 AddExtensionToCommandLineWhitelist();
221 ExtensionTestMessageListener
capture_started("tab_capture_started", false);
222 ExtensionTestMessageListener
entered_fullscreen("entered_fullscreen", false);
224 ASSERT_TRUE(RunExtensionSubtest("tab_capture", "fullscreen_test.html"))
226 EXPECT_TRUE(capture_started
.WaitUntilSatisfied());
228 // Click on the page to trigger the Javascript that will toggle the tab into
230 SimulateMouseClickInCurrentTab();
231 EXPECT_TRUE(entered_fullscreen
.WaitUntilSatisfied());
233 // Click again to exit fullscreen mode.
234 SimulateMouseClickInCurrentTab();
236 // Wait until the page examines its results and calls chrome.test.succeed().
237 ResultCatcher catcher
;
238 catcher
.RestrictToBrowserContext(browser()->profile());
239 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
242 // Times out on Win dbg bots: http://crbug.com/177163
243 // Flaky on MSan bots: http://crbug.com/294431
244 #if (defined(OS_WIN) && !defined(NDEBUG)) || defined(MEMORY_SANITIZER)
245 #define MAYBE_GrantForChromePages DISABLED_GrantForChromePages
247 #define MAYBE_GrantForChromePages GrantForChromePages
249 // Make sure tabCapture API can be granted for Chrome:// pages.
250 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_GrantForChromePages
) {
251 ExtensionTestMessageListener
before_open_tab("ready1", true);
252 ASSERT_TRUE(RunExtensionSubtest("tab_capture",
253 "active_tab_chrome_pages.html"))
255 EXPECT_TRUE(before_open_tab
.WaitUntilSatisfied());
257 // Open a tab on a chrome:// page and make sure we can capture.
258 content::OpenURLParams
params(GURL("chrome://version"), content::Referrer(),
260 ui::PAGE_TRANSITION_LINK
, false);
261 content::WebContents
* web_contents
= browser()->OpenURL(params
);
262 const Extension
* extension
= ExtensionRegistry::Get(
263 web_contents
->GetBrowserContext())->enabled_extensions().GetByID(
265 TabHelper::FromWebContents(web_contents
)
266 ->active_tab_permission_granter()->GrantIfRequested(extension
);
267 before_open_tab
.Reply("");
269 ResultCatcher catcher
;
270 catcher
.RestrictToBrowserContext(browser()->profile());
271 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
274 // http://crbug.com/177163
275 #if defined(OS_WIN) && !defined(NDEBUG)
276 #define MAYBE_CaptureInSplitIncognitoMode DISABLED_CaptureInSplitIncognitoMode
278 #define MAYBE_CaptureInSplitIncognitoMode CaptureInSplitIncognitoMode
280 // Tests that a tab in incognito mode can be captured.
281 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_CaptureInSplitIncognitoMode
) {
282 AddExtensionToCommandLineWhitelist();
283 ASSERT_TRUE(RunExtensionSubtest("tab_capture",
284 "start_tab_capture.html",
285 kFlagEnableIncognito
| kFlagUseIncognito
))
289 // http://crbug.com/177163
290 #if defined(OS_WIN) && !defined(NDEBUG)
291 #define MAYBE_Constraints DISABLED_Constraints
293 #define MAYBE_Constraints Constraints
295 // Tests that valid constraints allow tab capture to start, while invalid ones
297 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_Constraints
) {
298 AddExtensionToCommandLineWhitelist();
299 ASSERT_TRUE(RunExtensionSubtest("tab_capture", "constraints.html"))
303 // http://crbug.com/177163
304 #if defined(OS_WIN) && !defined(NDEBUG)
305 #define MAYBE_TabIndicator DISABLED_TabIndicator
307 #define MAYBE_TabIndicator TabIndicator
309 // Tests that the tab indicator (in the tab strip) is shown during tab capture.
310 IN_PROC_BROWSER_TEST_F(TabCaptureApiTest
, MAYBE_TabIndicator
) {
311 ASSERT_EQ(TAB_MEDIA_STATE_NONE
,
312 chrome::GetTabMediaStateForContents(
313 browser()->tab_strip_model()->GetActiveWebContents()));
315 // Run an extension test that just turns on tab capture, which should cause
316 // the indicator to turn on.
317 AddExtensionToCommandLineWhitelist();
318 ASSERT_TRUE(RunExtensionSubtest("tab_capture", "start_tab_capture.html"))
321 // A TabStripModelObserver that quits the MessageLoop whenever the UI's model
322 // is sent an event that changes the indicator status.
323 class IndicatorChangeObserver
: public TabStripModelObserver
{
325 explicit IndicatorChangeObserver(Browser
* browser
)
326 : last_media_state_(chrome::GetTabMediaStateForContents(
327 browser
->tab_strip_model()->GetActiveWebContents())) {}
329 TabMediaState
last_media_state() const { return last_media_state_
; }
331 void TabChangedAt(content::WebContents
* contents
,
333 TabChangeType change_type
) override
{
334 const TabMediaState media_state
=
335 chrome::GetTabMediaStateForContents(contents
);
336 const bool has_changed
= media_state
!= last_media_state_
;
337 last_media_state_
= media_state
;
339 base::ThreadTaskRunnerHandle::Get()->PostTask(
340 FROM_HERE
, base::MessageLoop::QuitClosure());
345 TabMediaState last_media_state_
;
348 // Run the browser until the indicator turns on.
349 IndicatorChangeObserver
observer(browser());
350 browser()->tab_strip_model()->AddObserver(&observer
);
351 const base::TimeTicks start_time
= base::TimeTicks::Now();
352 while (observer
.last_media_state() != TAB_MEDIA_STATE_CAPTURING
) {
353 if (base::TimeTicks::Now() - start_time
>
354 base::TimeDelta::FromSeconds(10)) {
355 EXPECT_EQ(TAB_MEDIA_STATE_CAPTURING
, observer
.last_media_state());
356 browser()->tab_strip_model()->RemoveObserver(&observer
);
359 content::RunMessageLoop();
361 browser()->tab_strip_model()->RemoveObserver(&observer
);
366 } // namespace extensions