1 // Copyright 2014 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/json/json_reader.h"
7 #include "base/strings/string_util.h"
8 #include "base/test/scoped_feature_list.h"
9 #include "build/build_config.h"
10 #include "chrome/browser/content_settings/cookie_settings_factory.h"
11 #include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
12 #include "chrome/browser/media/webrtc/webrtc_browsertest_common.h"
13 #include "chrome/browser/profiles/profile.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/common/chrome_switches.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "components/content_settings/core/browser/cookie_settings.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browsing_data_remover.h"
23 #include "content/public/common/content_features.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/browsing_data_remover_test_util.h"
27 #include "media/audio/audio_device_description.h"
28 #include "media/audio/audio_manager.h"
29 #include "media/base/media_switches.h"
30 #include "net/test/embedded_test_server/embedded_test_server.h"
31 
32 namespace {
33 
34 const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html";
35 
36 const char kDeviceKindAudioInput[] = "audioinput";
37 const char kDeviceKindVideoInput[] = "videoinput";
38 const char kDeviceKindAudioOutput[] = "audiooutput";
39 
40 }  // namespace
41 
42 // Integration test for WebRTC enumerateDevices. It always uses fake devices.
43 // It needs to be a browser test (and not content browser test) to be able to
44 // test that labels are cleared or not depending on if access to devices has
45 // been granted.
46 class WebRtcGetMediaDevicesBrowserTest
47     : public WebRtcTestBase,
48       public testing::WithParamInterface<bool> {
49  public:
WebRtcGetMediaDevicesBrowserTest()50   WebRtcGetMediaDevicesBrowserTest()
51       : has_audio_output_devices_initialized_(false),
52         has_audio_output_devices_(false) {}
53 
SetUpInProcessBrowserTestFixture()54   void SetUpInProcessBrowserTestFixture() override {
55     DetectErrorsInJavaScript();  // Look for errors in our rather complex js.
56   }
57 
SetUpCommandLine(base::CommandLine * command_line)58   void SetUpCommandLine(base::CommandLine* command_line) override {
59     // Ensure the infobar is enabled, since we expect that in this test.
60     EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));
61   }
62 
63  protected:
64   // This is used for media devices and sources.
65   struct MediaDeviceInfo {
66     std::string device_id;  // Domain specific device ID.
67     std::string kind;
68     std::string label;
69     std::string group_id;
70   };
71 
EnumerateDevices(content::WebContents * tab,std::vector<MediaDeviceInfo> * devices)72   void EnumerateDevices(content::WebContents* tab,
73                         std::vector<MediaDeviceInfo>* devices) {
74     std::string devices_as_json = ExecuteJavascript("enumerateDevices()", tab);
75     EXPECT_FALSE(devices_as_json.empty());
76 
77     int error_code;
78     std::string error_message;
79     std::unique_ptr<base::Value> value =
80         base::JSONReader::ReadAndReturnErrorDeprecated(
81             devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
82             &error_message);
83 
84     ASSERT_TRUE(value.get() != NULL) << error_message;
85     EXPECT_EQ(value->type(), base::Value::Type::LIST);
86 
87     base::ListValue* values;
88     ASSERT_TRUE(value->GetAsList(&values));
89     ASSERT_FALSE(values->empty());
90     bool found_audio_input = false;
91     bool found_video_input = false;
92 
93     for (auto it = values->begin(); it != values->end(); ++it) {
94       const base::DictionaryValue* dict;
95       MediaDeviceInfo device;
96       ASSERT_TRUE(it->GetAsDictionary(&dict));
97       ASSERT_TRUE(dict->GetString("deviceId", &device.device_id));
98       ASSERT_TRUE(dict->GetString("kind", &device.kind));
99       ASSERT_TRUE(dict->GetString("label", &device.label));
100       ASSERT_TRUE(dict->GetString("groupId", &device.group_id));
101 
102       // Should be HMAC SHA256.
103       if (!media::AudioDeviceDescription::IsDefaultDevice(device.device_id) &&
104           !(device.device_id ==
105             media::AudioDeviceDescription::kCommunicationsDeviceId)) {
106         EXPECT_EQ(64ul, device.device_id.length());
107         EXPECT_TRUE(
108             base::ContainsOnlyChars(device.device_id, "0123456789abcdef"));
109       }
110 
111       EXPECT_TRUE(device.kind == kDeviceKindAudioInput ||
112                   device.kind == kDeviceKindVideoInput ||
113                   device.kind == kDeviceKindAudioOutput);
114       if (device.kind == kDeviceKindAudioInput) {
115         found_audio_input = true;
116       } else if (device.kind == kDeviceKindVideoInput) {
117         found_video_input = true;
118       }
119 
120       EXPECT_FALSE(device.group_id.empty());
121       devices->push_back(device);
122     }
123 
124     EXPECT_TRUE(found_audio_input);
125     EXPECT_TRUE(found_video_input);
126   }
127 
CheckEnumerationsAreDifferent(const std::vector<MediaDeviceInfo> & devices,const std::vector<MediaDeviceInfo> & devices2)128   static void CheckEnumerationsAreDifferent(
129       const std::vector<MediaDeviceInfo>& devices,
130       const std::vector<MediaDeviceInfo>& devices2) {
131     for (auto& device : devices) {
132       auto it = std::find_if(devices2.begin(), devices2.end(),
133                              [&device](const MediaDeviceInfo& device_info) {
134                                return device.device_id == device_info.device_id;
135                              });
136       if (device.device_id == media::AudioDeviceDescription::kDefaultDeviceId ||
137           device.device_id ==
138               media::AudioDeviceDescription::kCommunicationsDeviceId) {
139         EXPECT_NE(it, devices2.end());
140       } else {
141         EXPECT_EQ(it, devices2.end());
142       }
143 
144       it = std::find_if(devices2.begin(), devices2.end(),
145                         [&device](const MediaDeviceInfo& device_info) {
146                           return device.group_id == device_info.group_id;
147                         });
148       EXPECT_EQ(it, devices2.end());
149     }
150   }
151 
152   bool has_audio_output_devices_initialized_;
153   bool has_audio_output_devices_;
154 
155  private:
156   base::test::ScopedFeatureList audio_service_features_;
157 };
158 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,EnumerateDevicesWithoutAccess)159 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
160                        EnumerateDevicesWithoutAccess) {
161   ASSERT_TRUE(embedded_test_server()->Start());
162   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
163   ui_test_utils::NavigateToURL(browser(), url);
164   content::WebContents* tab =
165       browser()->tab_strip_model()->GetActiveWebContents();
166 
167   std::vector<MediaDeviceInfo> devices;
168   EnumerateDevices(tab, &devices);
169 
170   // Labels should be empty if access has not been allowed.
171   for (const auto& device_info : devices) {
172     EXPECT_TRUE(device_info.label.empty());
173   }
174 }
175 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,EnumerateDevicesWithAccess)176 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
177                        EnumerateDevicesWithAccess) {
178   ASSERT_TRUE(embedded_test_server()->Start());
179   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
180   ui_test_utils::NavigateToURL(browser(), url);
181   content::WebContents* tab =
182       browser()->tab_strip_model()->GetActiveWebContents();
183 
184   EXPECT_TRUE(GetUserMediaAndAccept(tab));
185 
186   std::vector<MediaDeviceInfo> devices;
187   EnumerateDevices(tab, &devices);
188 
189   // Labels should be non-empty if access has been allowed.
190   for (const auto& device_info : devices) {
191     EXPECT_TRUE(!device_info.label.empty());
192   }
193 }
194 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,DeviceIdSameGroupIdDiffersAfterReload)195 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
196                        DeviceIdSameGroupIdDiffersAfterReload) {
197   ASSERT_TRUE(embedded_test_server()->Start());
198   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
199   ui_test_utils::NavigateToURL(browser(), url);
200   content::WebContents* tab =
201       browser()->tab_strip_model()->GetActiveWebContents();
202   std::vector<MediaDeviceInfo> devices;
203   EnumerateDevices(tab, &devices);
204 
205   ui_test_utils::NavigateToURL(browser(), url);
206   std::vector<MediaDeviceInfo> devices2;
207   EnumerateDevices(tab, &devices2);
208 
209   EXPECT_EQ(devices.size(), devices2.size());
210   for (auto& device : devices) {
211     auto it = std::find_if(devices2.begin(), devices2.end(),
212                            [&device](const MediaDeviceInfo& device_info) {
213                              return device.device_id == device_info.device_id;
214                            });
215     EXPECT_NE(it, devices2.end());
216 
217     it = std::find_if(devices2.begin(), devices2.end(),
218                       [&device](const MediaDeviceInfo& device_info) {
219                         return device.group_id == device_info.group_id;
220                       });
221     EXPECT_EQ(it, devices2.end());
222   }
223 }
224 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,DeviceIdSameGroupIdDiffersAcrossTabs)225 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
226                        DeviceIdSameGroupIdDiffersAcrossTabs) {
227   ASSERT_TRUE(embedded_test_server()->Start());
228   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
229   ui_test_utils::NavigateToURL(browser(), url);
230   content::WebContents* tab1 =
231       browser()->tab_strip_model()->GetActiveWebContents();
232   std::vector<MediaDeviceInfo> devices;
233   EnumerateDevices(tab1, &devices);
234 
235   chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), -1, true);
236   ui_test_utils::NavigateToURL(browser(), url);
237   content::WebContents* tab2 =
238       browser()->tab_strip_model()->GetActiveWebContents();
239   std::vector<MediaDeviceInfo> devices2;
240   EnumerateDevices(tab2, &devices2);
241 
242   EXPECT_NE(tab1, tab2);
243   EXPECT_EQ(devices.size(), devices2.size());
244   for (auto& device : devices) {
245     auto it = std::find_if(devices2.begin(), devices2.end(),
246                            [&device](const MediaDeviceInfo& device_info) {
247                              return device.device_id == device_info.device_id;
248                            });
249     EXPECT_NE(it, devices2.end());
250 
251     it = std::find_if(devices2.begin(), devices2.end(),
252                       [&device](const MediaDeviceInfo& device_info) {
253                         return device.group_id == device_info.group_id;
254                       });
255     EXPECT_EQ(it, devices2.end());
256   }
257 }
258 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,DeviceIdDiffersAfterClearingCookies)259 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
260                        DeviceIdDiffersAfterClearingCookies) {
261   ASSERT_TRUE(embedded_test_server()->Start());
262   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
263   ui_test_utils::NavigateToURL(browser(), url);
264   content::WebContents* tab =
265       browser()->tab_strip_model()->GetActiveWebContents();
266 
267   EXPECT_TRUE(GetUserMediaAndAccept(tab));
268 
269   std::vector<MediaDeviceInfo> devices;
270   EnumerateDevices(tab, &devices);
271 
272   auto* remover =
273       content::BrowserContext::GetBrowsingDataRemover(browser()->profile());
274   content::BrowsingDataRemoverCompletionObserver completion_observer(remover);
275   remover->RemoveAndReply(
276       base::Time(), base::Time::Max(),
277       content::BrowsingDataRemover::DATA_TYPE_COOKIES,
278       content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
279       &completion_observer);
280   completion_observer.BlockUntilCompletion();
281 
282   std::vector<MediaDeviceInfo> devices2;
283   EnumerateDevices(tab, &devices2);
284 
285   EXPECT_EQ(devices.size(), devices2.size());
286   CheckEnumerationsAreDifferent(devices, devices2);
287 }
288 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,DeviceIdDiffersAcrossTabsWithCookiesDisabled)289 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
290                        DeviceIdDiffersAcrossTabsWithCookiesDisabled) {
291   ASSERT_TRUE(embedded_test_server()->Start());
292   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
293   ui_test_utils::NavigateToURL(browser(), url);
294   CookieSettingsFactory::GetForProfile(browser()->profile())
295       ->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
296   content::WebContents* tab1 =
297       browser()->tab_strip_model()->GetActiveWebContents();
298 
299   EXPECT_TRUE(GetUserMediaAndAccept(tab1));
300 
301   std::vector<MediaDeviceInfo> devices;
302   EnumerateDevices(tab1, &devices);
303 
304   chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), -1, true);
305   ui_test_utils::NavigateToURL(browser(), url);
306   content::WebContents* tab2 =
307       browser()->tab_strip_model()->GetActiveWebContents();
308   std::vector<MediaDeviceInfo> devices2;
309   EnumerateDevices(tab2, &devices2);
310 
311   EXPECT_NE(tab1, tab2);
312   EXPECT_EQ(devices.size(), devices2.size());
313   CheckEnumerationsAreDifferent(devices, devices2);
314 }
315 
IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,DeviceIdDiffersSameTabAfterReloadWithCookiesDisabled)316 IN_PROC_BROWSER_TEST_F(WebRtcGetMediaDevicesBrowserTest,
317                        DeviceIdDiffersSameTabAfterReloadWithCookiesDisabled) {
318   ASSERT_TRUE(embedded_test_server()->Start());
319   GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
320   ui_test_utils::NavigateToURL(browser(), url);
321   CookieSettingsFactory::GetForProfile(browser()->profile())
322       ->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
323   content::WebContents* tab =
324       browser()->tab_strip_model()->GetActiveWebContents();
325 
326   EXPECT_TRUE(GetUserMediaAndAccept(tab));
327 
328   std::vector<MediaDeviceInfo> devices;
329   EnumerateDevices(tab, &devices);
330 
331   ui_test_utils::NavigateToURL(browser(), url);
332   tab = browser()->tab_strip_model()->GetActiveWebContents();
333   std::vector<MediaDeviceInfo> devices2;
334   EnumerateDevices(tab, &devices2);
335 
336   EXPECT_EQ(devices.size(), devices2.size());
337   CheckEnumerationsAreDifferent(devices, devices2);
338 }
339