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 "base/command_line.h"
      6 #include "base/file_util.h"
      7 #include "base/path_service.h"
      8 #include "base/process/launch.h"
      9 #include "base/strings/string_split.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/synchronization/waitable_event.h"
     12 #include "base/test/test_timeouts.h"
     13 #include "base/time/time.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/infobars/infobar.h"
     17 #include "chrome/browser/infobars/infobar_service.h"
     18 #include "chrome/browser/media/media_stream_infobar_delegate.h"
     19 #include "chrome/browser/media/webrtc_browsertest_base.h"
     20 #include "chrome/browser/media/webrtc_browsertest_common.h"
     21 #include "chrome/browser/media/webrtc_log_uploader.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_tabstrip.h"
     25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     26 #include "chrome/common/chrome_switches.h"
     27 #include "chrome/test/base/in_process_browser_test.h"
     28 #include "chrome/test/base/ui_test_utils.h"
     29 #include "chrome/test/ui/ui_test.h"
     30 #include "content/public/browser/browser_message_filter.h"
     31 #include "content/public/browser/notification_service.h"
     32 #include "content/public/browser/render_process_host.h"
     33 #include "content/public/test/browser_test_utils.h"
     34 #include "net/test/embedded_test_server/embedded_test_server.h"
     35 
     36 static const char kMainWebrtcTestHtmlPage[] =
     37     "/webrtc/webrtc_jsep01_test.html";
     38 
     39 static const char kTestLoggingSessionId[] = "0123456789abcdef";
     40 
     41 // Top-level integration test for WebRTC. Requires a real webcam and microphone
     42 // on the running system. This test is not meant to run in the main browser
     43 // test suite since normal tester machines do not have webcams.
     44 class WebrtcBrowserTest : public WebRtcTestBase {
     45  public:
     46   // See comment in test where this class is used for purpose.
     47   class BrowserMessageFilter : public content::BrowserMessageFilter {
     48    public:
     49     explicit BrowserMessageFilter(
     50         const base::Closure& on_channel_closing)
     51         : on_channel_closing_(on_channel_closing) {}
     52 
     53     virtual void OnChannelClosing() OVERRIDE {
     54       // Posting on the file thread ensures that the callback is run after
     55       // WebRtcLogUploader::UploadLog has finished. See also comment in
     56       // MANUAL_RunsAudioVideoWebRTCCallInTwoTabsWithLogging test.
     57       content::BrowserThread::PostTask(content::BrowserThread::FILE,
     58           FROM_HERE, on_channel_closing_);
     59     }
     60 
     61     virtual bool OnMessageReceived(const IPC::Message& message,
     62                                    bool* message_was_ok) OVERRIDE {
     63       return false;
     64     }
     65 
     66   private:
     67     virtual ~BrowserMessageFilter() {}
     68 
     69     base::Closure on_channel_closing_;
     70   };
     71 
     72   virtual void SetUp() OVERRIDE {
     73     // TODO(phoglund): Remove this when the bots enable real GPU with the
     74     // command line. crbug.com/271504
     75     UseRealGLBindings();
     76 
     77     WebRtcTestBase::SetUp();
     78   }
     79 
     80   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     81     PeerConnectionServerRunner::KillAllPeerConnectionServersOnCurrentSystem();
     82     peerconnection_server_.Start();
     83   }
     84 
     85   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
     86     peerconnection_server_.Stop();
     87   }
     88 
     89   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     90     // TODO(phoglund): check that user actually has the requisite devices and
     91     // print a nice message if not; otherwise the test just times out which can
     92     // be confusing.
     93     // This test expects real device handling and requires a real webcam / audio
     94     // device; it will not work with fake devices.
     95     EXPECT_FALSE(command_line->HasSwitch(
     96         switches::kUseFakeDeviceForMediaStream));
     97     EXPECT_FALSE(command_line->HasSwitch(
     98         switches::kUseFakeUIForMediaStream));
     99   }
    100 
    101   // Convenience method which executes the provided javascript in the context
    102   // of the provided web contents and returns what it evaluated to.
    103   std::string ExecuteJavascript(const std::string& javascript,
    104                                 content::WebContents* tab_contents) {
    105     std::string result;
    106     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
    107         tab_contents, javascript, &result));
    108     return result;
    109   }
    110 
    111   // Ensures we didn't get any errors asynchronously (e.g. while no javascript
    112   // call from this test was outstanding).
    113   // TODO(phoglund): this becomes obsolete when we switch to communicating with
    114   // the DOM message queue.
    115   void AssertNoAsynchronousErrors(content::WebContents* tab_contents) {
    116     EXPECT_EQ("ok-no-errors",
    117               ExecuteJavascript("getAnyTestFailures()", tab_contents));
    118   }
    119 
    120   // The peer connection server lets our two tabs find each other and talk to
    121   // each other (e.g. it is the application-specific "signaling solution").
    122   void ConnectToPeerConnectionServer(const std::string peer_name,
    123                                      content::WebContents* tab_contents) {
    124     std::string javascript = base::StringPrintf(
    125         "connect('http://localhost:8888', '%s');", peer_name.c_str());
    126     EXPECT_EQ("ok-connected", ExecuteJavascript(javascript, tab_contents));
    127   }
    128 
    129   void EstablishCall(content::WebContents* from_tab,
    130                      content::WebContents* to_tab,
    131                      bool enable_logging = false) {
    132     std::string javascript = enable_logging ?
    133         base::StringPrintf("preparePeerConnection(\"%s\")",
    134             kTestLoggingSessionId) :
    135         "preparePeerConnection(false)";
    136     EXPECT_EQ("ok-peerconnection-created",
    137               ExecuteJavascript(javascript, from_tab));
    138     EXPECT_EQ("ok-added",
    139               ExecuteJavascript("addLocalStream()", from_tab));
    140     EXPECT_EQ("ok-negotiating",
    141               ExecuteJavascript("negotiateCall()", from_tab));
    142 
    143     // Ensure the call gets up on both sides.
    144     EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
    145                                  "active", from_tab));
    146     EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
    147                                  "active", to_tab));
    148   }
    149 
    150   void StartDetectingVideo(content::WebContents* tab_contents,
    151                            const std::string& video_element) {
    152     std::string javascript = base::StringPrintf(
    153         "startDetection('%s', 'frame-buffer', 320, 240)",
    154         video_element.c_str());
    155     EXPECT_EQ("ok-started", ExecuteJavascript(javascript, tab_contents));
    156   }
    157 
    158   void WaitForVideoToPlay(content::WebContents* tab_contents) {
    159     EXPECT_TRUE(PollingWaitUntil("isVideoPlaying()", "video-playing",
    160                                  tab_contents));
    161   }
    162 
    163   void WaitForVideoToStopPlaying(content::WebContents* tab_contents) {
    164     EXPECT_TRUE(PollingWaitUntil("isVideoPlaying()", "video-not-playing",
    165                                  tab_contents));
    166   }
    167 
    168   void HangUp(content::WebContents* from_tab) {
    169     EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab));
    170   }
    171 
    172   void WaitUntilHangupVerified(content::WebContents* tab_contents) {
    173     EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
    174                                  "no-peer-connection", tab_contents));
    175   }
    176 
    177   std::string ToggleLocalVideoTrack(content::WebContents* tab_contents) {
    178     // Toggle the only video track in the page (e.g. video track 0).
    179     return ExecuteJavascript("toggleLocalStream("
    180         "function(local) { return local.getVideoTracks()[0]; }, "
    181         "'video');", tab_contents);
    182   }
    183 
    184   std::string ToggleRemoteVideoTrack(content::WebContents* tab_contents) {
    185     // Toggle the only video track in the page (e.g. video track 0).
    186     return ExecuteJavascript("toggleRemoteStream("
    187         "function(local) { return local.getVideoTracks()[0]; }, "
    188         "'video');", tab_contents);
    189   }
    190 
    191  private:
    192   PeerConnectionServerRunner peerconnection_server_;
    193 };
    194 
    195 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
    196                        MANUAL_RunsAudioVideoWebRTCCallInTwoTabs) {
    197   EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    198 
    199   ui_test_utils::NavigateToURL(
    200       browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    201   content::WebContents* left_tab =
    202       browser()->tab_strip_model()->GetActiveWebContents();
    203   GetUserMediaAndAccept(left_tab);
    204 
    205   chrome::AddBlankTabAt(browser(), -1, true);
    206   content::WebContents* right_tab =
    207       browser()->tab_strip_model()->GetActiveWebContents();
    208   ui_test_utils::NavigateToURL(
    209         browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    210   GetUserMediaAndAccept(right_tab);
    211 
    212   ConnectToPeerConnectionServer("peer 1", left_tab);
    213   ConnectToPeerConnectionServer("peer 2", right_tab);
    214 
    215   EstablishCall(left_tab, right_tab);
    216 
    217   AssertNoAsynchronousErrors(left_tab);
    218   AssertNoAsynchronousErrors(right_tab);
    219 
    220   StartDetectingVideo(left_tab, "remote-view");
    221   StartDetectingVideo(right_tab, "remote-view");
    222 
    223   WaitForVideoToPlay(left_tab);
    224   WaitForVideoToPlay(right_tab);
    225 
    226   HangUp(left_tab);
    227   WaitUntilHangupVerified(left_tab);
    228   WaitUntilHangupVerified(right_tab);
    229 
    230   AssertNoAsynchronousErrors(left_tab);
    231   AssertNoAsynchronousErrors(right_tab);
    232 }
    233 
    234 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
    235                        MANUAL_TestMediaStreamTrackEnableDisable) {
    236   EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    237 
    238   ui_test_utils::NavigateToURL(
    239       browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    240   content::WebContents* left_tab =
    241       browser()->tab_strip_model()->GetActiveWebContents();
    242   GetUserMediaAndAccept(left_tab);
    243 
    244   chrome::AddBlankTabAt(browser(), -1, true);
    245   content::WebContents* right_tab =
    246       browser()->tab_strip_model()->GetActiveWebContents();
    247   ui_test_utils::NavigateToURL(
    248         browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    249   GetUserMediaAndAccept(right_tab);
    250 
    251   ConnectToPeerConnectionServer("peer 1", left_tab);
    252   ConnectToPeerConnectionServer("peer 2", right_tab);
    253 
    254   EstablishCall(left_tab, right_tab);
    255 
    256   AssertNoAsynchronousErrors(left_tab);
    257   AssertNoAsynchronousErrors(right_tab);
    258 
    259   StartDetectingVideo(left_tab, "remote-view");
    260   StartDetectingVideo(right_tab, "remote-view");
    261 
    262   WaitForVideoToPlay(left_tab);
    263   WaitForVideoToPlay(right_tab);
    264 
    265   EXPECT_EQ("ok-video-toggled-to-false", ToggleLocalVideoTrack(left_tab));
    266 
    267   WaitForVideoToStopPlaying(right_tab);
    268 
    269   EXPECT_EQ("ok-video-toggled-to-true", ToggleLocalVideoTrack(left_tab));
    270 
    271   WaitForVideoToPlay(right_tab);
    272 
    273   HangUp(left_tab);
    274   WaitUntilHangupVerified(left_tab);
    275   WaitUntilHangupVerified(right_tab);
    276 
    277   AssertNoAsynchronousErrors(left_tab);
    278   AssertNoAsynchronousErrors(right_tab);
    279 }
    280 
    281 // Tests WebRTC diagnostic logging. Sets up the browser to save the multipart
    282 // contents to a buffer instead of uploading it, then verifies it after a call.
    283 // Example of multipart contents:
    284 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    285 // Content-Disposition: form-data; name="prod"
    286 //
    287 // Chrome_Linux
    288 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    289 // Content-Disposition: form-data; name="ver"
    290 //
    291 // 30.0.1554.0
    292 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    293 // Content-Disposition: form-data; name="guid"
    294 //
    295 // 0
    296 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    297 // Content-Disposition: form-data; name="type"
    298 //
    299 // webrtc_log
    300 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    301 // Content-Disposition: form-data; name="app_session_id"
    302 //
    303 // 0123456789abcdef
    304 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    305 // Content-Disposition: form-data; name="url"
    306 //
    307 // http://127.0.0.1:43213/webrtc/webrtc_jsep01_test.html
    308 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**----
    309 // Content-Disposition: form-data; name="webrtc_log"; filename="webrtc_log.gz"
    310 // Content-Type: application/gzip
    311 //
    312 // <compressed data (zip)>
    313 // ------**--yradnuoBgoLtrapitluMklaTelgooG--**------
    314 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
    315                        MANUAL_RunsAudioVideoWebRTCCallInTwoTabsWithLogging) {
    316   EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    317 
    318   // Add command line switch that forces allowing log uploads.
    319   CommandLine* command_line = CommandLine::ForCurrentProcess();
    320   command_line->AppendSwitch(switches::kEnableMetricsReportingForTesting);
    321 
    322   // Tell the uploader to save the multipart to a buffer instead of uploading.
    323   std::string multipart;
    324   g_browser_process->webrtc_log_uploader()->
    325       OverrideUploadWithBufferForTesting(&multipart);
    326   ui_test_utils::NavigateToURL(
    327       browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    328   content::WebContents* left_tab =
    329       browser()->tab_strip_model()->GetActiveWebContents();
    330   GetUserMediaAndAccept(left_tab);
    331 
    332   chrome::AddBlankTabAt(browser(), -1, true);
    333   content::WebContents* right_tab =
    334       browser()->tab_strip_model()->GetActiveWebContents();
    335   ui_test_utils::NavigateToURL(
    336       browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
    337   GetUserMediaAndAccept(right_tab);
    338 
    339   ConnectToPeerConnectionServer("peer 1", left_tab);
    340   ConnectToPeerConnectionServer("peer 2", right_tab);
    341 
    342   EstablishCall(left_tab, right_tab, true);
    343 
    344   AssertNoAsynchronousErrors(left_tab);
    345   AssertNoAsynchronousErrors(right_tab);
    346 
    347   StartDetectingVideo(left_tab, "remote-view");
    348   StartDetectingVideo(right_tab, "remote-view");
    349 
    350   WaitForVideoToPlay(left_tab);
    351   WaitForVideoToPlay(right_tab);
    352 
    353   HangUp(left_tab);
    354   WaitUntilHangupVerified(left_tab);
    355   WaitUntilHangupVerified(right_tab);
    356 
    357   AssertNoAsynchronousErrors(left_tab);
    358   AssertNoAsynchronousErrors(right_tab);
    359 
    360   // Uploading (or storing to our buffer in our test case) is triggered when
    361   // the tab is closed. We must ensure that WebRtcLogUploader::UploadLog, which
    362   // runs on the FILE thread, has finished after closing the tab before
    363   // continuing.
    364   // 1. Add a filter which just acts as a listener. It's added after
    365   //    WebRtcLoggingHandlerHost, which is the filter that posts a task for
    366   //    WebRtcLogUploader::UploadLog. So it's guarantueed to be removed after
    367   //    WebRtcLoggingHandlerHost.
    368   // 2. When the filter goes away post a task on the file thread to signal the
    369   //    event.
    370   base::WaitableEvent ipc_channel_closed(false, false);
    371   left_tab->GetRenderProcessHost()->GetChannel()->AddFilter(
    372       new BrowserMessageFilter(base::Bind(
    373           &base::WaitableEvent::Signal,
    374           base::Unretained(&ipc_channel_closed))));
    375   chrome::CloseWebContents(browser(), left_tab, false);
    376   ASSERT_TRUE(ipc_channel_closed.TimedWait(TestTimeouts::action_timeout()));
    377 
    378   const char boundary[] = "------**--yradnuoBgoLtrapitluMklaTelgooG--**----";
    379 
    380   // Remove the compressed data, it may contain "\r\n". Just verify that its
    381   // size is > 0.
    382   const char zip_content_type[] = "Content-Type: application/gzip";
    383   size_t zip_pos = multipart.find(&zip_content_type[0]);
    384   ASSERT_NE(std::string::npos, zip_pos);
    385   // Move pos to where the zip begins. - 1 to remove '\0', + 4 for two "\r\n".
    386   zip_pos += sizeof(zip_content_type) + 3;
    387   size_t zip_length = multipart.find(boundary, zip_pos);
    388   ASSERT_NE(std::string::npos, zip_length);
    389   // Calculate length, adjust for a "\r\n".
    390   zip_length -= zip_pos + 2;
    391   ASSERT_GT(zip_length, 0u);
    392   multipart.erase(zip_pos, zip_length);
    393 
    394   // Check the multipart contents.
    395   std::vector<std::string> multipart_lines;
    396   base::SplitStringUsingSubstr(multipart, "\r\n", &multipart_lines);
    397   ASSERT_EQ(31, static_cast<int>(multipart_lines.size()));
    398 
    399   EXPECT_STREQ(&boundary[0], multipart_lines[0].c_str());
    400   EXPECT_STREQ("Content-Disposition: form-data; name=\"prod\"",
    401                multipart_lines[1].c_str());
    402   EXPECT_TRUE(multipart_lines[2].empty());
    403   EXPECT_NE(std::string::npos, multipart_lines[3].find("Chrome"));
    404 
    405   EXPECT_STREQ(&boundary[0], multipart_lines[4].c_str());
    406   EXPECT_STREQ("Content-Disposition: form-data; name=\"ver\"",
    407                multipart_lines[5].c_str());
    408   EXPECT_TRUE(multipart_lines[6].empty());
    409   // Just check that the version contains a dot.
    410   EXPECT_NE(std::string::npos, multipart_lines[7].find('.'));
    411 
    412   EXPECT_STREQ(&boundary[0], multipart_lines[8].c_str());
    413   EXPECT_STREQ("Content-Disposition: form-data; name=\"guid\"",
    414                multipart_lines[9].c_str());
    415   EXPECT_TRUE(multipart_lines[10].empty());
    416   EXPECT_STREQ("0", multipart_lines[11].c_str());
    417 
    418   EXPECT_STREQ(&boundary[0], multipart_lines[12].c_str());
    419   EXPECT_STREQ("Content-Disposition: form-data; name=\"type\"",
    420                multipart_lines[13].c_str());
    421   EXPECT_TRUE(multipart_lines[14].empty());
    422   EXPECT_STREQ("webrtc_log", multipart_lines[15].c_str());
    423 
    424   EXPECT_STREQ(&boundary[0], multipart_lines[16].c_str());
    425   EXPECT_STREQ("Content-Disposition: form-data; name=\"app_session_id\"",
    426                multipart_lines[17].c_str());
    427   EXPECT_TRUE(multipart_lines[18].empty());
    428   EXPECT_STREQ(kTestLoggingSessionId, multipart_lines[19].c_str());
    429 
    430   EXPECT_STREQ(&boundary[0], multipart_lines[20].c_str());
    431   EXPECT_STREQ("Content-Disposition: form-data; name=\"url\"",
    432                multipart_lines[21].c_str());
    433   EXPECT_TRUE(multipart_lines[22].empty());
    434   EXPECT_NE(std::string::npos,
    435             multipart_lines[23].find(&kMainWebrtcTestHtmlPage[0]));
    436 
    437   EXPECT_STREQ(&boundary[0], multipart_lines[24].c_str());
    438   EXPECT_STREQ("Content-Disposition: form-data; name=\"webrtc_log\";"
    439                " filename=\"webrtc_log.gz\"",
    440                multipart_lines[25].c_str());
    441   EXPECT_STREQ("Content-Type: application/gzip",
    442                multipart_lines[26].c_str());
    443   EXPECT_TRUE(multipart_lines[27].empty());
    444   EXPECT_TRUE(multipart_lines[28].empty());  // The removed zip part.
    445   std::string final_delimiter = boundary;
    446   final_delimiter += "--";
    447   EXPECT_STREQ(final_delimiter.c_str(), multipart_lines[29].c_str());
    448   EXPECT_TRUE(multipart_lines[30].empty());
    449 }
    450