• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
22 
23 #if defined(OS_WIN)
24 // For fine-grained suppression.
25 #include "base/win/windows_version.h"
26 #endif
27 
28 const char WebRtcTestBase::kAudioVideoCallConstraints[] =
29     "{audio: true, video: true}";
30 const char WebRtcTestBase::kAudioVideoCallConstraintsQVGA[] =
31    "{audio: true, video: {mandatory: {minWidth: 320, maxWidth: 320, "
32    " minHeight: 240, maxHeight: 240}}}";
33 const char WebRtcTestBase::kAudioVideoCallConstraints360p[] =
34    "{audio: true, video: {mandatory: {minWidth: 640, maxWidth: 640, "
35    " minHeight: 360, maxHeight: 360}}}";
36 const char WebRtcTestBase::kAudioVideoCallConstraintsVGA[] =
37    "{audio: true, video: {mandatory: {minWidth: 640, maxWidth: 640, "
38    " minHeight: 480, maxHeight: 480}}}";
39 const char WebRtcTestBase::kAudioVideoCallConstraints720p[] =
40    "{audio: true, video: {mandatory: {minWidth: 1280, maxWidth: 1280, "
41    " minHeight: 720, maxHeight: 720}}}";
42 const char WebRtcTestBase::kAudioVideoCallConstraints1080p[] =
43     "{audio: true, 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 
52 namespace {
53 
54 base::LazyInstance<bool> hit_javascript_errors_ =
55       LAZY_INSTANCE_INITIALIZER;
56 
57 // Intercepts all log messages. We always attach this handler but only look at
58 // the results if the test requests so. Note that this will only work if the
59 // WebrtcTestBase-inheriting test cases do not run in parallel (if they did they
60 // would race to look at the log, which is global to all tests).
JavascriptErrorDetectingLogHandler(int severity,const char * file,int line,size_t message_start,const std::string & str)61 bool JavascriptErrorDetectingLogHandler(int severity,
62                                         const char* file,
63                                         int line,
64                                         size_t message_start,
65                                         const std::string& str) {
66   if (file == NULL || std::string("CONSOLE") != file)
67     return false;
68 
69   bool contains_uncaught = str.find("\"Uncaught ") != std::string::npos;
70   if (severity == logging::LOG_ERROR ||
71       (severity == logging::LOG_INFO && contains_uncaught)) {
72     hit_javascript_errors_.Get() = true;
73   }
74 
75   return false;
76 }
77 
78 }  // namespace
79 
WebRtcTestBase()80 WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) {
81   // The handler gets set for each test method, but that's fine since this
82   // set operation is idempotent.
83   logging::SetLogMessageHandler(&JavascriptErrorDetectingLogHandler);
84   hit_javascript_errors_.Get() = false;
85 
86   EnablePixelOutput();
87 }
88 
~WebRtcTestBase()89 WebRtcTestBase::~WebRtcTestBase() {
90   if (detect_errors_in_javascript_) {
91     EXPECT_FALSE(hit_javascript_errors_.Get())
92         << "Encountered javascript errors during test execution (Search "
93         << "for Uncaught or ERROR:CONSOLE in the test output).";
94   }
95 }
96 
GetUserMediaAndAccept(content::WebContents * tab_contents) const97 void WebRtcTestBase::GetUserMediaAndAccept(
98     content::WebContents* tab_contents) const {
99   GetUserMediaWithSpecificConstraintsAndAccept(tab_contents,
100                                                kAudioVideoCallConstraints);
101 }
102 
GetUserMediaWithSpecificConstraintsAndAccept(content::WebContents * tab_contents,const std::string & constraints) const103 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept(
104     content::WebContents* tab_contents,
105     const std::string& constraints) const {
106   infobars::InfoBar* infobar =
107       GetUserMediaAndWaitForInfoBar(tab_contents, constraints);
108   infobar->delegate()->AsConfirmInfoBarDelegate()->Accept();
109   CloseInfoBarInTab(tab_contents, infobar);
110 
111   // Wait for WebRTC to call the success callback.
112   const char kOkGotStream[] = "ok-got-stream";
113   EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()", kOkGotStream,
114                                      tab_contents));
115 }
116 
GetUserMediaAndDeny(content::WebContents * tab_contents)117 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents* tab_contents) {
118   return GetUserMediaWithSpecificConstraintsAndDeny(tab_contents,
119                                                     kAudioVideoCallConstraints);
120 }
121 
GetUserMediaWithSpecificConstraintsAndDeny(content::WebContents * tab_contents,const std::string & constraints) const122 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny(
123     content::WebContents* tab_contents,
124     const std::string& constraints) const {
125   infobars::InfoBar* infobar =
126       GetUserMediaAndWaitForInfoBar(tab_contents, constraints);
127   infobar->delegate()->AsConfirmInfoBarDelegate()->Cancel();
128   CloseInfoBarInTab(tab_contents, infobar);
129 
130   // Wait for WebRTC to call the fail callback.
131   EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
132                                      kFailedWithPermissionDeniedError,
133                                      tab_contents));
134 }
135 
GetUserMediaAndDismiss(content::WebContents * tab_contents) const136 void WebRtcTestBase::GetUserMediaAndDismiss(
137     content::WebContents* tab_contents) const {
138   infobars::InfoBar* infobar =
139       GetUserMediaAndWaitForInfoBar(tab_contents, kAudioVideoCallConstraints);
140   infobar->delegate()->InfoBarDismissed();
141   CloseInfoBarInTab(tab_contents, infobar);
142 
143   // A dismiss should be treated like a deny.
144   EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
145                                      kFailedWithPermissionDismissedError,
146                                      tab_contents));
147 }
148 
GetUserMedia(content::WebContents * tab_contents,const std::string & constraints) const149 void WebRtcTestBase::GetUserMedia(content::WebContents* tab_contents,
150                                   const std::string& constraints) const {
151   // Request user media: this will launch the media stream info bar.
152   std::string result;
153   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
154       tab_contents, "doGetUserMedia(" + constraints + ");", &result));
155   EXPECT_EQ("ok-requested", result);
156 }
157 
GetUserMediaAndWaitForInfoBar(content::WebContents * tab_contents,const std::string & constraints) const158 infobars::InfoBar* WebRtcTestBase::GetUserMediaAndWaitForInfoBar(
159     content::WebContents* tab_contents,
160     const std::string& constraints) const {
161   content::WindowedNotificationObserver infobar_added(
162       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
163       content::NotificationService::AllSources());
164 
165   // Request user media: this will launch the media stream info bar.
166   GetUserMedia(tab_contents, constraints);
167 
168   // Wait for the bar to pop up, then return it.
169   infobar_added.Wait();
170   content::Details<infobars::InfoBar::AddedDetails> details(
171       infobar_added.details());
172   EXPECT_TRUE(details->delegate()->AsMediaStreamInfoBarDelegate());
173   return details.ptr();
174 }
175 
OpenPageAndGetUserMediaInNewTab(const GURL & url) const176 content::WebContents* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab(
177     const GURL& url) const {
178   return OpenPageAndGetUserMediaInNewTabWithConstraints(
179       url, kAudioVideoCallConstraints);
180 }
181 
182 content::WebContents*
OpenPageAndGetUserMediaInNewTabWithConstraints(const GURL & url,const std::string & constraints) const183 WebRtcTestBase::OpenPageAndGetUserMediaInNewTabWithConstraints(
184     const GURL& url,
185     const std::string& constraints) const {
186   chrome::AddTabAt(browser(), GURL(), -1, true);
187   ui_test_utils::NavigateToURL(browser(), url);
188 #if defined (OS_LINUX)
189   // Load the page again on Linux to work around crbug.com/281268.
190   ui_test_utils::NavigateToURL(browser(), url);
191 #endif
192   content::WebContents* new_tab =
193       browser()->tab_strip_model()->GetActiveWebContents();
194   GetUserMediaWithSpecificConstraintsAndAccept(new_tab, constraints);
195   return new_tab;
196 }
197 
OpenTestPageAndGetUserMediaInNewTab(const std::string & test_page) const198 content::WebContents* WebRtcTestBase::OpenTestPageAndGetUserMediaInNewTab(
199     const std::string& test_page) const {
200   return OpenPageAndGetUserMediaInNewTab(
201       embedded_test_server()->GetURL(test_page));
202 }
203 
OpenPageAndAcceptUserMedia(const GURL & url) const204 content::WebContents* WebRtcTestBase::OpenPageAndAcceptUserMedia(
205     const GURL& url) const {
206   content::WindowedNotificationObserver infobar_added(
207       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
208       content::NotificationService::AllSources());
209 
210   ui_test_utils::NavigateToURL(browser(), url);
211 
212   infobar_added.Wait();
213 
214   content::WebContents* tab_contents =
215       browser()->tab_strip_model()->GetActiveWebContents();
216   content::Details<infobars::InfoBar::AddedDetails> details(
217       infobar_added.details());
218   infobars::InfoBar* infobar = details.ptr();
219   EXPECT_TRUE(infobar);
220   infobar->delegate()->AsMediaStreamInfoBarDelegate()->Accept();
221 
222   CloseInfoBarInTab(tab_contents, infobar);
223   return tab_contents;
224 }
225 
CloseInfoBarInTab(content::WebContents * tab_contents,infobars::InfoBar * infobar) const226 void WebRtcTestBase::CloseInfoBarInTab(content::WebContents* tab_contents,
227                                        infobars::InfoBar* infobar) const {
228   content::WindowedNotificationObserver infobar_removed(
229       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
230       content::NotificationService::AllSources());
231 
232   InfoBarService* infobar_service =
233       InfoBarService::FromWebContents(tab_contents);
234   infobar_service->RemoveInfoBar(infobar);
235 
236   infobar_removed.Wait();
237 }
238 
CloseLastLocalStream(content::WebContents * tab_contents) const239 void WebRtcTestBase::CloseLastLocalStream(
240     content::WebContents* tab_contents) const {
241   EXPECT_EQ("ok-stopped",
242             ExecuteJavascript("stopLocalStream();", tab_contents));
243 }
244 
245 // Convenience method which executes the provided javascript in the context
246 // of the provided web contents and returns what it evaluated to.
ExecuteJavascript(const std::string & javascript,content::WebContents * tab_contents) const247 std::string WebRtcTestBase::ExecuteJavascript(
248     const std::string& javascript,
249     content::WebContents* tab_contents) const {
250   std::string result;
251   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
252       tab_contents, javascript, &result));
253   return result;
254 }
255 
SetupPeerconnectionWithLocalStream(content::WebContents * tab) const256 void WebRtcTestBase::SetupPeerconnectionWithLocalStream(
257     content::WebContents* tab) const {
258   EXPECT_EQ("ok-peerconnection-created",
259             ExecuteJavascript("preparePeerConnection()", tab));
260   EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab));
261 }
262 
CreateLocalOffer(content::WebContents * from_tab) const263 std::string WebRtcTestBase::CreateLocalOffer(
264       content::WebContents* from_tab) const {
265   std::string response = ExecuteJavascript("createLocalOffer({})", from_tab);
266   EXPECT_EQ("ok-", response.substr(0, 3)) << "Failed to create local offer: "
267       << response;
268 
269   std::string local_offer = response.substr(3);
270   return local_offer;
271 }
272 
CreateAnswer(std::string local_offer,content::WebContents * to_tab) const273 std::string WebRtcTestBase::CreateAnswer(std::string local_offer,
274                                          content::WebContents* to_tab) const {
275   std::string javascript =
276       base::StringPrintf("receiveOfferFromPeer('%s', {})", local_offer.c_str());
277   std::string response = ExecuteJavascript(javascript, to_tab);
278   EXPECT_EQ("ok-", response.substr(0, 3))
279       << "Receiving peer failed to receive offer and create answer: "
280       << response;
281 
282   std::string answer = response.substr(3);
283   return answer;
284 }
285 
ReceiveAnswer(std::string answer,content::WebContents * from_tab) const286 void WebRtcTestBase::ReceiveAnswer(std::string answer,
287                                    content::WebContents* from_tab) const {
288   ASSERT_EQ(
289       "ok-accepted-answer",
290       ExecuteJavascript(
291           base::StringPrintf("receiveAnswerFromPeer('%s')", answer.c_str()),
292           from_tab));
293 }
294 
GatherAndSendIceCandidates(content::WebContents * from_tab,content::WebContents * to_tab) const295 void WebRtcTestBase::GatherAndSendIceCandidates(
296     content::WebContents* from_tab,
297     content::WebContents* to_tab) const {
298   std::string ice_candidates =
299       ExecuteJavascript("getAllIceCandidates()", from_tab);
300 
301   EXPECT_EQ("ok-received-candidates", ExecuteJavascript(
302       base::StringPrintf("receiveIceCandidates('%s')", ice_candidates.c_str()),
303       to_tab));
304 }
305 
NegotiateCall(content::WebContents * from_tab,content::WebContents * to_tab) const306 void WebRtcTestBase::NegotiateCall(content::WebContents* from_tab,
307                                    content::WebContents* to_tab) const {
308   std::string local_offer = CreateLocalOffer(from_tab);
309   std::string answer = CreateAnswer(local_offer, to_tab);
310   ReceiveAnswer(answer, from_tab);
311 
312   // Send all ICE candidates (wait for gathering to finish if necessary).
313   GatherAndSendIceCandidates(to_tab, from_tab);
314   GatherAndSendIceCandidates(from_tab, to_tab);
315 }
316 
HangUp(content::WebContents * from_tab) const317 void WebRtcTestBase::HangUp(content::WebContents* from_tab) const {
318   EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab));
319 }
320 
DetectErrorsInJavaScript()321 void WebRtcTestBase::DetectErrorsInJavaScript() {
322   detect_errors_in_javascript_ = true;
323 }
324 
StartDetectingVideo(content::WebContents * tab_contents,const std::string & video_element) const325 void WebRtcTestBase::StartDetectingVideo(
326     content::WebContents* tab_contents,
327     const std::string& video_element) const {
328   std::string javascript = base::StringPrintf(
329       "startDetection('%s', 320, 240)", video_element.c_str());
330   EXPECT_EQ("ok-started", ExecuteJavascript(javascript, tab_contents));
331 }
332 
WaitForVideoToPlay(content::WebContents * tab_contents) const333 void WebRtcTestBase::WaitForVideoToPlay(
334     content::WebContents* tab_contents) const {
335   EXPECT_TRUE(test::PollingWaitUntil("isVideoPlaying()", "video-playing",
336                                      tab_contents));
337 }
338 
GetStreamSize(content::WebContents * tab_contents,const std::string & video_element) const339 std::string WebRtcTestBase::GetStreamSize(
340     content::WebContents* tab_contents,
341     const std::string& video_element) const {
342   std::string javascript =
343       base::StringPrintf("getStreamSize('%s')", video_element.c_str());
344   std::string result = ExecuteJavascript(javascript, tab_contents);
345   EXPECT_TRUE(StartsWithASCII(result, "ok-", true));
346   return result.substr(3);
347 }
348 
HasWebcamAvailableOnSystem(content::WebContents * tab_contents) const349 bool WebRtcTestBase::HasWebcamAvailableOnSystem(
350     content::WebContents* tab_contents) const {
351   std::string result =
352       ExecuteJavascript("hasVideoInputDeviceOnSystem();", tab_contents);
353   return result == "has-video-input-device";
354 }
355 
OnWinXp() const356 bool WebRtcTestBase::OnWinXp() const {
357 #if defined(OS_WIN)
358   return base::win::GetVersion() <= base::win::VERSION_XP;
359 #else
360   return false;
361 #endif
362 }
363 
OnWin8() const364 bool WebRtcTestBase::OnWin8() const {
365 #if defined(OS_WIN)
366   return base::win::GetVersion() > base::win::VERSION_WIN7;
367 #else
368   return false;
369 #endif
370 }
371