Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(683)

Side by Side Diff: content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc

Issue 2424163004: Factor out authorization from AudioRendererHost. (Closed)
Patch Set: const& Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 // Unit tests for AudioOutputAuthorizationHandler.
6
7 #include "content/browser/renderer_host/media/audio_output_authorization_handler .h"
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/run_loop.h"
12 #include "content/browser/browser_thread_impl.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/test/mock_render_process_host.h"
15 #include "content/public/test/test_browser_context.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "media/audio/audio_device_description.h"
19 #include "media/audio/fake_audio_log_factory.h"
20 #include "media/audio/fake_audio_manager.h"
21 #include "media/base/media_switches.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "url/gurl.h"
25 #include "url/origin.h"
26
27 using ::testing::_;
28
29 namespace content {
30
31 namespace {
32 const int kRenderProcessId = 42;
33 const int kRenderFrameId = 31415;
34 const int kSessionId = 1618;
35 const char kSecurityOriginString[] = "http://localhost";
36 const char kBadSecurityOriginString[] = "about:about";
37 const char kDefaultDeviceId[] = "default";
38 const char kEmptyDeviceId[] = "";
39 const char kInvalidDeviceId[] = "invalid-device-id";
40 const char kSalt[] = "salt";
41
42 struct MockListener {
43 MOCK_METHOD4(MockAuthorizationCallback,
44 void(media::OutputDeviceStatus status,
45 bool should_send_id,
46 const media::AudioParameters& params,
47 const std::string& id));
48
49 AudioOutputAuthorizationHandler::AuthorizationCompletedCallback
50 GetCallback() {
51 return base::Bind(&MockListener::MockAuthorizationCallback,
52 base::Unretained(this));
53 }
54 };
55
56 url::Origin SecurityOrigin() {
57 return url::Origin(GURL(kSecurityOriginString));
58 }
59
60 url::Origin BadSecurityOrigin() {
61 return url::Origin(GURL(kBadSecurityOriginString));
62 }
63 } // namespace
64
65 class AudioOutputAuthorizationHandlerTest : public testing::Test {
66 public:
67 AudioOutputAuthorizationHandlerTest() {
68 // Not threadsafe, thus set before threads are started:
69 base::CommandLine::ForCurrentProcess()->AppendSwitch(
70 switches::kUseFakeDeviceForMediaStream);
71
72 thread_bundle_ = base::MakeUnique<TestBrowserThreadBundle>(
73 TestBrowserThreadBundle::Options::REAL_IO_THREAD);
74 audio_thread_ = base::MakeUnique<base::Thread>("AudioThread");
75
76 // Audio manager creation stolen from content/browser/browser_main_loop.cc.
77 #if defined(OS_WIN)
78 audio_thread_->init_com_with_mta(true);
79 #endif // defined(OS_WIN)
80 CHECK(audio_thread_->Start());
81
82 #if defined(OS_MACOSX)
83 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner =
84 base::ThreadTaskRunnerHandle::Get();
85 #else
86 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner =
87 audio_thread_->task_runner();
88 #endif // defined(OS_MACOSX)
89 audio_manager_.reset(new media::FakeAudioManager(
90 audio_task_runner, audio_thread_->task_runner(), &log_factory_));
91 media_stream_manager_ =
92 base::MakeUnique<MediaStreamManager>(audio_manager_.get());
93 // Make sure everything is done initializing:
94 SyncWithAllThreads();
95 }
96
97 ~AudioOutputAuthorizationHandlerTest() override { SyncWithAllThreads(); }
98
99 protected:
100 MediaStreamManager* GetMediaStreamManager() {
101 return media_stream_manager_.get();
102 }
103
104 void SyncWithAllThreads() {
105 // New tasks might be posted while we are syncing, but in
106 // every iteration at least one task will be run. 20 iterations should be
107 // enough for our code.
108 for (int i = 0; i < 20; ++i) {
109 base::RunLoop().RunUntilIdle();
110 SyncWith(BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
111 SyncWith(audio_thread_->task_runner());
112 }
113 }
114
115 std::string GetRawNondefaultId() {
116 std::string id;
117 BrowserThread::PostTask(
118 BrowserThread::IO, FROM_HERE,
119 base::Bind(
120 &AudioOutputAuthorizationHandlerTest::GetRawNondefaultIdOnIOThread,
121 base::Unretained(this), base::Unretained(&id)));
122 SyncWithAllThreads();
123 return id;
124 }
125
126 private:
127 void SyncWith(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
128 CHECK(task_runner);
129 CHECK(!task_runner->BelongsToCurrentThread());
130 base::WaitableEvent e = {base::WaitableEvent::ResetPolicy::MANUAL,
131 base::WaitableEvent::InitialState::NOT_SIGNALED};
132 task_runner->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
133 base::Unretained(&e)));
134 e.Wait();
135 }
136
137 void GetRawNondefaultIdOnIOThread(std::string* out) {
138 DCHECK_CURRENTLY_ON(BrowserThread::IO);
139 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
140 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
141
142 media_stream_manager_->media_devices_manager()->EnumerateDevices(
143 devices_to_enumerate,
144 base::Bind(
145 [](std::string* out, const MediaDeviceEnumeration& result) {
146 // Index 0 is default, so use 1.
147 CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]
148 .size() > 1)
149 << "Expected to have a nondefault device.";
150 *out = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT][1]
151 .device_id;
152 },
153 base::Unretained(out)));
154 }
155
156 // media_stream_manager must die after threads since it's a
157 // DestructionObserver.
158 std::unique_ptr<MediaStreamManager> media_stream_manager_;
159 std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
160 std::unique_ptr<base::Thread> audio_thread_;
161 media::FakeAudioLogFactory log_factory_;
162 media::ScopedAudioManagerPtr audio_manager_;
163
164 DISALLOW_COPY_AND_ASSIGN(AudioOutputAuthorizationHandlerTest);
165 };
166
167 TEST_F(AudioOutputAuthorizationHandlerTest, AuthorizeDefaultDevice_Ok) {
168 MockListener listener;
169 EXPECT_CALL(listener,
170 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
171 _, kDefaultDeviceId))
172 .Times(1);
173 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
174 base::MakeUnique<AudioOutputAuthorizationHandler>(
175 GetMediaStreamManager(), kRenderProcessId, kSalt);
176
177 BrowserThread::PostTask(
178 BrowserThread::IO, FROM_HERE,
179 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
180 base::Unretained(handler.get()), kRenderFrameId, 0,
181 kDefaultDeviceId, SecurityOrigin(), listener.GetCallback())));
182
183 SyncWithAllThreads();
184 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
185 SyncWithAllThreads();
186 }
187
188 TEST_F(AudioOutputAuthorizationHandlerTest,
189 AuthorizeDefaultDeviceByEmptyId_Ok) {
190 MockListener listener;
191 EXPECT_CALL(listener,
192 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
193 _, kDefaultDeviceId))
194 .Times(1);
195 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
196 base::MakeUnique<AudioOutputAuthorizationHandler>(
197 GetMediaStreamManager(), kRenderProcessId, kSalt);
198
199 BrowserThread::PostTask(
200 BrowserThread::IO, FROM_HERE,
201 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
202 base::Unretained(handler.get()), kRenderFrameId, 0,
203 kEmptyDeviceId, SecurityOrigin(), listener.GetCallback())));
204
205 SyncWithAllThreads();
206 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
207 SyncWithAllThreads();
208 }
209
210 TEST_F(AudioOutputAuthorizationHandlerTest,
211 AuthorizeNondefaultDeviceIdWithoutPermission_NotAuthorized) {
212 std::string raw_nondefault_id = GetRawNondefaultId();
213 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
214 kSalt, SecurityOrigin(), raw_nondefault_id);
215
216 MockListener listener;
217 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
218 base::MakeUnique<AudioOutputAuthorizationHandler>(
219 GetMediaStreamManager(), kRenderProcessId, kSalt);
220 BrowserThread::PostTask(
221 BrowserThread::IO, FROM_HERE,
222 base::Bind(
223 &AudioOutputAuthorizationHandler::OverridePermissionsForTesting,
224 base::Unretained(handler.get()), false));
225 SyncWithAllThreads();
226
227 EXPECT_CALL(listener, MockAuthorizationCallback(
228 media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
229 false, _, std::string()))
230 .Times(1);
231
232 BrowserThread::PostTask(
233 BrowserThread::IO, FROM_HERE,
234 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
235 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
236 SecurityOrigin(), listener.GetCallback())));
237
238 SyncWithAllThreads();
239 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
240 SyncWithAllThreads();
241 }
242
243 TEST_F(AudioOutputAuthorizationHandlerTest,
244 AuthorizeNondefaultDeviceIdWithPermission_Ok) {
245 std::string raw_nondefault_id = GetRawNondefaultId();
246 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
247 kSalt, SecurityOrigin(), raw_nondefault_id);
248 MockListener listener;
249 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
250 base::MakeUnique<AudioOutputAuthorizationHandler>(
251 GetMediaStreamManager(), kRenderProcessId, kSalt);
252 BrowserThread::PostTask(
253 BrowserThread::IO, FROM_HERE,
254 base::Bind(
255 &AudioOutputAuthorizationHandler::OverridePermissionsForTesting,
256 base::Unretained(handler.get()), true));
257
258 EXPECT_CALL(listener,
259 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
260 _, raw_nondefault_id))
261 .Times(1);
262
263 BrowserThread::PostTask(
264 BrowserThread::IO, FROM_HERE,
265 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
266 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
267 SecurityOrigin(), listener.GetCallback())));
268
269 SyncWithAllThreads();
270 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
271 SyncWithAllThreads();
272 }
273
274 TEST_F(AudioOutputAuthorizationHandlerTest,
275 AuthorizeInvalidDeviceId_BadMessage) {
276 std::unique_ptr<TestBrowserContext> context =
277 base::MakeUnique<TestBrowserContext>();
278 std::unique_ptr<MockRenderProcessHost> RPH =
279 base::MakeUnique<MockRenderProcessHost>(context.get());
280 MockListener listener;
281 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
282 base::MakeUnique<AudioOutputAuthorizationHandler>(GetMediaStreamManager(),
283 RPH->GetID(), kSalt);
284 EXPECT_EQ(RPH->bad_msg_count(), 0);
285
286 EXPECT_CALL(listener, MockAuthorizationCallback(_, _, _, _)).Times(0);
287
288 BrowserThread::PostTask(
289 BrowserThread::IO, FROM_HERE,
290 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
291 base::Unretained(handler.get()), kRenderFrameId, 0,
292 kInvalidDeviceId, SecurityOrigin(), listener.GetCallback())));
293
294 SyncWithAllThreads();
295 EXPECT_EQ(RPH->bad_msg_count(), 1);
296 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
297 SyncWithAllThreads();
298 RPH.reset();
299 context.reset();
300 }
301
302 TEST_F(AudioOutputAuthorizationHandlerTest,
303 AuthorizeNondefaultDeviceIdWithBadOrigin_BadMessage) {
304 std::string raw_nondefault_id = GetRawNondefaultId();
305 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
306 kSalt, SecurityOrigin(), raw_nondefault_id);
307 std::unique_ptr<TestBrowserContext> context =
308 base::MakeUnique<TestBrowserContext>();
309 std::unique_ptr<MockRenderProcessHost> RPH =
310 base::MakeUnique<MockRenderProcessHost>(context.get());
311 MockListener listener;
312 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
313 base::MakeUnique<AudioOutputAuthorizationHandler>(GetMediaStreamManager(),
314 RPH->GetID(), kSalt);
315
316 EXPECT_EQ(RPH->bad_msg_count(), 0);
317 EXPECT_CALL(listener, MockAuthorizationCallback(_, _, _, _)).Times(0);
318
319 BrowserThread::PostTask(
320 BrowserThread::IO, FROM_HERE,
321 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
322 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
323 BadSecurityOrigin(), listener.GetCallback())));
324
325 SyncWithAllThreads();
326 EXPECT_EQ(RPH->bad_msg_count(), 1);
327 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
328 SyncWithAllThreads();
329 RPH.reset();
330 context.reset();
331 }
332
333 TEST_F(AudioOutputAuthorizationHandlerTest,
334 AuthorizeWithSessionIdWithoutDevice_GivesDefault) {
335 MockListener listener;
336 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
337 base::MakeUnique<AudioOutputAuthorizationHandler>(
338 GetMediaStreamManager(), kRenderProcessId, kSalt);
339
340 EXPECT_CALL(listener,
341 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
342 _, kDefaultDeviceId))
343 .Times(1);
344
345 BrowserThread::PostTask(
346 BrowserThread::IO, FROM_HERE,
347 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
348 base::Unretained(handler.get()), kRenderFrameId, kSessionId,
349 std::string(), BadSecurityOrigin(), listener.GetCallback())));
350
351 SyncWithAllThreads();
352 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
353 SyncWithAllThreads();
354 }
355
356 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698