1 // Copyright 2013 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/files/file_enumerator.h"
7 #include "base/path_service.h"
8 #include "base/process/launch.h"
9 #include "base/rand_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/infobars/infobar_responder.h"
13 #include "chrome/browser/infobars/infobar_service.h"
14 #include "chrome/browser/media/webrtc_browsertest_base.h"
15 #include "chrome/browser/media/webrtc_browsertest_common.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tabstrip.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "media/base/media_switches.h"
24 #include "net/test/python_utils.h"
25 #include "ui/gl/gl_switches.h"
27 // You need this solution to run this test. The solution will download appengine
28 // and the apprtc code for you.
29 const char kAdviseOnGclientSolution
[] =
30 "You need to add this solution to your .gclient to run this test:\n"
32 " \"name\" : \"webrtc.DEPS\",\n"
33 " \"url\" : \"https://chromium.googlesource.com/chromium/deps/"
34 "webrtc/webrtc.DEPS\",\n"
36 const char kTitlePageOfAppEngineAdminPage
[] = "Instances";
38 const char kIsApprtcCallUpJavascript
[] =
39 "var remoteVideo = document.querySelector('#remote-video');"
40 "var remoteVideoActive ="
41 " remoteVideo != null &&"
42 " remoteVideo.classList.contains('active');"
43 "window.domAutomationController.send(remoteVideoActive.toString());";
46 // WebRTC-AppRTC integration test. Requires a real webcam and microphone
47 // on the running system. This test is not meant to run in the main browser
48 // test suite since normal tester machines do not have webcams. Chrome will use
49 // its fake camera for both tests, but Firefox will use the real webcam in the
50 // Firefox interop test. Thus, this test must on a machine with a real webcam.
52 // This test will bring up a AppRTC instance on localhost and verify that the
53 // call gets up when connecting to the same room from two tabs in a browser.
54 class WebRtcApprtcBrowserTest
: public WebRtcTestBase
{
56 WebRtcApprtcBrowserTest() {}
58 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
59 EXPECT_FALSE(command_line
->HasSwitch(switches::kUseFakeUIForMediaStream
));
61 // The video playback will not work without a GPU, so force its use here.
62 command_line
->AppendSwitch(switches::kUseGpuInTests
);
63 base::CommandLine::ForCurrentProcess()->AppendSwitch(
64 switches::kUseFakeDeviceForMediaStream
);
67 void TearDown() override
{
68 // Kill any processes we may have brought up. Note: this isn't perfect,
69 // especially if the test hangs or if we're on Windows.
70 LOG(INFO
) << "Entering TearDown";
71 if (dev_appserver_
.IsValid())
72 dev_appserver_
.Terminate(0, false);
73 if (collider_server_
.IsValid())
74 collider_server_
.Terminate(0, false);
75 if (firefox_
.IsValid())
76 firefox_
.Terminate(0, false);
77 LOG(INFO
) << "Exiting TearDown";
81 bool LaunchApprtcInstanceOnLocalhost(const std::string
& port
) {
82 base::FilePath appengine_dev_appserver
=
83 GetSourceDir().Append(
84 FILE_PATH_LITERAL("../google_appengine/dev_appserver.py"));
85 if (!base::PathExists(appengine_dev_appserver
)) {
86 LOG(ERROR
) << "Missing appengine sdk at " <<
87 appengine_dev_appserver
.value() << ". " << kAdviseOnGclientSolution
;
91 base::FilePath apprtc_dir
=
92 GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc/out/app_engine"));
93 if (!base::PathExists(apprtc_dir
)) {
94 LOG(ERROR
) << "Missing AppRTC AppEngine app at " <<
95 apprtc_dir
.value() << ". " << kAdviseOnGclientSolution
;
98 if (!base::PathExists(apprtc_dir
.Append(FILE_PATH_LITERAL("app.yaml")))) {
99 LOG(ERROR
) << "The AppRTC AppEngine app at " <<
100 apprtc_dir
.value() << " appears to have not been built." <<
101 "This should have been done by webrtc.DEPS scripts which invoke " <<
102 "'grunt build' on AppRTC.";
106 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
107 EXPECT_TRUE(GetPythonCommand(&command_line
));
109 command_line
.AppendArgPath(appengine_dev_appserver
);
110 command_line
.AppendArgPath(apprtc_dir
);
111 command_line
.AppendArg("--port=" + port
);
112 command_line
.AppendArg("--admin_port=9998");
113 command_line
.AppendArg("--skip_sdk_update_check");
114 command_line
.AppendArg("--clear_datastore=yes");
116 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
117 dev_appserver_
= base::LaunchProcess(command_line
, base::LaunchOptions());
118 return dev_appserver_
.IsValid();
121 bool LaunchColliderOnLocalHost(const std::string
& apprtc_url
,
122 const std::string
& collider_port
) {
123 // The go workspace should be created, and collidermain built, at the
124 // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
126 base::FilePath collider_server
= GetSourceDir().Append(
127 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe"));
129 base::FilePath collider_server
= GetSourceDir().Append(
130 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain"));
132 if (!base::PathExists(collider_server
)) {
133 LOG(ERROR
) << "Missing Collider server binary at " <<
134 collider_server
.value() << ". " << kAdviseOnGclientSolution
;
138 base::CommandLine
command_line(collider_server
);
140 command_line
.AppendArg("-tls=false");
141 command_line
.AppendArg("-port=" + collider_port
);
142 command_line
.AppendArg("-room-server=" + apprtc_url
);
144 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
145 collider_server_
= base::LaunchProcess(command_line
, base::LaunchOptions());
146 return collider_server_
.IsValid();
149 bool LocalApprtcInstanceIsUp() {
150 // Load the admin page and see if we manage to load it right.
151 ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998"));
152 content::WebContents
* tab_contents
=
153 browser()->tab_strip_model()->GetActiveWebContents();
154 std::string javascript
=
155 "window.domAutomationController.send(document.title)";
157 if (!content::ExecuteScriptAndExtractString(tab_contents
, javascript
,
161 return result
== kTitlePageOfAppEngineAdminPage
;
164 bool WaitForCallToComeUp(content::WebContents
* tab_contents
) {
165 return test::PollingWaitUntil(kIsApprtcCallUpJavascript
, "true",
169 bool EvalInJavascriptFile(content::WebContents
* tab_contents
,
170 const base::FilePath
& path
) {
171 std::string javascript
;
172 if (!ReadFileToString(path
, &javascript
)) {
173 LOG(ERROR
) << "Missing javascript code at " << path
.value() << ".";
177 if (!content::ExecuteScript(tab_contents
, javascript
)) {
178 LOG(ERROR
) << "Failed to execute the following javascript: " <<
185 bool DetectRemoteVideoPlaying(content::WebContents
* tab_contents
) {
186 if (!EvalInJavascriptFile(tab_contents
, GetSourceDir().Append(
187 FILE_PATH_LITERAL("chrome/test/data/webrtc/test_functions.js"))))
189 if (!EvalInJavascriptFile(tab_contents
, GetSourceDir().Append(
190 FILE_PATH_LITERAL("chrome/test/data/webrtc/video_detector.js"))))
193 // The remote video tag is called remoteVideo in the AppRTC code.
194 StartDetectingVideo(tab_contents
, "remote-video");
195 WaitForVideoToPlay(tab_contents
);
199 base::FilePath
GetSourceDir() {
200 base::FilePath source_dir
;
201 PathService::Get(base::DIR_SOURCE_ROOT
, &source_dir
);
205 bool LaunchFirefoxWithUrl(const GURL
& url
) {
206 base::FilePath firefox_binary
=
207 GetSourceDir().Append(
208 FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox"));
209 if (!base::PathExists(firefox_binary
)) {
210 LOG(ERROR
) << "Missing firefox binary at " <<
211 firefox_binary
.value() << ". " << kAdviseOnGclientSolution
;
214 base::FilePath firefox_launcher
=
215 GetSourceDir().Append(
216 FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py"));
217 if (!base::PathExists(firefox_launcher
)) {
218 LOG(ERROR
) << "Missing firefox launcher at " <<
219 firefox_launcher
.value() << ". " << kAdviseOnGclientSolution
;
223 base::CommandLine
command_line(firefox_launcher
);
224 command_line
.AppendSwitchPath("--binary", firefox_binary
);
225 command_line
.AppendSwitchASCII("--webpage", url
.spec());
227 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
228 firefox_
= base::LaunchProcess(command_line
, base::LaunchOptions());
229 return firefox_
.IsValid();
233 base::Process dev_appserver_
;
234 base::Process firefox_
;
235 base::Process collider_server_
;
238 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest
, MANUAL_WorksOnApprtc
) {
239 // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
243 DetectErrorsInJavaScript();
244 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
245 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
246 while (!LocalApprtcInstanceIsUp())
247 DVLOG(1) << "Waiting for AppRTC to come up...";
249 GURL room_url
= GURL("http://localhost:9999/r/some_room"
250 "?wshpp=localhost:8089&wstls=false");
252 // Set up the left tab.
253 chrome::AddTabAt(browser(), GURL(), -1, true);
254 content::WebContents
* left_tab
=
255 browser()->tab_strip_model()->GetActiveWebContents();
256 PermissionBubbleManager::FromWebContents(left_tab
)
257 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL
);
258 InfoBarResponder
left_infobar_responder(
259 InfoBarService::FromWebContents(left_tab
), InfoBarResponder::ACCEPT
);
260 ui_test_utils::NavigateToURL(browser(), room_url
);
262 // Set up the right tab.
263 chrome::AddTabAt(browser(), GURL(), -1, true);
264 content::WebContents
* right_tab
=
265 browser()->tab_strip_model()->GetActiveWebContents();
266 PermissionBubbleManager::FromWebContents(right_tab
)
267 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL
);
268 InfoBarResponder
right_infobar_responder(
269 InfoBarService::FromWebContents(right_tab
), InfoBarResponder::ACCEPT
);
270 ui_test_utils::NavigateToURL(browser(), room_url
);
272 ASSERT_TRUE(WaitForCallToComeUp(left_tab
));
273 ASSERT_TRUE(WaitForCallToComeUp(right_tab
));
275 ASSERT_TRUE(DetectRemoteVideoPlaying(left_tab
));
276 ASSERT_TRUE(DetectRemoteVideoPlaying(right_tab
));
278 chrome::CloseWebContents(browser(), left_tab
, false);
279 chrome::CloseWebContents(browser(), right_tab
, false);
282 #if defined(OS_LINUX)
283 #define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest
285 // Not implemented yet on Windows and Mac.
286 #define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest
289 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest
,
290 MAYBE_MANUAL_FirefoxApprtcInteropTest
) {
291 // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
295 DetectErrorsInJavaScript();
296 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
297 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
298 while (!LocalApprtcInstanceIsUp())
299 DVLOG(1) << "Waiting for AppRTC to come up...";
301 GURL room_url
= GURL("http://localhost:9999/r/some_room"
302 "?wshpp=localhost:8089&wstls=false"
303 "&firefox_fake_device=1");
304 chrome::AddTabAt(browser(), GURL(), -1, true);
305 content::WebContents
* chrome_tab
=
306 browser()->tab_strip_model()->GetActiveWebContents();
307 PermissionBubbleManager::FromWebContents(chrome_tab
)
308 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL
);
309 InfoBarResponder
infobar_responder(
310 InfoBarService::FromWebContents(chrome_tab
), InfoBarResponder::ACCEPT
);
311 ui_test_utils::NavigateToURL(browser(), room_url
);
313 ASSERT_TRUE(LaunchFirefoxWithUrl(room_url
));
315 ASSERT_TRUE(WaitForCallToComeUp(chrome_tab
));
317 // Ensure Firefox manages to send video our way.
318 ASSERT_TRUE(DetectRemoteVideoPlaying(chrome_tab
));