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/deferred_sequenced_task_runner.h"
7 #include "base/test/bind.h"
8 #include "build/build_config.h"
9 #include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
10 #include "chrome/browser/media/webrtc/webrtc_browsertest_common.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_tabstrip.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/network_service_instance.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/common/network_service_util.h"
20 #include "content/public/test/browser_test.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "media/base/media_switches.h"
23 #include "mojo/public/cpp/bindings/remote.h"
24 #include "net/nqe/network_quality_estimator.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26 #include "services/network/network_service.h"
27 #include "services/network/public/cpp/features.h"
28 #include "services/network/public/mojom/network_service_test.mojom.h"
29 #include "third_party/blink/public/common/features.h"
30 
31 #if defined(OS_MAC)
32 #include "base/mac/mac_util.h"
33 #endif
34 
35 static const char kMainWebrtcTestHtmlPage[] =
36     "/webrtc/webrtc_jsep01_test.html";
37 
38 static const char kKeygenAlgorithmRsa[] =
39     "{ name: \"RSASSA-PKCS1-v1_5\", modulusLength: 2048, publicExponent: "
40     "new Uint8Array([1, 0, 1]), hash: \"SHA-256\" }";
41 static const char kKeygenAlgorithmEcdsa[] =
42     "{ name: \"ECDSA\", namedCurve: \"P-256\" }";
43 
44 // Top-level integration test for WebRTC. It always uses fake devices; see
45 // WebRtcWebcamBrowserTest for a test that acquires any real webcam on the
46 // system.
47 class WebRtcBrowserTest : public WebRtcTestBase {
48  public:
WebRtcBrowserTest()49   WebRtcBrowserTest() : left_tab_(nullptr), right_tab_(nullptr) {}
50 
SetUpInProcessBrowserTestFixture()51   void SetUpInProcessBrowserTestFixture() override {
52     DetectErrorsInJavaScript();  // Look for errors in our rather complex js.
53   }
54 
SetUpCommandLine(base::CommandLine * command_line)55   void SetUpCommandLine(base::CommandLine* command_line) override {
56     // Ensure the infobar is enabled, since we expect that in this test.
57     EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));
58 
59     // Flag used by TestWebAudioMediaStream to force garbage collection.
60     command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
61   }
62 
RunsAudioVideoWebRTCCallInTwoTabs(const std::string & video_codec=WebRtcTestBase::kUseDefaultVideoCodec,bool prefer_hw_video_codec=false,const std::string & offer_cert_keygen_alg=WebRtcTestBase::kUseDefaultCertKeygen,const std::string & answer_cert_keygen_alg=WebRtcTestBase::kUseDefaultCertKeygen)63   void RunsAudioVideoWebRTCCallInTwoTabs(
64       const std::string& video_codec = WebRtcTestBase::kUseDefaultVideoCodec,
65       bool prefer_hw_video_codec = false,
66       const std::string& offer_cert_keygen_alg =
67           WebRtcTestBase::kUseDefaultCertKeygen,
68       const std::string& answer_cert_keygen_alg =
69           WebRtcTestBase::kUseDefaultCertKeygen) {
70     StartServerAndOpenTabs();
71 
72     SetupPeerconnectionWithLocalStream(left_tab_, offer_cert_keygen_alg);
73     SetupPeerconnectionWithLocalStream(right_tab_, answer_cert_keygen_alg);
74 
75     if (!video_codec.empty()) {
76       SetDefaultVideoCodec(left_tab_, video_codec, prefer_hw_video_codec);
77       SetDefaultVideoCodec(right_tab_, video_codec, prefer_hw_video_codec);
78     }
79     NegotiateCall(left_tab_, right_tab_);
80 
81     DetectVideoAndHangUp();
82   }
83 
RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(const std::string & cert_keygen_alg=WebRtcTestBase::kUseDefaultCertKeygen)84   void RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(
85       const std::string& cert_keygen_alg =
86           WebRtcTestBase::kUseDefaultCertKeygen) {
87     StartServerAndOpenTabs();
88 
89     // Generate and clone a certificate, resulting in JavaScript variable
90     // |gCertificateClone| being set to the resulting clone.
91     DeleteDatabase(left_tab_);
92     OpenDatabase(left_tab_);
93     GenerateAndCloneCertificate(left_tab_, cert_keygen_alg);
94     CloseDatabase(left_tab_);
95     DeleteDatabase(left_tab_);
96 
97     SetupPeerconnectionWithCertificateAndLocalStream(
98         left_tab_, "gCertificateClone");
99     SetupPeerconnectionWithLocalStream(right_tab_, cert_keygen_alg);
100 
101     NegotiateCall(left_tab_, right_tab_);
102     VerifyLocalDescriptionContainsCertificate(left_tab_, "gCertificate");
103 
104     DetectVideoAndHangUp();
105   }
106 
GetPeerToPeerConnectionsCountChangeFromNetworkService()107   uint32_t GetPeerToPeerConnectionsCountChangeFromNetworkService() {
108     uint32_t connection_count = 0u;
109     if (content::IsInProcessNetworkService()) {
110       base::RunLoop run_loop;
111       content::GetNetworkTaskRunner()->PostTask(
112           FROM_HERE, base::BindLambdaForTesting([&connection_count, &run_loop] {
113             connection_count =
114                 network::NetworkService::GetNetworkServiceForTesting()
115                     ->network_quality_estimator()
116                     ->GetPeerToPeerConnectionsCountChange();
117             run_loop.Quit();
118           }));
119       run_loop.Run();
120       return connection_count;
121     }
122 
123     mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
124     content::GetNetworkService()->BindTestInterface(
125         network_service_test.BindNewPipeAndPassReceiver());
126     // TODO(crbug.com/901026): Make sure the network process is started to avoid
127     // a deadlock on Android.
128     network_service_test.FlushForTesting();
129 
130     mojo::ScopedAllowSyncCallForTesting allow_sync_call;
131 
132     bool available = network_service_test->GetPeerToPeerConnectionsCountChange(
133         &connection_count);
134     EXPECT_TRUE(available);
135 
136     return connection_count;
137   }
138 
139  protected:
StartServerAndOpenTabs()140   void StartServerAndOpenTabs() {
141     ASSERT_TRUE(embedded_test_server()->Start());
142     left_tab_ = OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
143     right_tab_ = OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
144   }
145 
DetectVideoAndHangUp()146   void DetectVideoAndHangUp() {
147     StartDetectingVideo(left_tab_, "remote-view");
148     StartDetectingVideo(right_tab_, "remote-view");
149 #if !defined(OS_MAC)
150     // Video is choppy on Mac OS X. http://crbug.com/443542.
151     WaitForVideoToPlay(left_tab_);
152     WaitForVideoToPlay(right_tab_);
153 #endif
154     HangUp(left_tab_);
155     HangUp(right_tab_);
156   }
157 
158   content::WebContents* left_tab_;
159   content::WebContents* right_tab_;
160 };
161 
162 // TODO(898546): many of these tests are failing on ASan builds.
163 // They are also flaky crashers on Linux.
164 #if defined(ADDRESS_SANITIZER) || defined(OS_LINUX) || defined(OS_CHROMEOS)
165 #define MAYBE_WebRtcBrowserTest DISABLED_WebRtcBrowserTest
166 class DISABLED_WebRtcBrowserTest : public WebRtcBrowserTest {};
167 #else
168 #define MAYBE_WebRtcBrowserTest WebRtcBrowserTest
169 #endif
170 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsVP8)171 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
172                        RunsAudioVideoWebRTCCallInTwoTabsVP8) {
173   RunsAudioVideoWebRTCCallInTwoTabs("VP8");
174 }
175 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsVP9)176 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
177                        RunsAudioVideoWebRTCCallInTwoTabsVP9) {
178   RunsAudioVideoWebRTCCallInTwoTabs("VP9");
179 }
180 
181 #if BUILDFLAG(RTC_USE_H264)
182 
IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsH264)183 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
184                        RunsAudioVideoWebRTCCallInTwoTabsH264) {
185   // Only run test if run-time feature corresponding to |rtc_use_h264| is on.
186   if (!base::FeatureList::IsEnabled(
187           blink::features::kWebRtcH264WithOpenH264FFmpeg)) {
188     LOG(WARNING) << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. "
189         "Skipping WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsH264 "
190         "(test \"OK\")";
191     return;
192   }
193 
194 #if defined(OS_MAC)
195   // TODO(jam): this test only on 10.12.
196   if (base::mac::IsOS10_12())
197     return;
198 #endif
199 
200   RunsAudioVideoWebRTCCallInTwoTabs("H264", true /* prefer_hw_video_codec */);
201 }
202 
203 #endif  // BUILDFLAG(RTC_USE_H264)
204 
IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,TestWebAudioMediaStream)205 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest, TestWebAudioMediaStream) {
206   // This tests against crash regressions for the WebAudio-MediaStream
207   // integration.
208   ASSERT_TRUE(embedded_test_server()->Start());
209   GURL url(embedded_test_server()->GetURL("/webrtc/webaudio_crash.html"));
210   ui_test_utils::NavigateToURL(browser(), url);
211   content::WebContents* tab =
212       browser()->tab_strip_model()->GetActiveWebContents();
213 
214   // A sleep is necessary to be able to detect the crash.
215   test::SleepInJavascript(tab, 1000);
216 
217   ASSERT_FALSE(tab->IsCrashed());
218 }
219 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa)220 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
221                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa) {
222   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
223                                     false /* prefer_hw_video_codec */,
224                                     kKeygenAlgorithmRsa, kKeygenAlgorithmRsa);
225 }
226 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerEcdsa)227 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
228                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerEcdsa) {
229   RunsAudioVideoWebRTCCallInTwoTabs(
230       WebRtcTestBase::kUseDefaultVideoCodec, false /* prefer_hw_video_codec */,
231       kKeygenAlgorithmEcdsa, kKeygenAlgorithmEcdsa);
232 }
233 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateRsa)234 IN_PROC_BROWSER_TEST_F(
235     MAYBE_WebRtcBrowserTest,
236     RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateRsa) {
237   RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(kKeygenAlgorithmRsa);
238 }
239 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateEcdsa)240 IN_PROC_BROWSER_TEST_F(
241     MAYBE_WebRtcBrowserTest,
242     RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateEcdsa) {
243   RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificate(kKeygenAlgorithmEcdsa);
244 }
245 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa)246 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
247                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa) {
248   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
249                                     false /* prefer_hw_video_codec */,
250                                     kKeygenAlgorithmRsa, kKeygenAlgorithmEcdsa);
251 }
252 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa)253 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
254                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa) {
255   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
256                                     false /* prefer_hw_video_codec */,
257                                     kKeygenAlgorithmEcdsa, kKeygenAlgorithmRsa);
258 }
259 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback)260 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
261                        RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback) {
262   StartServerAndOpenTabs();
263   SetupPeerconnectionWithLocalStream(left_tab_);
264   SetupPeerconnectionWithLocalStream(right_tab_);
265   NegotiateCall(left_tab_, right_tab_);
266 
267   VerifyStatsGeneratedCallback(left_tab_);
268 
269   DetectVideoAndHangUp();
270 }
271 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,GetPeerToPeerConnectionsCountChangeFromNetworkService)272 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
273                        GetPeerToPeerConnectionsCountChangeFromNetworkService) {
274   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
275 
276   StartServerAndOpenTabs();
277   SetupPeerconnectionWithLocalStream(left_tab_);
278 
279   SetupPeerconnectionWithLocalStream(right_tab_);
280   NegotiateCall(left_tab_, right_tab_);
281 
282   VerifyStatsGeneratedCallback(left_tab_);
283   EXPECT_EQ(2u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
284 
285   DetectVideoAndHangUp();
286   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
287 }
288 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise)289 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
290                        RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise) {
291   StartServerAndOpenTabs();
292   SetupPeerconnectionWithLocalStream(left_tab_);
293   SetupPeerconnectionWithLocalStream(right_tab_);
294   CreateDataChannel(left_tab_, "data");
295   CreateDataChannel(right_tab_, "data");
296   NegotiateCall(left_tab_, right_tab_);
297 
298   std::set<std::string> missing_expected_stats;
299   for (const std::string& type : GetMandatoryStatsTypes(left_tab_)) {
300     missing_expected_stats.insert(type);
301   }
302   for (const std::string& type : VerifyStatsGeneratedPromise(left_tab_)) {
303     missing_expected_stats.erase(type);
304   }
305   for (const std::string& type : missing_expected_stats) {
306     EXPECT_TRUE(false) << "Expected stats dictionary is missing: " << type;
307   }
308 
309   DetectVideoAndHangUp();
310 }
311 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange)312 IN_PROC_BROWSER_TEST_F(
313     MAYBE_WebRtcBrowserTest,
314     RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange) {
315   StartServerAndOpenTabs();
316   SetupPeerconnectionWithLocalStream(left_tab_);
317   SetupPeerconnectionWithLocalStream(right_tab_);
318   NegotiateCall(left_tab_, right_tab_);
319 
320   std::string ice_gatheringstate =
321       ExecuteJavascript("getLastGatheringState()", left_tab_);
322 
323   EXPECT_EQ("complete", ice_gatheringstate);
324   DetectVideoAndHangUp();
325 }
326 
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange_ConnectionCount)327 IN_PROC_BROWSER_TEST_F(
328     MAYBE_WebRtcBrowserTest,
329     RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange_ConnectionCount) {
330   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
331   StartServerAndOpenTabs();
332   SetupPeerconnectionWithLocalStream(left_tab_);
333   SetupPeerconnectionWithLocalStream(right_tab_);
334   NegotiateCall(left_tab_, right_tab_);
335   EXPECT_EQ(2u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
336 
337   std::string ice_gatheringstate =
338       ExecuteJavascript("getLastGatheringState()", left_tab_);
339 
340   EXPECT_EQ("complete", ice_gatheringstate);
341   DetectVideoAndHangUp();
342   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
343 }
344