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/path_service.h" 7 #include "base/process/launch.h" 8 #include "base/rand_util.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/win/windows_version.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 "chrome/test/ui/ui_test.h" 20 #include "content/public/test/browser_test_utils.h" 21 #include "media/base/media_switches.h" 22 #include "net/test/python_utils.h" 23 24 25 // You need this solution to run this test. The solution will download appengine 26 // and the apprtc code for you. 27 const char kAdviseOnGclientSolution[] = 28 "You need to add this solution to your .gclient to run this test:\n" 29 "{\n" 30 " \"name\" : \"webrtc.DEPS\",\n" 31 " \"url\" : \"svn://svn.chromium.org/chrome/trunk/deps/" 32 "third_party/webrtc/webrtc.DEPS\",\n" 33 "}"; 34 const char kTitlePageOfAppEngineAdminPage[] = "Instances"; 35 36 37 // WebRTC-AppRTC integration test. Requires a real webcam and microphone 38 // on the running system. This test is not meant to run in the main browser 39 // test suite since normal tester machines do not have webcams. Chrome will use 40 // this camera for the regular AppRTC test whereas Firefox will use it in the 41 // Firefox interop test (where case Chrome will use its built-in fake device). 42 // 43 // This test will bring up a AppRTC instance on localhost and verify that the 44 // call gets up when connecting to the same room from two tabs in a browser. 45 class WebrtcApprtcBrowserTest : public WebRtcTestBase { 46 public: 47 WebrtcApprtcBrowserTest() 48 : dev_appserver_(base::kNullProcessHandle), 49 firefox_(base::kNullProcessHandle) { 50 } 51 52 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 53 EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream)); 54 55 // The video playback will not work without a GPU, so force its use here. 56 command_line->AppendSwitch(switches::kUseGpuInTests); 57 } 58 59 virtual void TearDown() OVERRIDE { 60 // Kill any processes we may have brought up. 61 if (dev_appserver_ != base::kNullProcessHandle) 62 base::KillProcess(dev_appserver_, 0, false); 63 // TODO(phoglund): Find some way to shut down Firefox cleanly on Windows. 64 if (firefox_ != base::kNullProcessHandle) 65 base::KillProcess(firefox_, 0, false); 66 } 67 68 protected: 69 bool LaunchApprtcInstanceOnLocalhost() { 70 base::FilePath appengine_dev_appserver = 71 GetSourceDir().Append( 72 FILE_PATH_LITERAL("../google_appengine/dev_appserver.py")); 73 if (!base::PathExists(appengine_dev_appserver)) { 74 LOG(ERROR) << "Missing appengine sdk at " << 75 appengine_dev_appserver.value() << ". " << kAdviseOnGclientSolution; 76 return false; 77 } 78 79 base::FilePath apprtc_dir = 80 GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc")); 81 if (!base::PathExists(apprtc_dir)) { 82 LOG(ERROR) << "Missing AppRTC code at " << 83 apprtc_dir.value() << ". " << kAdviseOnGclientSolution; 84 return false; 85 } 86 87 CommandLine command_line(CommandLine::NO_PROGRAM); 88 EXPECT_TRUE(GetPythonCommand(&command_line)); 89 90 command_line.AppendArgPath(appengine_dev_appserver); 91 command_line.AppendArgPath(apprtc_dir); 92 command_line.AppendArg("--port=9999"); 93 command_line.AppendArg("--admin_port=9998"); 94 command_line.AppendArg("--skip_sdk_update_check"); 95 96 VLOG(1) << "Running " << command_line.GetCommandLineString(); 97 return base::LaunchProcess(command_line, base::LaunchOptions(), 98 &dev_appserver_); 99 } 100 101 bool LocalApprtcInstanceIsUp() { 102 // Load the admin page and see if we manage to load it right. 103 ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998")); 104 content::WebContents* tab_contents = 105 browser()->tab_strip_model()->GetActiveWebContents(); 106 std::string javascript = 107 "window.domAutomationController.send(document.title)"; 108 std::string result; 109 if (!content::ExecuteScriptAndExtractString(tab_contents, javascript, 110 &result)) 111 return false; 112 113 return result == kTitlePageOfAppEngineAdminPage; 114 } 115 116 bool WaitForCallToComeUp(content::WebContents* tab_contents) { 117 // Apprtc will set remoteVideo.style.opacity to 1 when the call comes up. 118 std::string javascript = 119 "window.domAutomationController.send(remoteVideo.style.opacity)"; 120 return PollingWaitUntil(javascript, "1", tab_contents); 121 } 122 123 base::FilePath GetSourceDir() { 124 base::FilePath source_dir; 125 PathService::Get(base::DIR_SOURCE_ROOT, &source_dir); 126 return source_dir; 127 } 128 129 bool LaunchFirefoxWithUrl(const GURL& url) { 130 base::FilePath firefox_binary = 131 GetSourceDir().Append( 132 FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox")); 133 if (!base::PathExists(firefox_binary)) { 134 LOG(ERROR) << "Missing firefox binary at " << 135 firefox_binary.value() << ". " << kAdviseOnGclientSolution; 136 return false; 137 } 138 base::FilePath firefox_launcher = 139 GetSourceDir().Append( 140 FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py")); 141 if (!base::PathExists(firefox_launcher)) { 142 LOG(ERROR) << "Missing firefox launcher at " << 143 firefox_launcher.value() << ". " << kAdviseOnGclientSolution; 144 return false; 145 } 146 147 CommandLine command_line(firefox_launcher); 148 command_line.AppendSwitchPath("--binary", firefox_binary); 149 command_line.AppendSwitchASCII("--webpage", url.spec()); 150 151 VLOG(1) << "Running " << command_line.GetCommandLineString(); 152 return base::LaunchProcess(command_line, base::LaunchOptions(), 153 &firefox_); 154 155 return true; 156 } 157 158 private: 159 base::ProcessHandle dev_appserver_; 160 base::ProcessHandle firefox_; 161 }; 162 163 IN_PROC_BROWSER_TEST_F(WebrtcApprtcBrowserTest, MANUAL_WorksOnApprtc) { 164 // TODO(mcasas): Remove Win version filtering when this bug gets fixed: 165 // http://code.google.com/p/webrtc/issues/detail?id=2703 166 #if defined(OS_WIN) 167 if (base::win::GetVersion() < base::win::VERSION_VISTA) 168 return; 169 #endif 170 DetectErrorsInJavaScript(); 171 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost()); 172 while (!LocalApprtcInstanceIsUp()) 173 VLOG(1) << "Waiting for AppRTC to come up..."; 174 175 GURL room_url = GURL(base::StringPrintf("localhost:9999?r=room_%d", 176 base::RandInt(0, 65536))); 177 178 chrome::AddTabAt(browser(), GURL(), -1, true); 179 content::WebContents* left_tab = OpenPageAndAcceptUserMedia(room_url); 180 // TODO(phoglund): Remove when this bug gets fixed: 181 // http://code.google.com/p/webrtc/issues/detail?id=1742 182 SleepInJavascript(left_tab, 5000); 183 chrome::AddTabAt(browser(), GURL(), -1, true); 184 content::WebContents* right_tab = OpenPageAndAcceptUserMedia(room_url); 185 186 ASSERT_TRUE(WaitForCallToComeUp(left_tab)); 187 ASSERT_TRUE(WaitForCallToComeUp(right_tab)); 188 } 189 190 #if defined(OS_LINUX) 191 #define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest 192 #else 193 // Not implemented yet on Windows and Mac. 194 #define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest 195 #endif 196 197 IN_PROC_BROWSER_TEST_F(WebrtcApprtcBrowserTest, 198 MAYBE_MANUAL_FirefoxApprtcInteropTest) { 199 // TODO(mcasas): Remove Win version filtering when this bug gets fixed: 200 // http://code.google.com/p/webrtc/issues/detail?id=2703 201 #if defined(OS_WIN) 202 if (base::win::GetVersion() < base::win::VERSION_VISTA) 203 return; 204 #endif 205 206 DetectErrorsInJavaScript(); 207 ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost()); 208 while (!LocalApprtcInstanceIsUp()) 209 VLOG(1) << "Waiting for AppRTC to come up..."; 210 211 // Run Chrome with a fake device to avoid having the browsers fight over the 212 // camera (we'll just give that to firefox here). 213 CommandLine::ForCurrentProcess()->AppendSwitch( 214 switches::kUseFakeDeviceForMediaStream); 215 216 GURL room_url = GURL(base::StringPrintf("http://localhost:9999?r=room_%d", 217 base::RandInt(0, 65536))); 218 content::WebContents* chrome_tab = OpenPageAndAcceptUserMedia(room_url); 219 220 // TODO(phoglund): Remove when this bug gets fixed: 221 // http://code.google.com/p/webrtc/issues/detail?id=1742 222 SleepInJavascript(chrome_tab, 5000); 223 224 ASSERT_TRUE(LaunchFirefoxWithUrl(room_url)); 225 226 ASSERT_TRUE(WaitForCallToComeUp(chrome_tab)); 227 } 228