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 "chrome/browser/media/webrtc_browsertest_base.h"
7 #include "base/lazy_instance.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/chrome_notification_types.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 "components/infobars/core/infobar.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "net/test/embedded_test_server/embedded_test_server.h"
24 // For fine-grained suppression.
25 #include "base/win/windows_version.h"
28 const char WebRtcTestBase::kAudioVideoCallConstraints
[] =
29 "{audio: true, video: true}";
30 const char WebRtcTestBase::kVideoCallConstraintsQVGA
[] =
31 "{video: {mandatory: {minWidth: 320, maxWidth: 320, "
32 " minHeight: 240, maxHeight: 240}}}";
33 const char WebRtcTestBase::kVideoCallConstraints360p
[] =
34 "{video: {mandatory: {minWidth: 640, maxWidth: 640, "
35 " minHeight: 360, maxHeight: 360}}}";
36 const char WebRtcTestBase::kVideoCallConstraintsVGA
[] =
37 "{video: {mandatory: {minWidth: 640, maxWidth: 640, "
38 " minHeight: 480, maxHeight: 480}}}";
39 const char WebRtcTestBase::kVideoCallConstraints720p
[] =
40 "{video: {mandatory: {minWidth: 1280, maxWidth: 1280, "
41 " minHeight: 720, maxHeight: 720}}}";
42 const char WebRtcTestBase::kVideoCallConstraints1080p
[] =
43 "{video: {mandatory: {minWidth: 1920, maxWidth: 1920, "
44 " minHeight: 1080, maxHeight: 1080}}}";
45 const char WebRtcTestBase::kAudioOnlyCallConstraints
[] = "{audio: true}";
46 const char WebRtcTestBase::kVideoOnlyCallConstraints
[] = "{video: true}";
47 const char WebRtcTestBase::kFailedWithPermissionDeniedError
[] =
48 "failed-with-error-PermissionDeniedError";
49 const char WebRtcTestBase::kFailedWithPermissionDismissedError
[] =
50 "failed-with-error-PermissionDismissedError";
51 const char WebRtcTestBase::kAudioVideoCallConstraints360p
[] =
52 "{audio: true, video: {mandatory: {minWidth: 640, maxWidth: 640, "
53 " minHeight: 360, maxHeight: 360}}}";
54 const char WebRtcTestBase::kAudioVideoCallConstraints720p
[] =
55 "{audio: true, video: {mandatory: {minWidth: 1280, maxWidth: 1280, "
56 " minHeight: 720, maxHeight: 720}}}";
60 base::LazyInstance
<bool> hit_javascript_errors_
=
61 LAZY_INSTANCE_INITIALIZER
;
63 // Intercepts all log messages. We always attach this handler but only look at
64 // the results if the test requests so. Note that this will only work if the
65 // WebrtcTestBase-inheriting test cases do not run in parallel (if they did they
66 // would race to look at the log, which is global to all tests).
67 bool JavascriptErrorDetectingLogHandler(int severity
,
71 const std::string
& str
) {
72 if (file
== NULL
|| std::string("CONSOLE") != file
)
75 bool contains_uncaught
= str
.find("\"Uncaught ") != std::string::npos
;
76 if (severity
== logging::LOG_ERROR
||
77 (severity
== logging::LOG_INFO
&& contains_uncaught
)) {
78 hit_javascript_errors_
.Get() = true;
86 WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) {
87 // The handler gets set for each test method, but that's fine since this
88 // set operation is idempotent.
89 logging::SetLogMessageHandler(&JavascriptErrorDetectingLogHandler
);
90 hit_javascript_errors_
.Get() = false;
95 WebRtcTestBase::~WebRtcTestBase() {
96 if (detect_errors_in_javascript_
) {
97 EXPECT_FALSE(hit_javascript_errors_
.Get())
98 << "Encountered javascript errors during test execution (Search "
99 << "for Uncaught or ERROR:CONSOLE in the test output).";
103 void WebRtcTestBase::GetUserMediaAndAccept(
104 content::WebContents
* tab_contents
) const {
105 GetUserMediaWithSpecificConstraintsAndAccept(tab_contents
,
106 kAudioVideoCallConstraints
);
109 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept(
110 content::WebContents
* tab_contents
,
111 const std::string
& constraints
) const {
112 infobars::InfoBar
* infobar
=
113 GetUserMediaAndWaitForInfoBar(tab_contents
, constraints
);
114 infobar
->delegate()->AsConfirmInfoBarDelegate()->Accept();
115 CloseInfoBarInTab(tab_contents
, infobar
);
117 // Wait for WebRTC to call the success callback.
118 const char kOkGotStream
[] = "ok-got-stream";
119 EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()", kOkGotStream
,
123 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents
* tab_contents
) {
124 return GetUserMediaWithSpecificConstraintsAndDeny(tab_contents
,
125 kAudioVideoCallConstraints
);
128 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny(
129 content::WebContents
* tab_contents
,
130 const std::string
& constraints
) const {
131 infobars::InfoBar
* infobar
=
132 GetUserMediaAndWaitForInfoBar(tab_contents
, constraints
);
133 infobar
->delegate()->AsConfirmInfoBarDelegate()->Cancel();
134 CloseInfoBarInTab(tab_contents
, infobar
);
136 // Wait for WebRTC to call the fail callback.
137 EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
138 kFailedWithPermissionDeniedError
,
142 void WebRtcTestBase::GetUserMediaAndDismiss(
143 content::WebContents
* tab_contents
) const {
144 infobars::InfoBar
* infobar
=
145 GetUserMediaAndWaitForInfoBar(tab_contents
, kAudioVideoCallConstraints
);
146 infobar
->delegate()->InfoBarDismissed();
147 CloseInfoBarInTab(tab_contents
, infobar
);
149 // A dismiss should be treated like a deny.
150 EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
151 kFailedWithPermissionDismissedError
,
155 void WebRtcTestBase::GetUserMedia(content::WebContents
* tab_contents
,
156 const std::string
& constraints
) const {
157 // Request user media: this will launch the media stream info bar.
159 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
160 tab_contents
, "doGetUserMedia(" + constraints
+ ");", &result
));
161 EXPECT_EQ("ok-requested", result
);
164 infobars::InfoBar
* WebRtcTestBase::GetUserMediaAndWaitForInfoBar(
165 content::WebContents
* tab_contents
,
166 const std::string
& constraints
) const {
167 content::WindowedNotificationObserver
infobar_added(
168 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED
,
169 content::NotificationService::AllSources());
171 // Request user media: this will launch the media stream info bar.
172 GetUserMedia(tab_contents
, constraints
);
174 // Wait for the bar to pop up, then return it.
175 infobar_added
.Wait();
176 content::Details
<infobars::InfoBar::AddedDetails
> details(
177 infobar_added
.details());
178 EXPECT_TRUE(details
->delegate()->AsMediaStreamInfoBarDelegate());
179 return details
.ptr();
182 content::WebContents
* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab(
183 const GURL
& url
) const {
184 return OpenPageAndGetUserMediaInNewTabWithConstraints(
185 url
, kAudioVideoCallConstraints
);
188 content::WebContents
*
189 WebRtcTestBase::OpenPageAndGetUserMediaInNewTabWithConstraints(
191 const std::string
& constraints
) const {
192 chrome::AddTabAt(browser(), GURL(), -1, true);
193 ui_test_utils::NavigateToURL(browser(), url
);
194 content::WebContents
* new_tab
=
195 browser()->tab_strip_model()->GetActiveWebContents();
196 GetUserMediaWithSpecificConstraintsAndAccept(new_tab
, constraints
);
200 content::WebContents
* WebRtcTestBase::OpenTestPageAndGetUserMediaInNewTab(
201 const std::string
& test_page
) const {
202 return OpenPageAndGetUserMediaInNewTab(
203 embedded_test_server()->GetURL(test_page
));
206 content::WebContents
* WebRtcTestBase::OpenPageAndAcceptUserMedia(
207 const GURL
& url
) const {
208 content::WindowedNotificationObserver
infobar_added(
209 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED
,
210 content::NotificationService::AllSources());
212 ui_test_utils::NavigateToURL(browser(), url
);
214 infobar_added
.Wait();
216 content::WebContents
* tab_contents
=
217 browser()->tab_strip_model()->GetActiveWebContents();
218 content::Details
<infobars::InfoBar::AddedDetails
> details(
219 infobar_added
.details());
220 infobars::InfoBar
* infobar
= details
.ptr();
221 EXPECT_TRUE(infobar
);
222 infobar
->delegate()->AsMediaStreamInfoBarDelegate()->Accept();
224 CloseInfoBarInTab(tab_contents
, infobar
);
228 void WebRtcTestBase::CloseInfoBarInTab(content::WebContents
* tab_contents
,
229 infobars::InfoBar
* infobar
) const {
230 content::WindowedNotificationObserver
infobar_removed(
231 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED
,
232 content::NotificationService::AllSources());
234 InfoBarService
* infobar_service
=
235 InfoBarService::FromWebContents(tab_contents
);
236 infobar_service
->RemoveInfoBar(infobar
);
238 infobar_removed
.Wait();
241 void WebRtcTestBase::CloseLastLocalStream(
242 content::WebContents
* tab_contents
) const {
243 EXPECT_EQ("ok-stopped",
244 ExecuteJavascript("stopLocalStream();", tab_contents
));
247 // Convenience method which executes the provided javascript in the context
248 // of the provided web contents and returns what it evaluated to.
249 std::string
WebRtcTestBase::ExecuteJavascript(
250 const std::string
& javascript
,
251 content::WebContents
* tab_contents
) const {
253 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
254 tab_contents
, javascript
, &result
));
258 void WebRtcTestBase::SetupPeerconnectionWithLocalStream(
259 content::WebContents
* tab
) const {
260 SetupPeerconnectionWithoutLocalStream(tab
);
261 EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab
));
264 void WebRtcTestBase::SetupPeerconnectionWithoutLocalStream(
265 content::WebContents
* tab
) const {
266 EXPECT_EQ("ok-peerconnection-created",
267 ExecuteJavascript("preparePeerConnection()", tab
));
270 std::string
WebRtcTestBase::CreateLocalOffer(
271 content::WebContents
* from_tab
) const {
272 std::string response
= ExecuteJavascript("createLocalOffer({})", from_tab
);
273 EXPECT_EQ("ok-", response
.substr(0, 3)) << "Failed to create local offer: "
276 std::string local_offer
= response
.substr(3);
280 std::string
WebRtcTestBase::CreateAnswer(std::string local_offer
,
281 content::WebContents
* to_tab
) const {
282 std::string javascript
=
283 base::StringPrintf("receiveOfferFromPeer('%s', {})", local_offer
.c_str());
284 std::string response
= ExecuteJavascript(javascript
, to_tab
);
285 EXPECT_EQ("ok-", response
.substr(0, 3))
286 << "Receiving peer failed to receive offer and create answer: "
289 std::string answer
= response
.substr(3);
293 void WebRtcTestBase::ReceiveAnswer(std::string answer
,
294 content::WebContents
* from_tab
) const {
296 "ok-accepted-answer",
298 base::StringPrintf("receiveAnswerFromPeer('%s')", answer
.c_str()),
302 void WebRtcTestBase::GatherAndSendIceCandidates(
303 content::WebContents
* from_tab
,
304 content::WebContents
* to_tab
) const {
305 std::string ice_candidates
=
306 ExecuteJavascript("getAllIceCandidates()", from_tab
);
308 EXPECT_EQ("ok-received-candidates", ExecuteJavascript(
309 base::StringPrintf("receiveIceCandidates('%s')", ice_candidates
.c_str()),
313 void WebRtcTestBase::NegotiateCall(content::WebContents
* from_tab
,
314 content::WebContents
* to_tab
) const {
315 std::string local_offer
= CreateLocalOffer(from_tab
);
316 std::string answer
= CreateAnswer(local_offer
, to_tab
);
317 ReceiveAnswer(answer
, from_tab
);
319 // Send all ICE candidates (wait for gathering to finish if necessary).
320 GatherAndSendIceCandidates(to_tab
, from_tab
);
321 GatherAndSendIceCandidates(from_tab
, to_tab
);
324 void WebRtcTestBase::HangUp(content::WebContents
* from_tab
) const {
325 EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab
));
328 void WebRtcTestBase::DetectErrorsInJavaScript() {
329 detect_errors_in_javascript_
= true;
332 void WebRtcTestBase::StartDetectingVideo(
333 content::WebContents
* tab_contents
,
334 const std::string
& video_element
) const {
335 std::string javascript
= base::StringPrintf(
336 "startDetection('%s', 320, 240)", video_element
.c_str());
337 EXPECT_EQ("ok-started", ExecuteJavascript(javascript
, tab_contents
));
340 void WebRtcTestBase::WaitForVideoToPlay(
341 content::WebContents
* tab_contents
) const {
342 EXPECT_TRUE(test::PollingWaitUntil("isVideoPlaying()", "video-playing",
346 std::string
WebRtcTestBase::GetStreamSize(
347 content::WebContents
* tab_contents
,
348 const std::string
& video_element
) const {
349 std::string javascript
=
350 base::StringPrintf("getStreamSize('%s')", video_element
.c_str());
351 std::string result
= ExecuteJavascript(javascript
, tab_contents
);
352 EXPECT_TRUE(StartsWithASCII(result
, "ok-", true));
353 return result
.substr(3);
356 bool WebRtcTestBase::HasWebcamAvailableOnSystem(
357 content::WebContents
* tab_contents
) const {
359 ExecuteJavascript("hasVideoInputDeviceOnSystem();", tab_contents
);
360 return result
== "has-video-input-device";
363 bool WebRtcTestBase::OnWinXp() const {
365 return base::win::GetVersion() <= base::win::VERSION_XP
;
371 bool WebRtcTestBase::OnWin8() const {
373 return base::win::GetVersion() > base::win::VERSION_WIN7
;