Home | History | Annotate | Download | only in media
      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