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/webrtc_browsertest_base.h"
6 
7 #include <stddef.h>
8 
9 #include <limits>
10 
11 #include "base/json/json_reader.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/values.h"
21 #include "build/build_config.h"
22 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
23 #include "chrome/browser/media/webrtc/webrtc_browsertest_common.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_tabstrip.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chrome/test/base/ui_test_utils.h"
30 #include "components/permissions/permission_request_manager.h"
31 #include "components/permissions/test/permission_request_observer.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 
36 #if defined(OS_WIN)
37 // For fine-grained suppression.
38 #include "base/win/windows_version.h"
39 #endif
40 
41 const char WebRtcTestBase::kAudioVideoCallConstraints[] =
42     "{audio: true, video: true}";
43 const char WebRtcTestBase::kVideoCallConstraintsQVGA[] =
44    "{video: {mandatory: {minWidth: 320, maxWidth: 320, "
45    " minHeight: 240, maxHeight: 240}}}";
46 const char WebRtcTestBase::kVideoCallConstraints360p[] =
47    "{video: {mandatory: {minWidth: 640, maxWidth: 640, "
48    " minHeight: 360, maxHeight: 360}}}";
49 const char WebRtcTestBase::kVideoCallConstraintsVGA[] =
50    "{video: {mandatory: {minWidth: 640, maxWidth: 640, "
51    " minHeight: 480, maxHeight: 480}}}";
52 const char WebRtcTestBase::kVideoCallConstraints720p[] =
53    "{video: {mandatory: {minWidth: 1280, maxWidth: 1280, "
54    " minHeight: 720, maxHeight: 720}}}";
55 const char WebRtcTestBase::kVideoCallConstraints1080p[] =
56     "{video: {mandatory: {minWidth: 1920, maxWidth: 1920, "
57     " minHeight: 1080, maxHeight: 1080}}}";
58 const char WebRtcTestBase::kAudioOnlyCallConstraints[] = "{audio: true}";
59 const char WebRtcTestBase::kVideoOnlyCallConstraints[] = "{video: true}";
60 const char WebRtcTestBase::kOkGotStream[] = "ok-got-stream";
61 const char WebRtcTestBase::kFailedWithNotAllowedError[] =
62     "failed-with-error-NotAllowedError";
63 const char WebRtcTestBase::kAudioVideoCallConstraints360p[] =
64    "{audio: true, video: {mandatory: {minWidth: 640, maxWidth: 640, "
65    " minHeight: 360, maxHeight: 360}}}";
66 const char WebRtcTestBase::kAudioVideoCallConstraints720p[] =
67    "{audio: true, video: {mandatory: {minWidth: 1280, maxWidth: 1280, "
68    " minHeight: 720, maxHeight: 720}}}";
69 const char WebRtcTestBase::kUseDefaultCertKeygen[] = "null";
70 const char WebRtcTestBase::kUseDefaultAudioCodec[] = "";
71 const char WebRtcTestBase::kUseDefaultVideoCodec[] = "";
72 const char WebRtcTestBase::kVP9Profile0Specifier[] = "profile-id=0";
73 const char WebRtcTestBase::kVP9Profile2Specifier[] = "profile-id=2";
74 const char WebRtcTestBase::kUndefined[] = "undefined";
75 
76 namespace {
77 
78 base::LazyInstance<bool>::DestructorAtExit hit_javascript_errors_ =
79     LAZY_INSTANCE_INITIALIZER;
80 
81 // Intercepts all log messages. We always attach this handler but only look at
82 // the results if the test requests so. Note that this will only work if the
83 // WebrtcTestBase-inheriting test cases do not run in parallel (if they did they
84 // 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)85 bool JavascriptErrorDetectingLogHandler(int severity,
86                                         const char* file,
87                                         int line,
88                                         size_t message_start,
89                                         const std::string& str) {
90   if (file == NULL || std::string("CONSOLE") != file)
91     return false;
92 
93   // TODO(crbug.com/918871): Fix AppRTC and stop ignoring this error.
94   if (str.find("Synchronous XHR in page dismissal") != std::string::npos)
95     return false;
96 
97   bool contains_uncaught = str.find("\"Uncaught ") != std::string::npos;
98   if (severity == logging::LOG_ERROR ||
99       (severity == logging::LOG_INFO && contains_uncaught)) {
100     hit_javascript_errors_.Get() = true;
101   }
102 
103   return false;
104 }
105 
JsonArrayToVectorOfStrings(const std::string & json_array)106 std::vector<std::string> JsonArrayToVectorOfStrings(
107     const std::string& json_array) {
108   std::unique_ptr<base::Value> value =
109       base::JSONReader::ReadDeprecated(json_array);
110   EXPECT_TRUE(value);
111   EXPECT_TRUE(value->is_list());
112   std::unique_ptr<base::ListValue> list =
113       base::ListValue::From(std::move(value));
114   std::vector<std::string> vector;
115   vector.reserve(list->GetSize());
116   for (size_t i = 0; i < list->GetSize(); ++i) {
117     base::Value* item;
118     EXPECT_TRUE(list->Get(i, &item));
119     EXPECT_TRUE(item->is_string());
120     std::string item_str;
121     EXPECT_TRUE(item->GetAsString(&item_str));
122     vector.push_back(std::move(item_str));
123   }
124   return vector;
125 }
126 
127 }  // namespace
128 
WebRtcTestBase()129 WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) {
130   // The handler gets set for each test method, but that's fine since this
131   // set operation is idempotent.
132   logging::SetLogMessageHandler(&JavascriptErrorDetectingLogHandler);
133   hit_javascript_errors_.Get() = false;
134 
135   EnablePixelOutput();
136 }
137 
~WebRtcTestBase()138 WebRtcTestBase::~WebRtcTestBase() {
139   if (detect_errors_in_javascript_) {
140     EXPECT_FALSE(hit_javascript_errors_.Get())
141         << "Encountered javascript errors during test execution (Search "
142         << "for Uncaught or ERROR:CONSOLE in the test output).";
143   }
144 }
145 
GetUserMediaAndAccept(content::WebContents * tab_contents) const146 bool WebRtcTestBase::GetUserMediaAndAccept(
147     content::WebContents* tab_contents) const {
148   return GetUserMediaWithSpecificConstraintsAndAccept(
149       tab_contents, kAudioVideoCallConstraints);
150 }
151 
GetUserMediaWithSpecificConstraintsAndAccept(content::WebContents * tab_contents,const std::string & constraints) const152 bool WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept(
153     content::WebContents* tab_contents,
154     const std::string& constraints) const {
155   std::string result;
156   permissions::PermissionRequestManager::FromWebContents(tab_contents)
157       ->set_auto_response_for_test(
158           permissions::PermissionRequestManager::ACCEPT_ALL);
159   permissions::PermissionRequestObserver observer(tab_contents);
160   GetUserMedia(tab_contents, constraints);
161   EXPECT_TRUE(observer.request_shown());
162   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
163       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
164   return kOkGotStream == result;
165 }
166 
GetUserMediaWithSpecificConstraintsAndAcceptIfPrompted(content::WebContents * tab_contents,const std::string & constraints) const167 bool WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAcceptIfPrompted(
168     content::WebContents* tab_contents,
169     const std::string& constraints) const {
170   std::string result;
171   permissions::PermissionRequestManager::FromWebContents(tab_contents)
172       ->set_auto_response_for_test(
173           permissions::PermissionRequestManager::ACCEPT_ALL);
174   GetUserMedia(tab_contents, constraints);
175   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
176       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
177   return kOkGotStream == result;
178 }
179 
GetUserMediaAndDeny(content::WebContents * tab_contents)180 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents* tab_contents) {
181   return GetUserMediaWithSpecificConstraintsAndDeny(tab_contents,
182                                                     kAudioVideoCallConstraints);
183 }
184 
GetUserMediaWithSpecificConstraintsAndDeny(content::WebContents * tab_contents,const std::string & constraints) const185 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny(
186     content::WebContents* tab_contents,
187     const std::string& constraints) const {
188   std::string result;
189   permissions::PermissionRequestManager::FromWebContents(tab_contents)
190       ->set_auto_response_for_test(
191           permissions::PermissionRequestManager::DENY_ALL);
192   permissions::PermissionRequestObserver observer(tab_contents);
193   GetUserMedia(tab_contents, constraints);
194   EXPECT_TRUE(observer.request_shown());
195   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
196       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
197   EXPECT_EQ(kFailedWithNotAllowedError, result);
198 }
199 
GetUserMediaAndDismiss(content::WebContents * tab_contents) const200 void WebRtcTestBase::GetUserMediaAndDismiss(
201     content::WebContents* tab_contents) const {
202   std::string result;
203   permissions::PermissionRequestManager::FromWebContents(tab_contents)
204       ->set_auto_response_for_test(
205           permissions::PermissionRequestManager::DISMISS);
206   permissions::PermissionRequestObserver observer(tab_contents);
207   GetUserMedia(tab_contents, kAudioVideoCallConstraints);
208   EXPECT_TRUE(observer.request_shown());
209   // A dismiss should be treated like a deny.
210   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
211       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
212   EXPECT_EQ(kFailedWithNotAllowedError, result);
213 }
214 
GetUserMediaAndExpectAutoAcceptWithoutPrompt(content::WebContents * tab_contents) const215 void WebRtcTestBase::GetUserMediaAndExpectAutoAcceptWithoutPrompt(
216     content::WebContents* tab_contents) const {
217   std::string result;
218   // We issue a GetUserMedia() request. We expect that the origin already has a
219   // sticky "accept" permission (e.g. because the caller previously called
220   // GetUserMediaAndAccept()), and therefore the GetUserMedia() request
221   // automatically succeeds without a prompt.
222   // If the caller made a mistake, a prompt may show up instead. For this case,
223   // we set an auto-response to avoid leaving the prompt hanging. The choice of
224   // DENY_ALL makes sure that the response to the prompt doesn't accidentally
225   // result in a newly granted media stream permission.
226   permissions::PermissionRequestManager::FromWebContents(tab_contents)
227       ->set_auto_response_for_test(
228           permissions::PermissionRequestManager::DENY_ALL);
229   permissions::PermissionRequestObserver observer(tab_contents);
230   GetUserMedia(tab_contents, kAudioVideoCallConstraints);
231   EXPECT_FALSE(observer.request_shown());
232   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
233       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
234   EXPECT_EQ(kOkGotStream, result);
235 }
236 
GetUserMediaAndExpectAutoDenyWithoutPrompt(content::WebContents * tab_contents) const237 void WebRtcTestBase::GetUserMediaAndExpectAutoDenyWithoutPrompt(
238     content::WebContents* tab_contents) const {
239   std::string result;
240   // We issue a GetUserMedia() request. We expect that the origin already has a
241   // sticky "deny" permission (e.g. because the caller previously called
242   // GetUserMediaAndDeny()), and therefore the GetUserMedia() request
243   // automatically succeeds without a prompt.
244   // If the caller made a mistake, a prompt may show up instead. For this case,
245   // we set an auto-response to avoid leaving the prompt hanging. The choice of
246   // ACCEPT_ALL makes sure that the response to the prompt doesn't accidentally
247   // result in a newly granted media stream permission.
248   permissions::PermissionRequestManager::FromWebContents(tab_contents)
249       ->set_auto_response_for_test(
250           permissions::PermissionRequestManager::ACCEPT_ALL);
251   permissions::PermissionRequestObserver observer(tab_contents);
252   GetUserMedia(tab_contents, kAudioVideoCallConstraints);
253   EXPECT_FALSE(observer.request_shown());
254   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
255       tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
256   EXPECT_EQ(kFailedWithNotAllowedError, result);
257 }
258 
GetUserMedia(content::WebContents * tab_contents,const std::string & constraints) const259 void WebRtcTestBase::GetUserMedia(content::WebContents* tab_contents,
260                                   const std::string& constraints) const {
261   // Request user media: this will launch the media stream info bar or bubble.
262   std::string result;
263   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
264       tab_contents, "doGetUserMedia(" + constraints + ");", &result));
265   EXPECT_TRUE(result == "request-callback-denied" ||
266               result == "request-callback-granted");
267 }
268 
OpenPageAndGetUserMediaInNewTab(const GURL & url) const269 content::WebContents* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab(
270     const GURL& url) const {
271   return OpenPageAndGetUserMediaInNewTabWithConstraints(
272       url, kAudioVideoCallConstraints);
273 }
274 
275 content::WebContents*
OpenPageAndGetUserMediaInNewTabWithConstraints(const GURL & url,const std::string & constraints) const276 WebRtcTestBase::OpenPageAndGetUserMediaInNewTabWithConstraints(
277     const GURL& url,
278     const std::string& constraints) const {
279   chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), -1, true);
280   ui_test_utils::NavigateToURL(browser(), url);
281   content::WebContents* new_tab =
282       browser()->tab_strip_model()->GetActiveWebContents();
283   // Accept if necessary, but don't expect a prompt (because auto-accept is also
284   // okay).
285   permissions::PermissionRequestManager::FromWebContents(new_tab)
286       ->set_auto_response_for_test(
287           permissions::PermissionRequestManager::ACCEPT_ALL);
288   GetUserMedia(new_tab, constraints);
289   std::string result;
290   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
291       new_tab->GetMainFrame(), "obtainGetUserMediaResult();", &result));
292   EXPECT_EQ(kOkGotStream, result);
293   return new_tab;
294 }
295 
OpenTestPageAndGetUserMediaInNewTab(const std::string & test_page) const296 content::WebContents* WebRtcTestBase::OpenTestPageAndGetUserMediaInNewTab(
297     const std::string& test_page) const {
298   return OpenPageAndGetUserMediaInNewTab(
299       embedded_test_server()->GetURL(test_page));
300 }
301 
OpenTestPageInNewTab(const std::string & test_page) const302 content::WebContents* WebRtcTestBase::OpenTestPageInNewTab(
303     const std::string& test_page) const {
304   chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), -1, true);
305   GURL url = embedded_test_server()->GetURL(test_page);
306   ui_test_utils::NavigateToURL(browser(), url);
307   content::WebContents* new_tab =
308       browser()->tab_strip_model()->GetActiveWebContents();
309   // Accept if necessary, but don't expect a prompt (because auto-accept is also
310   // okay).
311   permissions::PermissionRequestManager::FromWebContents(new_tab)
312       ->set_auto_response_for_test(
313           permissions::PermissionRequestManager::ACCEPT_ALL);
314   return new_tab;
315 }
316 
CloseLastLocalStream(content::WebContents * tab_contents) const317 void WebRtcTestBase::CloseLastLocalStream(
318     content::WebContents* tab_contents) const {
319   EXPECT_EQ("ok-stopped",
320             ExecuteJavascript("stopLocalStream();", tab_contents));
321 }
322 
323 // Convenience method which executes the provided javascript in the context
324 // of the provided web contents and returns what it evaluated to.
ExecuteJavascript(const std::string & javascript,content::WebContents * tab_contents) const325 std::string WebRtcTestBase::ExecuteJavascript(
326     const std::string& javascript,
327     content::WebContents* tab_contents) const {
328   std::string result;
329   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
330       tab_contents, javascript, &result));
331   return result;
332 }
333 
ChangeToLegacyGetStats(content::WebContents * tab) const334 void WebRtcTestBase::ChangeToLegacyGetStats(content::WebContents* tab) const {
335   content::ExecuteScriptAsync(tab, "changeToLegacyGetStats()");
336 }
337 
SetupPeerconnectionWithLocalStream(content::WebContents * tab,const std::string & certificate_keygen_algorithm) const338 void WebRtcTestBase::SetupPeerconnectionWithLocalStream(
339     content::WebContents* tab,
340     const std::string& certificate_keygen_algorithm) const {
341   SetupPeerconnectionWithoutLocalStream(tab, certificate_keygen_algorithm);
342   EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab));
343 }
344 
SetupPeerconnectionWithoutLocalStream(content::WebContents * tab,const std::string & certificate_keygen_algorithm) const345 void WebRtcTestBase::SetupPeerconnectionWithoutLocalStream(
346     content::WebContents* tab,
347     const std::string& certificate_keygen_algorithm) const {
348   std::string javascript = base::StringPrintf(
349       "preparePeerConnection(%s)", certificate_keygen_algorithm.c_str());
350   EXPECT_EQ("ok-peerconnection-created", ExecuteJavascript(javascript, tab));
351 }
352 
SetupPeerconnectionWithCertificateAndLocalStream(content::WebContents * tab,const std::string & certificate) const353 void WebRtcTestBase::SetupPeerconnectionWithCertificateAndLocalStream(
354     content::WebContents* tab,
355     const std::string& certificate) const {
356   SetupPeerconnectionWithCertificateWithoutLocalStream(tab, certificate);
357   EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab));
358 }
359 
SetupPeerconnectionWithCertificateWithoutLocalStream(content::WebContents * tab,const std::string & certificate) const360 void WebRtcTestBase::SetupPeerconnectionWithCertificateWithoutLocalStream(
361     content::WebContents* tab,
362     const std::string& certificate) const {
363   std::string javascript = base::StringPrintf(
364       "preparePeerConnectionWithCertificate(%s)", certificate.c_str());
365   EXPECT_EQ("ok-peerconnection-created", ExecuteJavascript(javascript, tab));
366 }
367 
SetupPeerconnectionWithConstraintsAndLocalStream(content::WebContents * tab,const std::string & constraints,const std::string & certificate_keygen_algorithm) const368 void WebRtcTestBase::SetupPeerconnectionWithConstraintsAndLocalStream(
369     content::WebContents* tab,
370     const std::string& constraints,
371     const std::string& certificate_keygen_algorithm) const {
372   std::string javascript = base::StringPrintf(
373       "preparePeerConnection(%s, %s)", certificate_keygen_algorithm.c_str(),
374       constraints.c_str());
375   EXPECT_EQ("ok-peerconnection-created", ExecuteJavascript(javascript, tab));
376   EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab));
377 }
378 
CreateLocalOffer(content::WebContents * from_tab) const379 std::string WebRtcTestBase::CreateLocalOffer(
380     content::WebContents* from_tab) const {
381   std::string response = ExecuteJavascript("createLocalOffer({})", from_tab);
382   EXPECT_EQ("ok-", response.substr(0, 3)) << "Failed to create local offer: "
383       << response;
384 
385   std::string local_offer = response.substr(3);
386   return local_offer;
387 }
388 
CreateAnswer(std::string local_offer,content::WebContents * to_tab) const389 std::string WebRtcTestBase::CreateAnswer(std::string local_offer,
390                                          content::WebContents* to_tab) const {
391   std::string javascript =
392       base::StringPrintf("receiveOfferFromPeer('%s', {})", local_offer.c_str());
393   std::string response = ExecuteJavascript(javascript, to_tab);
394   EXPECT_EQ("ok-", response.substr(0, 3))
395       << "Receiving peer failed to receive offer and create answer: "
396       << response;
397 
398   std::string answer = response.substr(3);
399   response = ExecuteJavascript(
400       base::StringPrintf("verifyDefaultCodecs('%s')", answer.c_str()),
401       to_tab);
402   EXPECT_EQ("ok-", response.substr(0, 3))
403       << "Receiving peer failed to verify default codec: " << response;
404   return answer;
405 }
406 
ReceiveAnswer(const std::string & answer,content::WebContents * from_tab) const407 void WebRtcTestBase::ReceiveAnswer(const std::string& answer,
408                                    content::WebContents* from_tab) const {
409   ASSERT_EQ(
410       "ok-accepted-answer",
411       ExecuteJavascript(
412           base::StringPrintf("receiveAnswerFromPeer('%s')", answer.c_str()),
413           from_tab));
414 }
415 
GatherAndSendIceCandidates(content::WebContents * from_tab,content::WebContents * to_tab) const416 void WebRtcTestBase::GatherAndSendIceCandidates(
417     content::WebContents* from_tab,
418     content::WebContents* to_tab) const {
419   std::string ice_candidates =
420       ExecuteJavascript("getAllIceCandidates()", from_tab);
421 
422   EXPECT_EQ("ok-received-candidates", ExecuteJavascript(
423       base::StringPrintf("receiveIceCandidates('%s')", ice_candidates.c_str()),
424       to_tab));
425 }
426 
CreateDataChannel(content::WebContents * tab,const std::string & label)427 void WebRtcTestBase::CreateDataChannel(content::WebContents* tab,
428                                        const std::string& label) {
429   EXPECT_EQ("ok-created",
430             ExecuteJavascript("createDataChannel('" + label + "')", tab));
431 }
432 
NegotiateCall(content::WebContents * from_tab,content::WebContents * to_tab) const433 void WebRtcTestBase::NegotiateCall(content::WebContents* from_tab,
434                                    content::WebContents* to_tab) const {
435   std::string local_offer = CreateLocalOffer(from_tab);
436   std::string answer = CreateAnswer(local_offer, to_tab);
437   ReceiveAnswer(answer, from_tab);
438 
439   // Send all ICE candidates (wait for gathering to finish if necessary).
440   GatherAndSendIceCandidates(to_tab, from_tab);
441   GatherAndSendIceCandidates(from_tab, to_tab);
442 }
443 
VerifyLocalDescriptionContainsCertificate(content::WebContents * tab,const std::string & certificate) const444 void WebRtcTestBase::VerifyLocalDescriptionContainsCertificate(
445     content::WebContents* tab,
446     const std::string& certificate) const {
447   std::string javascript = base::StringPrintf(
448       "verifyLocalDescriptionContainsCertificate(%s)", certificate.c_str());
449   EXPECT_EQ("ok-verified", ExecuteJavascript(javascript, tab));
450 }
451 
HangUp(content::WebContents * from_tab) const452 void WebRtcTestBase::HangUp(content::WebContents* from_tab) const {
453   EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab));
454 }
455 
DetectErrorsInJavaScript()456 void WebRtcTestBase::DetectErrorsInJavaScript() {
457   detect_errors_in_javascript_ = true;
458 }
459 
StartDetectingVideo(content::WebContents * tab_contents,const std::string & video_element) const460 void WebRtcTestBase::StartDetectingVideo(
461     content::WebContents* tab_contents,
462     const std::string& video_element) const {
463   std::string javascript = base::StringPrintf(
464       "startDetection('%s', 320, 240)", video_element.c_str());
465   EXPECT_EQ("ok-started", ExecuteJavascript(javascript, tab_contents));
466 }
467 
WaitForVideoToPlay(content::WebContents * tab_contents) const468 bool WebRtcTestBase::WaitForVideoToPlay(
469     content::WebContents* tab_contents) const {
470   bool is_video_playing = test::PollingWaitUntil(
471       "isVideoPlaying()", "video-playing", tab_contents);
472   EXPECT_TRUE(is_video_playing);
473   return is_video_playing;
474 }
475 
WaitForVideoToStop(content::WebContents * tab_contents) const476 bool WebRtcTestBase::WaitForVideoToStop(
477     content::WebContents* tab_contents) const {
478   bool is_video_stopped =
479       test::PollingWaitUntil("isVideoStopped()", "video-stopped", tab_contents);
480   EXPECT_TRUE(is_video_stopped);
481   return is_video_stopped;
482 }
483 
GetStreamSize(content::WebContents * tab_contents,const std::string & video_element) const484 std::string WebRtcTestBase::GetStreamSize(
485     content::WebContents* tab_contents,
486     const std::string& video_element) const {
487   std::string javascript =
488       base::StringPrintf("getStreamSize('%s')", video_element.c_str());
489   std::string result = ExecuteJavascript(javascript, tab_contents);
490   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
491   return result.substr(3);
492 }
493 
OnWin8OrHigher() const494 bool WebRtcTestBase::OnWin8OrHigher() const {
495 #if defined(OS_WIN)
496   return base::win::GetVersion() >= base::win::Version::WIN8;
497 #else
498   return false;
499 #endif
500 }
501 
OpenDatabase(content::WebContents * tab) const502 void WebRtcTestBase::OpenDatabase(content::WebContents* tab) const {
503   EXPECT_EQ("ok-database-opened", ExecuteJavascript("openDatabase()", tab));
504 }
505 
CloseDatabase(content::WebContents * tab) const506 void WebRtcTestBase::CloseDatabase(content::WebContents* tab) const {
507   EXPECT_EQ("ok-database-closed", ExecuteJavascript("closeDatabase()", tab));
508 }
509 
DeleteDatabase(content::WebContents * tab) const510 void WebRtcTestBase::DeleteDatabase(content::WebContents* tab) const {
511   EXPECT_EQ("ok-database-deleted", ExecuteJavascript("deleteDatabase()", tab));
512 }
513 
GenerateAndCloneCertificate(content::WebContents * tab,const std::string & keygen_algorithm) const514 void WebRtcTestBase::GenerateAndCloneCertificate(
515     content::WebContents* tab, const std::string& keygen_algorithm) const {
516   std::string javascript = base::StringPrintf(
517       "generateAndCloneCertificate(%s)", keygen_algorithm.c_str());
518   EXPECT_EQ("ok-generated-and-cloned", ExecuteJavascript(javascript, tab));
519 }
520 
VerifyStatsGeneratedCallback(content::WebContents * tab) const521 void WebRtcTestBase::VerifyStatsGeneratedCallback(
522     content::WebContents* tab) const {
523   EXPECT_EQ("ok-got-stats",
524             ExecuteJavascript("verifyLegacyStatsGenerated()", tab));
525 }
526 
VerifyStatsGeneratedPromise(content::WebContents * tab) const527 std::vector<std::string> WebRtcTestBase::VerifyStatsGeneratedPromise(
528     content::WebContents* tab) const {
529   std::string result = ExecuteJavascript("verifyStatsGeneratedPromise()", tab);
530   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
531   return JsonArrayToVectorOfStrings(result.substr(3));
532 }
533 
MeasureGetStatsCallbackPerformance(content::WebContents * tab) const534 double WebRtcTestBase::MeasureGetStatsCallbackPerformance(
535     content::WebContents* tab) const {
536   std::string result = ExecuteJavascript(
537       "measureGetStatsCallbackPerformance()", tab);
538   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
539   double ms;
540   if (!base::StringToDouble(result.substr(3), &ms))
541     return std::numeric_limits<double>::infinity();
542   return ms;
543 }
544 
545 scoped_refptr<content::TestStatsReportDictionary>
GetStatsReportDictionary(content::WebContents * tab) const546 WebRtcTestBase::GetStatsReportDictionary(content::WebContents* tab) const {
547   std::string result = ExecuteJavascript("getStatsReportDictionary()", tab);
548   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
549   std::unique_ptr<base::Value> parsed_json =
550       base::JSONReader::ReadDeprecated(result.substr(3));
551   base::DictionaryValue* dictionary;
552   CHECK(parsed_json);
553   CHECK(parsed_json->GetAsDictionary(&dictionary));
554   ignore_result(parsed_json.release());
555   return scoped_refptr<content::TestStatsReportDictionary>(
556       new content::TestStatsReportDictionary(
557           std::unique_ptr<base::DictionaryValue>(dictionary)));
558 }
559 
MeasureGetStatsPerformance(content::WebContents * tab) const560 double WebRtcTestBase::MeasureGetStatsPerformance(
561     content::WebContents* tab) const {
562   std::string result = ExecuteJavascript("measureGetStatsPerformance()", tab);
563   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
564   double ms;
565   if (!base::StringToDouble(result.substr(3), &ms))
566     return std::numeric_limits<double>::infinity();
567   return ms;
568 }
569 
GetMandatoryStatsTypes(content::WebContents * tab) const570 std::vector<std::string> WebRtcTestBase::GetMandatoryStatsTypes(
571     content::WebContents* tab) const {
572   return JsonArrayToVectorOfStrings(
573       ExecuteJavascript("getMandatoryStatsTypes()", tab));
574 }
575 
SetDefaultAudioCodec(content::WebContents * tab,const std::string & audio_codec) const576 void WebRtcTestBase::SetDefaultAudioCodec(
577     content::WebContents* tab,
578     const std::string& audio_codec) const {
579   EXPECT_EQ("ok", ExecuteJavascript(
580       "setDefaultAudioCodec('" + audio_codec + "')", tab));
581 }
582 
SetDefaultVideoCodec(content::WebContents * tab,const std::string & video_codec,bool prefer_hw_codec,const std::string & profile) const583 void WebRtcTestBase::SetDefaultVideoCodec(content::WebContents* tab,
584                                           const std::string& video_codec,
585                                           bool prefer_hw_codec,
586                                           const std::string& profile) const {
587   std::string codec_profile = profile;
588   // When no |profile| is given, we default VP9 to Profile 0.
589   if (video_codec.compare("VP9") == 0 && codec_profile.empty())
590     codec_profile = kVP9Profile0Specifier;
591 
592   EXPECT_EQ("ok", ExecuteJavascript(
593                       "setDefaultVideoCodec('" + video_codec + "'," +
594                           (prefer_hw_codec ? "true" : "false") + "," +
595                           (codec_profile.empty() ? "null"
596                                                  : "'" + codec_profile + "'") +
597                           ")",
598                       tab));
599 }
600 
EnableOpusDtx(content::WebContents * tab) const601 void WebRtcTestBase::EnableOpusDtx(content::WebContents* tab) const {
602   EXPECT_EQ("ok-forced", ExecuteJavascript("forceOpusDtx()", tab));
603 }
604 
GetDesktopMediaStream(content::WebContents * tab)605 std::string WebRtcTestBase::GetDesktopMediaStream(content::WebContents* tab) {
606   DCHECK(static_cast<bool>(LoadDesktopCaptureExtension()));
607 
608   // Post a task to the extension, opening a desktop media stream.
609   return ExecuteJavascript("openDesktopMediaStream()", tab);
610 }
611 
LoadDesktopCaptureExtension()612 base::Optional<std::string> WebRtcTestBase::LoadDesktopCaptureExtension() {
613   base::Optional<std::string> extension_id;
614   if (!desktop_capture_extension_.get()) {
615     extensions::ChromeTestExtensionLoader loader(browser()->profile());
616     base::FilePath extension_path;
617     EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &extension_path));
618     extension_path = extension_path.AppendASCII("extensions/desktop_capture");
619     desktop_capture_extension_ = loader.LoadExtension(extension_path);
620     LOG(INFO) << "Loaded desktop capture extension, id = "
621               << desktop_capture_extension_->id();
622 
623     extensions::ExtensionRegistry* registry =
624         extensions::ExtensionRegistry::Get(browser()->profile());
625 
626     EXPECT_TRUE(registry->enabled_extensions().GetByID(
627         desktop_capture_extension_->id()));
628   }
629   if (desktop_capture_extension_)
630     extension_id.emplace(desktop_capture_extension_->id());
631   return extension_id;
632 }
633