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/media/webrtc_browsertest_base.h"
13 #include "chrome/browser/media/webrtc_browsertest_common.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_tabstrip.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "content/public/test/browser_test_utils.h"
20 #include "media/base/media_switches.h"
21 #include "net/test/python_utils.h"
22 #include "ui/gl/gl_switches.h"
24 // You need this solution to run this test. The solution will download appengine
25 // and the apprtc code for you.
26 const char kAdviseOnGclientSolution
[] =
27 "You need to add this solution to your .gclient to run this test:\n"
29 " \"name\" : \"webrtc.DEPS\",\n"
30 " \"url\" : \"https://chromium.googlesource.com/chromium/deps/"
31 "webrtc/webrtc.DEPS\",\n"
33 const char kTitlePageOfAppEngineAdminPage
[] = "Instances";
35 const char kIsApprtcCallUpJavascript
[] =
36 "var remoteVideo = document.querySelector('#remote-video');"
37 "var remoteVideoActive ="
38 " remoteVideo != null &&"
39 " remoteVideo.classList.contains('active');"
40 "window.domAutomationController.send(remoteVideoActive.toString());";
43 // WebRTC-AppRTC integration test. Requires a real webcam and microphone
44 // on the running system. This test is not meant to run in the main browser
45 // test suite since normal tester machines do not have webcams. Chrome will use
46 // its fake camera for both tests, but Firefox will use the real webcam in the
47 // Firefox interop test. Thus, this test must on a machine with a real webcam.
49 // This test will bring up a AppRTC instance on localhost and verify that the
50 // call gets up when connecting to the same room from two tabs in a browser.
51 class WebRtcApprtcBrowserTest
: public WebRtcTestBase
{
53 WebRtcApprtcBrowserTest() {}
55 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
56 EXPECT_FALSE(command_line
->HasSwitch(switches::kUseFakeUIForMediaStream
));
58 // The video playback will not work without a GPU, so force its use here.
59 command_line
->AppendSwitch(switches::kUseGpuInTests
);
60 base::CommandLine::ForCurrentProcess()->AppendSwitch(
61 switches::kUseFakeDeviceForMediaStream
);
64 void TearDown() override
{
65 // Kill any processes we may have brought up. Note: this isn't perfect,
66 // especially if the test hangs or if we're on Windows.
67 LOG(INFO
) << "Entering TearDown";
68 if (dev_appserver_
.IsValid())
69 dev_appserver_
.Terminate(0, false);
70 if (collider_server_
.IsValid())
71 collider_server_
.Terminate(0, false);
72 if (firefox_
.IsValid())
73 firefox_
.Terminate(0, false);
74 LOG(INFO
) << "Exiting TearDown";
78 bool LaunchApprtcInstanceOnLocalhost(const std::string
& port
) {
79 base::FilePath appengine_dev_appserver
=
80 GetSourceDir().Append(
81 FILE_PATH_LITERAL("../google_appengine/dev_appserver.py"));
82 if (!base::PathExists(appengine_dev_appserver
)) {
83 LOG(ERROR
) << "Missing appengine sdk at " <<
84 appengine_dev_appserver
.value() << ". " << kAdviseOnGclientSolution
;
88 base::FilePath apprtc_dir
=
89 GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc/out/app_engine"));
90 if (!base::PathExists(apprtc_dir
)) {
91 LOG(ERROR
) << "Missing AppRTC AppEngine app at " <<
92 apprtc_dir
.value() << ". " << kAdviseOnGclientSolution
;
95 if (!base::PathExists(apprtc_dir
.Append(FILE_PATH_LITERAL("app.yaml")))) {
96 LOG(ERROR
) << "The AppRTC AppEngine app at " <<
97 apprtc_dir
.value() << " appears to have not been built." <<
98 "This should have been done by webrtc.DEPS scripts which invoke " <<
99 "'grunt build' on AppRTC.";
103 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
104 EXPECT_TRUE(GetPythonCommand(&command_line
));
106 command_line
.AppendArgPath(appengine_dev_appserver
);
107 command_line
.AppendArgPath(apprtc_dir
);
108 command_line
.AppendArg("--port=" + port
);
109 command_line
.AppendArg("--admin_port=9998");
110 command_line
.AppendArg("--skip_sdk_update_check");
111 command_line
.AppendArg("--clear_datastore=yes");
113 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
114 dev_appserver_
= base::LaunchProcess(command_line
, base::LaunchOptions());
115 return dev_appserver_
.IsValid();
118 bool LaunchColliderOnLocalHost(const std::string
& apprtc_url
,
119 const std::string
& collider_port
) {
120 // The go workspace should be created, and collidermain built, at the
121 // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
123 base::FilePath collider_server
= GetSourceDir().Append(
124 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe"));
126 base::FilePath collider_server
= GetSourceDir().Append(
127 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain"));
129 if (!base::PathExists(collider_server
)) {
130 LOG(ERROR
) << "Missing Collider server binary at " <<
131 collider_server
.value() << ". " << kAdviseOnGclientSolution
;
135 base::CommandLine
command_line(collider_server
);
137 command_line
.AppendArg("-tls=false");
138 command_line
.AppendArg("-port=" + collider_port
);
139 command_line
.AppendArg("-room-server=" + apprtc_url
);
141 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
142 collider_server_
= base::LaunchProcess(command_line
, base::LaunchOptions());
143 return collider_server_
.IsValid();
146 bool LocalApprtcInstanceIsUp() {
147 // Load the admin page and see if we manage to load it right.
148 ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998"));
149 content::WebContents
* tab_contents
=
150 browser()->tab_strip_model()->GetActiveWebContents();
151 std::string javascript
=
152 "window.domAutomationController.send(document.title)";
154 if (!content::ExecuteScriptAndExtractString(tab_contents
, javascript
,
158 return result
== kTitlePageOfAppEngineAdminPage
;
161 bool WaitForCallToComeUp(content::WebContents
* tab_contents
) {
162 return test::PollingWaitUntil(kIsApprtcCallUpJavascript
, "true",
166 bool EvalInJavascriptFile(content::WebContents
* tab_contents
,
167 const base::FilePath
& path
) {
168 std::string javascript
;
169 if (!ReadFileToString(path
, &javascript
)) {
170 LOG(ERROR
) << "Missing javascript code at " << path
.value() << ".";
174 if (!content::ExecuteScript(tab_contents
, javascript
)) {
175 LOG(ERROR
) << "Failed to execute the following javascript: " <<
182 bool DetectRemoteVideoPlaying(content::WebContents
* tab_contents
) {
183 if (!EvalInJavascriptFile(tab_contents
, GetSourceDir().Append(
184 FILE_PATH_LITERAL("chrome/test/data/webrtc/test_functions.js"))))
186 if (!EvalInJavascriptFile(tab_contents
, GetSourceDir().Append(
187 FILE_PATH_LITERAL("chrome/test/data/webrtc/video_detector.js"))))
190 // The remote video tag is called remoteVideo in the AppRTC code.
191 StartDetectingVideo(tab_contents
, "remote-video");
192 WaitForVideoToPlay(tab_contents
);
196 base::FilePath
GetSourceDir() {
197 base::FilePath source_dir
;
198 PathService::Get(base::DIR_SOURCE_ROOT
, &source_dir
);
202 bool LaunchFirefoxWithUrl(const GURL
& url
) {
203 base::FilePath firefox_binary
=
204 GetSourceDir().Append(
205 FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox"));
206 if (!base::PathExists(firefox_binary
)) {
207 LOG(ERROR
) << "Missing firefox binary at " <<
208 firefox_binary
.value() << ". " << kAdviseOnGclientSolution
;
211 base::FilePath firefox_launcher
=
212 GetSourceDir().Append(
213 FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py"));
214 if (!base::PathExists(firefox_launcher
)) {
215 LOG(ERROR
) << "Missing firefox launcher at " <<
216 firefox_launcher
.value() << ". " << kAdviseOnGclientSolution
;
220 base::CommandLine
command_line(firefox_launcher
);
221 command_line
.AppendSwitchPath("--binary", firefox_binary
);
222 command_line
.AppendSwitchASCII("--webpage", url
.spec());
224 DVLOG(1) << "Running " << command_line
.GetCommandLineString();
225 firefox_
= base::LaunchProcess(command_line
, base::LaunchOptions());
226 return firefox_
.IsValid();
230 base::Process dev_appserver_
;
231 base::Process firefox_
;
232 base::Process collider_server_
;
235 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest
, MANUAL_WorksOnApprtc
) {
236 // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
240 DetectErrorsInJavaScript();
241 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
242 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
243 while (!LocalApprtcInstanceIsUp())
244 DVLOG(1) << "Waiting for AppRTC to come up...";
246 GURL room_url
= GURL("http://localhost:9999/r/some_room"
247 "?wshpp=localhost:8089&wstls=false");
249 chrome::AddTabAt(browser(), GURL(), -1, true);
250 content::WebContents
* left_tab
= OpenPageAndAcceptUserMedia(room_url
);
252 chrome::AddTabAt(browser(), GURL(), -1, true);
253 content::WebContents
* right_tab
= OpenPageAndAcceptUserMedia(room_url
);
255 ASSERT_TRUE(WaitForCallToComeUp(left_tab
));
256 ASSERT_TRUE(WaitForCallToComeUp(right_tab
));
258 ASSERT_TRUE(DetectRemoteVideoPlaying(left_tab
));
259 ASSERT_TRUE(DetectRemoteVideoPlaying(right_tab
));
261 chrome::CloseWebContents(browser(), left_tab
, false);
262 chrome::CloseWebContents(browser(), right_tab
, false);
265 #if defined(OS_LINUX)
266 #define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest
268 // Not implemented yet on Windows and Mac.
269 #define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest
272 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest
,
273 MAYBE_MANUAL_FirefoxApprtcInteropTest
) {
274 // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
278 DetectErrorsInJavaScript();
279 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
280 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
281 while (!LocalApprtcInstanceIsUp())
282 DVLOG(1) << "Waiting for AppRTC to come up...";
284 GURL room_url
= GURL("http://localhost:9999/r/some_room"
285 "?wshpp=localhost:8089&wstls=false"
286 "&firefox_fake_device=1");
287 content::WebContents
* chrome_tab
= OpenPageAndAcceptUserMedia(room_url
);
289 ASSERT_TRUE(LaunchFirefoxWithUrl(room_url
));
291 ASSERT_TRUE(WaitForCallToComeUp(chrome_tab
));
293 // Ensure Firefox manages to send video our way.
294 ASSERT_TRUE(DetectRemoteVideoPlaying(chrome_tab
));