| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 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 "build/build_config.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/infobars/infobar_responder.h" | |
| 14 #include "chrome/browser/infobars/infobar_service.h" | |
| 15 #include "chrome/browser/media/webrtc_browsertest_base.h" | |
| 16 #include "chrome/browser/media/webrtc_browsertest_common.h" | |
| 17 #include "chrome/browser/ui/browser.h" | |
| 18 #include "chrome/browser/ui/browser_tabstrip.h" | |
| 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 20 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h" | |
| 21 #include "chrome/common/chrome_switches.h" | |
| 22 #include "chrome/test/base/ui_test_utils.h" | |
| 23 #include "content/public/common/content_switches.h" | |
| 24 #include "content/public/test/browser_test_utils.h" | |
| 25 #include "media/base/media_switches.h" | |
| 26 #include "net/test/python_utils.h" | |
| 27 #include "ui/gl/gl_switches.h" | |
| 28 | |
| 29 const char kTitlePageOfAppEngineAdminPage[] = "Instances"; | |
| 30 | |
| 31 const char kIsApprtcCallUpJavascript[] = | |
| 32 "var remoteVideo = document.querySelector('#remote-video');" | |
| 33 "var remoteVideoActive =" | |
| 34 " remoteVideo != null &&" | |
| 35 " remoteVideo.classList.contains('active');" | |
| 36 "window.domAutomationController.send(remoteVideoActive.toString());"; | |
| 37 | |
| 38 | |
| 39 // WebRTC-AppRTC integration test. Requires a real webcam and microphone | |
| 40 // on the running system. This test is not meant to run in the main browser | |
| 41 // test suite since normal tester machines do not have webcams. Chrome will use | |
| 42 // its fake camera for both tests, but Firefox will use the real webcam in the | |
| 43 // Firefox interop test. Thus, this test must on a machine with a real webcam. | |
| 44 // | |
| 45 // This test will bring up a AppRTC instance on localhost and verify that the | |
| 46 // call gets up when connecting to the same room from two tabs in a browser. | |
| 47 class WebRtcApprtcBrowserTest : public WebRtcTestBase { | |
| 48 public: | |
| 49 WebRtcApprtcBrowserTest() {} | |
| 50 | |
| 51 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 52 EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream)); | |
| 53 | |
| 54 // The video playback will not work without a GPU, so force its use here. | |
| 55 command_line->AppendSwitch(switches::kUseGpuInTests); | |
| 56 base::CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 57 switches::kUseFakeDeviceForMediaStream); | |
| 58 } | |
| 59 | |
| 60 void TearDown() override { | |
| 61 // Kill any processes we may have brought up. Note: this isn't perfect, | |
| 62 // especially if the test hangs or if we're on Windows. | |
| 63 LOG(INFO) << "Entering TearDown"; | |
| 64 if (dev_appserver_.IsValid()) | |
| 65 dev_appserver_.Terminate(0, false); | |
| 66 if (collider_server_.IsValid()) | |
| 67 collider_server_.Terminate(0, false); | |
| 68 if (firefox_.IsValid()) | |
| 69 firefox_.Terminate(0, false); | |
| 70 LOG(INFO) << "Exiting TearDown"; | |
| 71 } | |
| 72 | |
| 73 protected: | |
| 74 bool LaunchApprtcInstanceOnLocalhost(const std::string& port) { | |
| 75 base::FilePath appengine_dev_appserver = | |
| 76 GetSourceDir().Append( | |
| 77 FILE_PATH_LITERAL("../google_appengine/dev_appserver.py")); | |
| 78 if (!base::PathExists(appengine_dev_appserver)) { | |
| 79 LOG(ERROR) << "Missing appengine sdk at " << | |
| 80 appengine_dev_appserver.value() << ".\n" << | |
| 81 test::kAdviseOnGclientSolution; | |
| 82 return false; | |
| 83 } | |
| 84 | |
| 85 base::FilePath apprtc_dir = | |
| 86 GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc/out/app_engine")); | |
| 87 if (!base::PathExists(apprtc_dir)) { | |
| 88 LOG(ERROR) << "Missing AppRTC AppEngine app at " << | |
| 89 apprtc_dir.value() << ".\n" << test::kAdviseOnGclientSolution; | |
| 90 return false; | |
| 91 } | |
| 92 if (!base::PathExists(apprtc_dir.Append(FILE_PATH_LITERAL("app.yaml")))) { | |
| 93 LOG(ERROR) << "The AppRTC AppEngine app at " << | |
| 94 apprtc_dir.value() << " appears to have not been built." << | |
| 95 "This should have been done by webrtc.DEPS scripts which invoke " << | |
| 96 "'grunt build' on AppRTC."; | |
| 97 return false; | |
| 98 } | |
| 99 | |
| 100 base::CommandLine command_line(base::CommandLine::NO_PROGRAM); | |
| 101 EXPECT_TRUE(GetPythonCommand(&command_line)); | |
| 102 | |
| 103 command_line.AppendArgPath(appengine_dev_appserver); | |
| 104 command_line.AppendArgPath(apprtc_dir); | |
| 105 command_line.AppendArg("--port=" + port); | |
| 106 command_line.AppendArg("--admin_port=9998"); | |
| 107 command_line.AppendArg("--skip_sdk_update_check"); | |
| 108 command_line.AppendArg("--clear_datastore=yes"); | |
| 109 | |
| 110 DVLOG(1) << "Running " << command_line.GetCommandLineString(); | |
| 111 dev_appserver_ = base::LaunchProcess(command_line, base::LaunchOptions()); | |
| 112 return dev_appserver_.IsValid(); | |
| 113 } | |
| 114 | |
| 115 bool LaunchColliderOnLocalHost(const std::string& apprtc_url, | |
| 116 const std::string& collider_port) { | |
| 117 // The go workspace should be created, and collidermain built, at the | |
| 118 // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs. | |
| 119 #if defined(OS_WIN) | |
| 120 base::FilePath collider_server = GetSourceDir().Append( | |
| 121 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe")); | |
| 122 #else | |
| 123 base::FilePath collider_server = GetSourceDir().Append( | |
| 124 FILE_PATH_LITERAL("out/go-workspace/bin/collidermain")); | |
| 125 #endif | |
| 126 if (!base::PathExists(collider_server)) { | |
| 127 LOG(ERROR) << "Missing Collider server binary at " << | |
| 128 collider_server.value() << ".\n" << test::kAdviseOnGclientSolution; | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 base::CommandLine command_line(collider_server); | |
| 133 | |
| 134 command_line.AppendArg("-tls=false"); | |
| 135 command_line.AppendArg("-port=" + collider_port); | |
| 136 command_line.AppendArg("-room-server=" + apprtc_url); | |
| 137 | |
| 138 DVLOG(1) << "Running " << command_line.GetCommandLineString(); | |
| 139 collider_server_ = base::LaunchProcess(command_line, base::LaunchOptions()); | |
| 140 return collider_server_.IsValid(); | |
| 141 } | |
| 142 | |
| 143 bool LocalApprtcInstanceIsUp() { | |
| 144 // Load the admin page and see if we manage to load it right. | |
| 145 ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998")); | |
| 146 content::WebContents* tab_contents = | |
| 147 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 148 std::string javascript = | |
| 149 "window.domAutomationController.send(document.title)"; | |
| 150 std::string result; | |
| 151 if (!content::ExecuteScriptAndExtractString(tab_contents, javascript, | |
| 152 &result)) | |
| 153 return false; | |
| 154 | |
| 155 return result == kTitlePageOfAppEngineAdminPage; | |
| 156 } | |
| 157 | |
| 158 bool WaitForCallToComeUp(content::WebContents* tab_contents) { | |
| 159 return test::PollingWaitUntil(kIsApprtcCallUpJavascript, "true", | |
| 160 tab_contents); | |
| 161 } | |
| 162 | |
| 163 bool EvalInJavascriptFile(content::WebContents* tab_contents, | |
| 164 const base::FilePath& path) { | |
| 165 std::string javascript; | |
| 166 if (!ReadFileToString(path, &javascript)) { | |
| 167 LOG(ERROR) << "Missing javascript code at " << path.value() << "."; | |
| 168 return false; | |
| 169 } | |
| 170 | |
| 171 if (!content::ExecuteScript(tab_contents, javascript)) { | |
| 172 LOG(ERROR) << "Failed to execute the following javascript: " << | |
| 173 javascript; | |
| 174 return false; | |
| 175 } | |
| 176 return true; | |
| 177 } | |
| 178 | |
| 179 bool DetectRemoteVideoPlaying(content::WebContents* tab_contents) { | |
| 180 if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append( | |
| 181 FILE_PATH_LITERAL("chrome/test/data/webrtc/test_functions.js")))) | |
| 182 return false; | |
| 183 if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append( | |
| 184 FILE_PATH_LITERAL("chrome/test/data/webrtc/video_detector.js")))) | |
| 185 return false; | |
| 186 | |
| 187 // The remote video tag is called remoteVideo in the AppRTC code. | |
| 188 StartDetectingVideo(tab_contents, "remote-video"); | |
| 189 WaitForVideoToPlay(tab_contents); | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 base::FilePath GetSourceDir() { | |
| 194 base::FilePath source_dir; | |
| 195 PathService::Get(base::DIR_SOURCE_ROOT, &source_dir); | |
| 196 return source_dir; | |
| 197 } | |
| 198 | |
| 199 bool LaunchFirefoxWithUrl(const GURL& url) { | |
| 200 base::FilePath firefox_binary = | |
| 201 GetSourceDir().Append( | |
| 202 FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox")); | |
| 203 if (!base::PathExists(firefox_binary)) { | |
| 204 LOG(ERROR) << "Missing firefox binary at " << | |
| 205 firefox_binary.value() << ".\n" << test::kAdviseOnGclientSolution; | |
| 206 return false; | |
| 207 } | |
| 208 base::FilePath firefox_launcher = | |
| 209 GetSourceDir().Append( | |
| 210 FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py")); | |
| 211 if (!base::PathExists(firefox_launcher)) { | |
| 212 LOG(ERROR) << "Missing firefox launcher at " << | |
| 213 firefox_launcher.value() << ".\n" << test::kAdviseOnGclientSolution; | |
| 214 return false; | |
| 215 } | |
| 216 | |
| 217 base::CommandLine command_line(firefox_launcher); | |
| 218 command_line.AppendSwitchPath("--binary", firefox_binary); | |
| 219 command_line.AppendSwitchASCII("--webpage", url.spec()); | |
| 220 | |
| 221 DVLOG(1) << "Running " << command_line.GetCommandLineString(); | |
| 222 firefox_ = base::LaunchProcess(command_line, base::LaunchOptions()); | |
| 223 return firefox_.IsValid(); | |
| 224 } | |
| 225 | |
| 226 private: | |
| 227 base::Process dev_appserver_; | |
| 228 base::Process firefox_; | |
| 229 base::Process collider_server_; | |
| 230 }; | |
| 231 | |
| 232 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, MANUAL_WorksOnApprtc) { | |
| 233 DetectErrorsInJavaScript(); | |
| 234 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999")); | |
| 235 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089")); | |
| 236 while (!LocalApprtcInstanceIsUp()) | |
| 237 DVLOG(1) << "Waiting for AppRTC to come up..."; | |
| 238 | |
| 239 GURL room_url = GURL("http://localhost:9999/r/some_room" | |
| 240 "?wshpp=localhost:8089&wstls=false"); | |
| 241 | |
| 242 // Set up the left tab. | |
| 243 chrome::AddTabAt(browser(), GURL(), -1, true); | |
| 244 content::WebContents* left_tab = | |
| 245 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 246 PermissionBubbleManager::FromWebContents(left_tab) | |
| 247 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL); | |
| 248 InfoBarResponder left_infobar_responder( | |
| 249 InfoBarService::FromWebContents(left_tab), InfoBarResponder::ACCEPT); | |
| 250 ui_test_utils::NavigateToURL(browser(), room_url); | |
| 251 | |
| 252 // Set up the right tab. | |
| 253 chrome::AddTabAt(browser(), GURL(), -1, true); | |
| 254 content::WebContents* right_tab = | |
| 255 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 256 PermissionBubbleManager::FromWebContents(right_tab) | |
| 257 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL); | |
| 258 InfoBarResponder right_infobar_responder( | |
| 259 InfoBarService::FromWebContents(right_tab), InfoBarResponder::ACCEPT); | |
| 260 ui_test_utils::NavigateToURL(browser(), room_url); | |
| 261 | |
| 262 ASSERT_TRUE(WaitForCallToComeUp(left_tab)); | |
| 263 ASSERT_TRUE(WaitForCallToComeUp(right_tab)); | |
| 264 | |
| 265 ASSERT_TRUE(DetectRemoteVideoPlaying(left_tab)); | |
| 266 ASSERT_TRUE(DetectRemoteVideoPlaying(right_tab)); | |
| 267 | |
| 268 chrome::CloseWebContents(browser(), left_tab, false); | |
| 269 chrome::CloseWebContents(browser(), right_tab, false); | |
| 270 } | |
| 271 | |
| 272 #if defined(OS_LINUX) | |
| 273 #define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest | |
| 274 #else | |
| 275 // Not implemented yet on Windows and Mac. | |
| 276 #define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInter
opTest | |
| 277 #endif | |
| 278 | |
| 279 IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, | |
| 280 MAYBE_MANUAL_FirefoxApprtcInteropTest) { | |
| 281 DetectErrorsInJavaScript(); | |
| 282 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999")); | |
| 283 ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089")); | |
| 284 while (!LocalApprtcInstanceIsUp()) | |
| 285 DVLOG(1) << "Waiting for AppRTC to come up..."; | |
| 286 | |
| 287 GURL room_url = GURL("http://localhost:9999/r/some_room" | |
| 288 "?wshpp=localhost:8089&wstls=false" | |
| 289 "&firefox_fake_device=1"); | |
| 290 chrome::AddTabAt(browser(), GURL(), -1, true); | |
| 291 content::WebContents* chrome_tab = | |
| 292 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 293 PermissionBubbleManager::FromWebContents(chrome_tab) | |
| 294 ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL); | |
| 295 InfoBarResponder infobar_responder( | |
| 296 InfoBarService::FromWebContents(chrome_tab), InfoBarResponder::ACCEPT); | |
| 297 ui_test_utils::NavigateToURL(browser(), room_url); | |
| 298 | |
| 299 ASSERT_TRUE(LaunchFirefoxWithUrl(room_url)); | |
| 300 | |
| 301 ASSERT_TRUE(WaitForCallToComeUp(chrome_tab)); | |
| 302 | |
| 303 // Ensure Firefox manages to send video our way. | |
| 304 ASSERT_TRUE(DetectRemoteVideoPlaying(chrome_tab)); | |
| 305 } | |
| OLD | NEW |