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 "chrome/browser/media/webrtc_browsertest_base.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/strings/stringprintf.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/infobars/infobar.h" 11 #include "chrome/browser/infobars/infobar_service.h" 12 #include "chrome/browser/media/media_stream_infobar_delegate.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/test/base/ui_test_utils.h" 18 #include "content/public/browser/notification_service.h" 19 #include "content/public/test/browser_test_utils.h" 20 21 const char WebRtcTestBase::kAudioVideoCallConstraints[] = 22 "'{audio: true, video: true}'"; 23 const char WebRtcTestBase::kAudioOnlyCallConstraints[] = "'{audio: true}'"; 24 const char WebRtcTestBase::kVideoOnlyCallConstraints[] = "'{video: true}'"; 25 const char WebRtcTestBase::kFailedWithPermissionDeniedError[] = 26 "failed-with-error-PermissionDeniedError"; 27 28 namespace { 29 30 base::LazyInstance<bool> hit_javascript_errors_ = 31 LAZY_INSTANCE_INITIALIZER; 32 33 // Intercepts all log messages. We always attach this handler but only look at 34 // the results if the test requests so. Note that this will only work if the 35 // WebrtcTestBase-inheriting test cases do not run in parallel (if they did they 36 // would race to look at the log, which is global to all tests). 37 bool JavascriptErrorDetectingLogHandler(int severity, 38 const char* file, 39 int line, 40 size_t message_start, 41 const std::string& str) { 42 if (file == NULL || std::string("CONSOLE") != file) 43 return false; 44 45 bool contains_uncaught = str.find("\"Uncaught ") != std::string::npos; 46 if (severity == logging::LOG_ERROR || 47 (severity == logging::LOG_INFO && contains_uncaught)) { 48 hit_javascript_errors_.Get() = true; 49 } 50 51 return false; 52 } 53 54 } // namespace 55 56 WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) { 57 // The handler gets set for each test method, but that's fine since this 58 // set operation is idempotent. 59 logging::SetLogMessageHandler(&JavascriptErrorDetectingLogHandler); 60 hit_javascript_errors_.Get() = false; 61 } 62 63 WebRtcTestBase::~WebRtcTestBase() { 64 if (detect_errors_in_javascript_) { 65 EXPECT_FALSE(hit_javascript_errors_.Get()) 66 << "Encountered javascript errors during test execution (Search " 67 << "for Uncaught or ERROR:CONSOLE in the test output)."; 68 } 69 } 70 71 void WebRtcTestBase::GetUserMediaAndAccept( 72 content::WebContents* tab_contents) const { 73 GetUserMediaWithSpecificConstraintsAndAccept(tab_contents, 74 kAudioVideoCallConstraints); 75 } 76 77 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept( 78 content::WebContents* tab_contents, 79 const std::string& constraints) const { 80 InfoBar* infobar = GetUserMediaAndWaitForInfoBar(tab_contents, constraints); 81 infobar->delegate()->AsConfirmInfoBarDelegate()->Accept(); 82 CloseInfoBarInTab(tab_contents, infobar); 83 84 // Wait for WebRTC to call the success callback. 85 const char kOkGotStream[] = "ok-got-stream"; 86 EXPECT_TRUE(PollingWaitUntil("obtainGetUserMediaResult()", kOkGotStream, 87 tab_contents)); 88 } 89 90 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents* tab_contents) { 91 return GetUserMediaWithSpecificConstraintsAndDeny(tab_contents, 92 kAudioVideoCallConstraints); 93 } 94 95 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny( 96 content::WebContents* tab_contents, 97 const std::string& constraints) const { 98 InfoBar* infobar = GetUserMediaAndWaitForInfoBar(tab_contents, constraints); 99 infobar->delegate()->AsConfirmInfoBarDelegate()->Cancel(); 100 CloseInfoBarInTab(tab_contents, infobar); 101 102 // Wait for WebRTC to call the fail callback. 103 EXPECT_TRUE(PollingWaitUntil("obtainGetUserMediaResult()", 104 kFailedWithPermissionDeniedError, tab_contents)); 105 } 106 107 void WebRtcTestBase::GetUserMediaAndDismiss( 108 content::WebContents* tab_contents) const { 109 InfoBar* infobar = 110 GetUserMediaAndWaitForInfoBar(tab_contents, kAudioVideoCallConstraints); 111 infobar->delegate()->InfoBarDismissed(); 112 CloseInfoBarInTab(tab_contents, infobar); 113 114 // A dismiss should be treated like a deny. 115 EXPECT_TRUE(PollingWaitUntil("obtainGetUserMediaResult()", 116 kFailedWithPermissionDeniedError, tab_contents)); 117 } 118 119 void WebRtcTestBase::GetUserMedia(content::WebContents* tab_contents, 120 const std::string& constraints) const { 121 // Request user media: this will launch the media stream info bar. 122 std::string result; 123 EXPECT_TRUE(content::ExecuteScriptAndExtractString( 124 tab_contents, "doGetUserMedia(" + constraints + ");", &result)); 125 EXPECT_EQ("ok-requested", result); 126 } 127 128 InfoBar* WebRtcTestBase::GetUserMediaAndWaitForInfoBar( 129 content::WebContents* tab_contents, 130 const std::string& constraints) const { 131 content::WindowedNotificationObserver infobar_added( 132 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, 133 content::NotificationService::AllSources()); 134 135 // Request user media: this will launch the media stream info bar. 136 GetUserMedia(tab_contents, constraints); 137 138 // Wait for the bar to pop up, then return it. 139 infobar_added.Wait(); 140 content::Details<InfoBar::AddedDetails> details(infobar_added.details()); 141 EXPECT_TRUE(details->delegate()->AsMediaStreamInfoBarDelegate()); 142 return details.ptr(); 143 } 144 145 content::WebContents* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab( 146 const GURL& url) const { 147 chrome::AddTabAt(browser(), GURL(), -1, true); 148 ui_test_utils::NavigateToURL(browser(), url); 149 #if defined (OS_LINUX) 150 // Load the page again on Linux to work around crbug.com/281268. 151 ui_test_utils::NavigateToURL(browser(), url); 152 #endif 153 content::WebContents* new_tab = 154 browser()->tab_strip_model()->GetActiveWebContents(); 155 GetUserMediaAndAccept(new_tab); 156 return new_tab; 157 } 158 159 content::WebContents* WebRtcTestBase::OpenPageAndAcceptUserMedia( 160 const GURL& url) const { 161 content::WindowedNotificationObserver infobar_added( 162 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, 163 content::NotificationService::AllSources()); 164 165 ui_test_utils::NavigateToURL(browser(), url); 166 167 infobar_added.Wait(); 168 169 content::WebContents* tab_contents = 170 browser()->tab_strip_model()->GetActiveWebContents(); 171 content::Details<InfoBar::AddedDetails> details(infobar_added.details()); 172 InfoBar* infobar = details.ptr(); 173 EXPECT_TRUE(infobar); 174 infobar->delegate()->AsMediaStreamInfoBarDelegate()->Accept(); 175 176 CloseInfoBarInTab(tab_contents, infobar); 177 return tab_contents; 178 } 179 180 void WebRtcTestBase::CloseInfoBarInTab( 181 content::WebContents* tab_contents, 182 InfoBar* infobar) const { 183 content::WindowedNotificationObserver infobar_removed( 184 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, 185 content::NotificationService::AllSources()); 186 187 InfoBarService* infobar_service = 188 InfoBarService::FromWebContents(tab_contents); 189 infobar_service->RemoveInfoBar(infobar); 190 191 infobar_removed.Wait(); 192 } 193 194 // Convenience method which executes the provided javascript in the context 195 // of the provided web contents and returns what it evaluated to. 196 std::string WebRtcTestBase::ExecuteJavascript( 197 const std::string& javascript, 198 content::WebContents* tab_contents) const { 199 std::string result; 200 EXPECT_TRUE(content::ExecuteScriptAndExtractString( 201 tab_contents, javascript, &result)); 202 return result; 203 } 204 205 // The peer connection server lets our two tabs find each other and talk to 206 // each other (e.g. it is the application-specific "signaling solution"). 207 void WebRtcTestBase::ConnectToPeerConnectionServer( 208 const std::string& peer_name, 209 content::WebContents* tab_contents) const { 210 std::string javascript = base::StringPrintf( 211 "connect('http://localhost:%s', '%s');", 212 PeerConnectionServerRunner::kDefaultPort, peer_name.c_str()); 213 EXPECT_EQ("ok-connected", ExecuteJavascript(javascript, tab_contents)); 214 } 215 216 void WebRtcTestBase::DetectErrorsInJavaScript() { 217 detect_errors_in_javascript_ = true; 218 } 219