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