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 #ifndef CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_BROWSERTEST_BASE_H_
6 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_BROWSERTEST_BASE_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/optional.h"
14 #include "chrome/browser/media/webrtc/test_stats_dictionary.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 
17 namespace infobars {
18 class InfoBar;
19 }
20 
21 namespace content {
22 class WebContents;
23 }
24 
25 namespace extensions {
26 class Extension;
27 }
28 
29 // Base class for WebRTC browser tests with useful primitives for interacting
30 // getUserMedia. We use inheritance here because it makes the test code look
31 // as clean as it can be.
32 class WebRtcTestBase : public InProcessBrowserTest {
33  public:
34   // Typical constraints.
35   static const char kAudioVideoCallConstraints[];
36   static const char kAudioOnlyCallConstraints[];
37   static const char kVideoOnlyCallConstraints[];
38   static const char kVideoCallConstraintsQVGA[];
39   static const char kVideoCallConstraints360p[];
40   static const char kVideoCallConstraintsVGA[];
41   static const char kVideoCallConstraints720p[];
42   static const char kVideoCallConstraints1080p[];
43   static const char kAudioVideoCallConstraints360p[];
44   static const char kAudioVideoCallConstraints720p[];
45 
46   static const char kOkGotStream[];
47   static const char kFailedWithNotAllowedError[];
48 
49   static const char kUseDefaultCertKeygen[];
50   static const char kUseDefaultAudioCodec[];
51   static const char kUseDefaultVideoCodec[];
52 
53   static const char kVP9Profile0Specifier[];
54   static const char kVP9Profile2Specifier[];
55 
56   static const char kUndefined[];
57 
58   enum class StreamArgumentType {
59     NO_STREAM,
60     SHARED_STREAM,
61     INDIVIDUAL_STREAMS
62   };
63 
64  protected:
65   WebRtcTestBase();
66   ~WebRtcTestBase() override;
67 
68   // These all require that the loaded page fulfills the public interface in
69   // chrome/test/data/webrtc/getusermedia.js.
70   // If an error is reported back from the getUserMedia call, these functions
71   // will return false.
72   // The ...AndAccept()/...AndDeny()/...AndDismiss() functions expect that a
73   // prompt will be shown (i.e. the current origin in the tab_contents doesn't
74   // have a saved permission).
75   bool GetUserMediaAndAccept(content::WebContents* tab_contents) const;
76   bool GetUserMediaWithSpecificConstraintsAndAccept(
77       content::WebContents* tab_contents,
78       const std::string& constraints) const;
79   bool GetUserMediaWithSpecificConstraintsAndAcceptIfPrompted(
80       content::WebContents* tab_contents,
81       const std::string& constraints) const;
82   void GetUserMediaAndDeny(content::WebContents* tab_contents);
83   void GetUserMediaWithSpecificConstraintsAndDeny(
84       content::WebContents* tab_contents,
85       const std::string& constraints) const;
86   void GetUserMediaAndDismiss(content::WebContents* tab_contents) const;
87   void GetUserMediaAndExpectAutoAcceptWithoutPrompt(
88       content::WebContents* tab_contents) const;
89   void GetUserMediaAndExpectAutoDenyWithoutPrompt(
90       content::WebContents* tab_contents) const;
91   void GetUserMedia(content::WebContents* tab_contents,
92                     const std::string& constraints) const;
93 
94   // Convenience method which opens the page at url, calls GetUserMediaAndAccept
95   // and returns the new tab.
96   content::WebContents* OpenPageAndGetUserMediaInNewTab(const GURL& url) const;
97 
98   // Convenience method which opens the page at url, calls
99   // GetUserMediaAndAcceptWithSpecificConstraints and returns the new tab.
100   content::WebContents* OpenPageAndGetUserMediaInNewTabWithConstraints(
101       const GURL& url, const std::string& constraints) const;
102 
103   // Convenience method which gets the URL for |test_page| and calls
104   // OpenPageAndGetUserMediaInNewTab().
105   content::WebContents* OpenTestPageAndGetUserMediaInNewTab(
106     const std::string& test_page) const;
107 
108   // Convenience method which gets the URL for |test_page|, but without calling
109   // GetUserMedia.
110   content::WebContents* OpenTestPageInNewTab(
111       const std::string& test_page) const;
112 
113   // Closes the last local stream acquired by the GetUserMedia* methods.
114   void CloseLastLocalStream(content::WebContents* tab_contents) const;
115 
116   std::string ExecuteJavascript(const std::string& javascript,
117                                 content::WebContents* tab_contents) const;
118 
119   // TODO(https://crbug.com/1004239): Remove this function as soon as browser
120   // tests stop relying on the legacy getStats() API.
121   void ChangeToLegacyGetStats(content::WebContents* tab) const;
122 
123   // Sets up a peer connection in the tab and adds the current local stream
124   // (which you can prepare by calling one of the GetUserMedia* methods above).
125   // Optionally, |certificate_keygen_algorithm| is JavaScript for an
126   // |AlgorithmIdentifier| to be used as parameter to
127   // |RTCPeerConnection.generateCertificate|. The resulting certificate will be
128   // used by the peer connection. Or use |kUseDefaultCertKeygen| to use a
129   // certificate.
130   void SetupPeerconnectionWithLocalStream(
131       content::WebContents* tab,
132       const std::string& certificate_keygen_algorithm =
133           kUseDefaultCertKeygen) const;
134   // Same as above but does not add the local stream.
135   void SetupPeerconnectionWithoutLocalStream(
136       content::WebContents* tab,
137       const std::string& certificate_keygen_algorithm =
138           kUseDefaultCertKeygen) const;
139   // Same as |SetupPeerconnectionWithLocalStream| except a certificate is
140   // specified, which is a reference to an |RTCCertificate| object.
141   void SetupPeerconnectionWithCertificateAndLocalStream(
142       content::WebContents* tab,
143       const std::string& certificate) const;
144   // Same as above but does not add the local stream.
145   void SetupPeerconnectionWithCertificateWithoutLocalStream(
146       content::WebContents* tab,
147       const std::string& certificate) const;
148   // Same as |SetupPeerconnectionWithLocalStream| except RTCPeerConnection
149   // constraints are specified.
150   void SetupPeerconnectionWithConstraintsAndLocalStream(
151       content::WebContents* tab,
152       const std::string& constraints,
153       const std::string& certificate_keygen_algorithm =
154           kUseDefaultCertKeygen) const;
155 
156   void CreateDataChannel(content::WebContents* tab, const std::string& label);
157 
158   // Exchanges offers and answers between the peer connections in the
159   // respective tabs. Before calling this, you must have prepared peer
160   // connections in both tabs and configured them as you like (for instance by
161   // calling SetupPeerconnectionWithLocalStream).
162   // If |video_codec| is not |kUseDefaultVideoCodec|, the SDP offer is modified
163   // (and SDP answer verified) so that the specified video codec (case-sensitive
164   // name) is used during the call instead of the default one.
165   void NegotiateCall(content::WebContents* from_tab,
166                      content::WebContents* to_tab) const;
167 
168   void VerifyLocalDescriptionContainsCertificate(
169       content::WebContents* tab,
170       const std::string& certificate) const;
171 
172   // Hangs up a negotiated call.
173   void HangUp(content::WebContents* from_tab) const;
174 
175   // Call this to enable monitoring of javascript errors for this test method.
176   // This will only work if the tests are run sequentially by the test runner
177   // (i.e. with --test-launcher-developer-mode or --test-launcher-jobs=1).
178   void DetectErrorsInJavaScript();
179 
180   // Methods for detecting if video is playing (the loaded page must have
181   // chrome/test/data/webrtc/video_detector.js and its dependencies loaded to
182   // make that work). Looks at a 320x240 area of the target video tag.
183   void StartDetectingVideo(content::WebContents* tab_contents,
184                            const std::string& video_element) const;
185 
186   // Wait for a video to start/stop playing. StartDetectingVideo must have
187   // been called already.
188   bool WaitForVideoToPlay(content::WebContents* tab_contents) const;
189   bool WaitForVideoToStop(content::WebContents* tab_contents) const;
190 
191   // Returns the stream size as a string on the format <width>x<height>.
192   std::string GetStreamSize(content::WebContents* tab_contents,
193                             const std::string& video_element) const;
194 
195   // Returns true if we're on Windows 8 or higher.
196   bool OnWin8OrHigher() const;
197 
198   void OpenDatabase(content::WebContents* tab) const;
199   void CloseDatabase(content::WebContents* tab) const;
200   void DeleteDatabase(content::WebContents* tab) const;
201 
202   void GenerateAndCloneCertificate(content::WebContents* tab,
203                                    const std::string& keygen_algorithm) const;
204 
205   void VerifyStatsGeneratedCallback(content::WebContents* tab) const;
206   double MeasureGetStatsCallbackPerformance(content::WebContents* tab) const;
207   std::vector<std::string> VerifyStatsGeneratedPromise(
208       content::WebContents* tab) const;
209   scoped_refptr<content::TestStatsReportDictionary> GetStatsReportDictionary(
210       content::WebContents* tab) const;
211   double MeasureGetStatsPerformance(content::WebContents* tab) const;
212   std::vector<std::string> GetMandatoryStatsTypes(
213       content::WebContents* tab) const;
214 
215   // Change the default audio/video codec in the offer SDP.
216   void SetDefaultAudioCodec(content::WebContents* tab,
217                             const std::string& audio_codec) const;
218   // |prefer_hw_codec| controls what codec with name |video_codec| (and with
219   // profile |profile| if given)should be selected. This parameter only matters
220   // if there are multiple codecs with the same name, which can be the case for
221   // H264.
222   void SetDefaultVideoCodec(content::WebContents* tab,
223                             const std::string& video_codec,
224                             bool prefer_hw_codec = false,
225                             const std::string& profile = std::string()) const;
226 
227   // Add 'usedtx=1' to the offer SDP.
228   void EnableOpusDtx(content::WebContents* tab) const;
229 
230   // Try to open a dekstop media stream, and return the stream id.
231   // On failure, will return empty string.
232   std::string GetDesktopMediaStream(content::WebContents* tab);
233   base::Optional<std::string> LoadDesktopCaptureExtension();
234 
235  private:
236   void CloseInfoBarInTab(content::WebContents* tab_contents,
237                          infobars::InfoBar* infobar) const;
238 
239   std::string CreateLocalOffer(content::WebContents* from_tab) const;
240   std::string CreateAnswer(std::string local_offer,
241                            content::WebContents* to_tab) const;
242   void ReceiveAnswer(const std::string& answer,
243                      content::WebContents* from_tab) const;
244   void GatherAndSendIceCandidates(content::WebContents* from_tab,
245                                   content::WebContents* to_tab) const;
246   bool HasStreamWithTrack(content::WebContents* tab,
247                           const char* function_name,
248                           std::string stream_id,
249                           std::string track_id) const;
250 
251   infobars::InfoBar* GetUserMediaAndWaitForInfoBar(
252       content::WebContents* tab_contents,
253       const std::string& constraints) const;
254 
255   bool detect_errors_in_javascript_;
256   scoped_refptr<const extensions::Extension> desktop_capture_extension_;
257 
258   DISALLOW_COPY_AND_ASSIGN(WebRtcTestBase);
259 };
260 
261 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_BROWSERTEST_BASE_H_
262