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

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: . 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 CHECK(audio_manager_);
106 // New tasks might be posted while we are syncing, but in
107 // every iteration at least one task will be run. 20 iterations should be
108 // enough for our code.
109 for (int i = 0; i < 20; ++i) {
110 base::RunLoop().RunUntilIdle();
111 SyncWith(BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
112 SyncWith(audio_thread_->task_runner());
113 }
114 }
115
116 std::string GetRawNondefaultId() {
117 std::string id;
118 BrowserThread::PostTask(
119 BrowserThread::IO, FROM_HERE,
120 base::Bind(
121 &AudioOutputAuthorizationHandlerTest::GetRawNondefaultIdOnIOThread,
122 base::Unretained(this), base::Unretained(&id)));
123 SyncWithAllThreads();
124 return id;
125 }
126
127 private:
128 void SyncWith(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
129 CHECK(task_runner);
130 CHECK(!task_runner->BelongsToCurrentThread());
131 base::WaitableEvent e = {base::WaitableEvent::ResetPolicy::MANUAL,
132 base::WaitableEvent::InitialState::NOT_SIGNALED};
133 task_runner->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
134 base::Unretained(&e)));
135 e.Wait();
136 }
137
138 void GetRawNondefaultIdOnIOThread(std::string* out) {
139 DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
141 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
142
143 media_stream_manager_->media_devices_manager()->EnumerateDevices(
144 devices_to_enumerate,
145 base::Bind(
146 [](std::string* out, const MediaDeviceEnumeration& result) {
147 // Index 0 is default, so use 1.
148 CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]
149 .size() > 1)
150 << "Expected to have a nondefault device.";
151 *out = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT][1]
152 .device_id;
153 },
154 base::Unretained(out)));
155 }
156
157 // media_stream_manager must die after threads since it's a
158 // DestructionObserver.
159 std::unique_ptr<MediaStreamManager> media_stream_manager_;
160 std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
161 std::unique_ptr<base::Thread> audio_thread_;
162 media::FakeAudioLogFactory log_factory_;
163 media::ScopedAudioManagerPtr audio_manager_;
164
165 DISALLOW_COPY_AND_ASSIGN(AudioOutputAuthorizationHandlerTest);
166 };
167
168 TEST_F(AudioOutputAuthorizationHandlerTest, AuthorizeDefaultDevice_Ok) {
169 MockListener listener;
170 EXPECT_CALL(listener,
171 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
172 _, kDefaultDeviceId))
173 .Times(1);
174 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
175 base::MakeUnique<AudioOutputAuthorizationHandler>(
176 GetMediaStreamManager(), kRenderProcessId, kSalt);
177
178 BrowserThread::PostTask(
179 BrowserThread::IO, FROM_HERE,
180 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
181 base::Unretained(handler.get()), kRenderFrameId, 0,
182 kDefaultDeviceId, SecurityOrigin(), listener.GetCallback())));
183
184 SyncWithAllThreads();
185 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
186 SyncWithAllThreads();
187 }
188
189 TEST_F(AudioOutputAuthorizationHandlerTest,
190 AuthorizeDefaultDeviceByEmptyId_Ok) {
191 MockListener listener;
192 EXPECT_CALL(listener,
193 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
194 _, kDefaultDeviceId))
195 .Times(1);
196 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
197 base::MakeUnique<AudioOutputAuthorizationHandler>(
198 GetMediaStreamManager(), kRenderProcessId, kSalt);
199
200 BrowserThread::PostTask(
201 BrowserThread::IO, FROM_HERE,
202 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
203 base::Unretained(handler.get()), kRenderFrameId, 0,
204 kEmptyDeviceId, SecurityOrigin(), listener.GetCallback())));
205
206 SyncWithAllThreads();
207 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
208 SyncWithAllThreads();
209 }
210
211 TEST_F(AudioOutputAuthorizationHandlerTest,
212 AuthorizeNondefaultDeviceIdWithoutPermission_NotAuthorized) {
213 std::string raw_nondefault_id = GetRawNondefaultId();
214 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
215 kSalt, SecurityOrigin(), raw_nondefault_id);
216
217 MockListener listener;
218 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
219 base::MakeUnique<AudioOutputAuthorizationHandler>(
220 GetMediaStreamManager(), kRenderProcessId, kSalt);
221 BrowserThread::PostTask(
222 BrowserThread::IO, FROM_HERE,
223 base::Bind(
224 &AudioOutputAuthorizationHandler::OverridePermissionsForTesting,
225 base::Unretained(handler.get()), false));
226 SyncWithAllThreads();
227
228 EXPECT_CALL(listener, MockAuthorizationCallback(
229 media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
230 false, _, std::string()))
231 .Times(1);
232
233 BrowserThread::PostTask(
234 BrowserThread::IO, FROM_HERE,
235 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
236 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
237 SecurityOrigin(), listener.GetCallback())));
238
239 SyncWithAllThreads();
240 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
241 SyncWithAllThreads();
242 }
243
244 TEST_F(AudioOutputAuthorizationHandlerTest,
245 AuthorizeNondefaultDeviceIdWithPermission_Ok) {
246 std::string raw_nondefault_id = GetRawNondefaultId();
247 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
248 kSalt, SecurityOrigin(), raw_nondefault_id);
249 MockListener listener;
250 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
251 base::MakeUnique<AudioOutputAuthorizationHandler>(
252 GetMediaStreamManager(), kRenderProcessId, kSalt);
253 BrowserThread::PostTask(
254 BrowserThread::IO, FROM_HERE,
255 base::Bind(
256 &AudioOutputAuthorizationHandler::OverridePermissionsForTesting,
257 base::Unretained(handler.get()), true));
258
259 EXPECT_CALL(listener,
260 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
261 _, raw_nondefault_id))
262 .Times(1);
263
264 BrowserThread::PostTask(
265 BrowserThread::IO, FROM_HERE,
266 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
267 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
268 SecurityOrigin(), listener.GetCallback())));
269
270 SyncWithAllThreads();
271 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
272 SyncWithAllThreads();
273 }
274
275 TEST_F(AudioOutputAuthorizationHandlerTest,
276 AuthorizeInvalidDeviceId_BadMessage) {
277 std::unique_ptr<TestBrowserContext> context =
278 base::MakeUnique<TestBrowserContext>();
279 std::unique_ptr<MockRenderProcessHost> RPH =
280 base::MakeUnique<MockRenderProcessHost>(context.get());
281 MockListener listener;
282 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
283 base::MakeUnique<AudioOutputAuthorizationHandler>(GetMediaStreamManager(),
284 RPH->GetID(), kSalt);
285 EXPECT_EQ(RPH->bad_msg_count(), 0);
286
287 EXPECT_CALL(listener, MockAuthorizationCallback(_, _, _, _)).Times(0);
288
289 BrowserThread::PostTask(
290 BrowserThread::IO, FROM_HERE,
291 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
292 base::Unretained(handler.get()), kRenderFrameId, 0,
293 kInvalidDeviceId, SecurityOrigin(), listener.GetCallback())));
294
295 SyncWithAllThreads();
296 EXPECT_EQ(RPH->bad_msg_count(), 1);
297 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
298 SyncWithAllThreads();
299 RPH.reset();
300 context.reset();
301 }
302
303 TEST_F(AudioOutputAuthorizationHandlerTest,
304 AuthorizeNondefaultDeviceIdWithBadOrigin_BadMessage) {
305 std::string raw_nondefault_id = GetRawNondefaultId();
306 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID(
307 kSalt, SecurityOrigin(), raw_nondefault_id);
308 std::unique_ptr<TestBrowserContext> context =
309 base::MakeUnique<TestBrowserContext>();
310 std::unique_ptr<MockRenderProcessHost> RPH =
311 base::MakeUnique<MockRenderProcessHost>(context.get());
312 MockListener listener;
313 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
314 base::MakeUnique<AudioOutputAuthorizationHandler>(GetMediaStreamManager(),
315 RPH->GetID(), kSalt);
316
317 EXPECT_EQ(RPH->bad_msg_count(), 0);
318 EXPECT_CALL(listener, MockAuthorizationCallback(_, _, _, _)).Times(0);
319
320 BrowserThread::PostTask(
321 BrowserThread::IO, FROM_HERE,
322 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
323 base::Unretained(handler.get()), kRenderFrameId, 0, hashed_id,
324 BadSecurityOrigin(), listener.GetCallback())));
325
326 SyncWithAllThreads();
327 EXPECT_EQ(RPH->bad_msg_count(), 1);
328 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
329 SyncWithAllThreads();
330 RPH.reset();
331 context.reset();
332 }
333
334 TEST_F(AudioOutputAuthorizationHandlerTest,
335 AuthorizeWithSessionIdWithoutDevice_GivesDefault) {
336 MockListener listener;
337 std::unique_ptr<AudioOutputAuthorizationHandler> handler =
338 base::MakeUnique<AudioOutputAuthorizationHandler>(
339 GetMediaStreamManager(), kRenderProcessId, kSalt);
340
341 EXPECT_CALL(listener,
342 MockAuthorizationCallback(media::OUTPUT_DEVICE_STATUS_OK, false,
343 _, kDefaultDeviceId))
344 .Times(1);
345
346 BrowserThread::PostTask(
347 BrowserThread::IO, FROM_HERE,
348 (base::Bind(&AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
349 base::Unretained(handler.get()), kRenderFrameId, kSessionId,
350 std::string(), BadSecurityOrigin(), listener.GetCallback())));
351
352 SyncWithAllThreads();
353 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, handler.release());
354 SyncWithAllThreads();
355 }
356
357 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698