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 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "content/browser/frame_host/render_frame_host_delegate.h" 9 #include "content/public/common/renderer_preferences.h" 10 #include "content/public/test/test_browser_thread.h" 11 #include "testing/gmock/include/gmock/gmock.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "ui/gfx/rect.h" 14 15 using testing::_; 16 using testing::Return; 17 using testing::SaveArg; 18 19 namespace content { 20 namespace { 21 22 class MockRenderFrameHostDelegate : public RenderFrameHostDelegate { 23 public: 24 MOCK_METHOD2(RequestMediaAccessPermission, 25 void(const MediaStreamRequest& request, 26 const MediaResponseCallback& callback)); 27 MOCK_METHOD2(CheckMediaAccessPermission, 28 bool(const GURL& security_origin, 29 MediaStreamType type)); 30 }; 31 32 class MockResponseCallback { 33 public: 34 MOCK_METHOD2(OnAccessRequestResponse, 35 void(const MediaStreamDevices& devices, 36 content::MediaStreamRequestResult result)); 37 MOCK_METHOD1(OnCheckResponse, void(bool have_access)); 38 }; 39 40 class MockMediaStreamUI : public MediaStreamUI { 41 public: 42 MOCK_METHOD1(OnStarted, gfx::NativeViewId(const base::Closure& stop)); 43 }; 44 45 class MockStopStreamHandler { 46 public: 47 MOCK_METHOD0(OnStop, void()); 48 MOCK_METHOD1(OnWindowId, void(gfx::NativeViewId window_id)); 49 }; 50 51 52 } // namespace 53 54 class MediaStreamUIProxyTest : public testing::Test { 55 public: 56 MediaStreamUIProxyTest() 57 : ui_thread_(BrowserThread::UI, &message_loop_), 58 io_thread_(BrowserThread::IO, &message_loop_) { 59 proxy_ = MediaStreamUIProxy::CreateForTests(&delegate_); 60 } 61 62 virtual ~MediaStreamUIProxyTest() { 63 proxy_.reset(); 64 message_loop_.RunUntilIdle(); 65 } 66 67 protected: 68 base::MessageLoop message_loop_; 69 TestBrowserThread ui_thread_; 70 TestBrowserThread io_thread_; 71 72 MockRenderFrameHostDelegate delegate_; 73 MockResponseCallback response_callback_; 74 scoped_ptr<MediaStreamUIProxy> proxy_; 75 }; 76 77 MATCHER_P(SameRequest, expected, "") { 78 return 79 expected.render_process_id == arg.render_process_id && 80 expected.render_frame_id == arg.render_frame_id && 81 expected.tab_capture_device_id == arg.tab_capture_device_id && 82 expected.security_origin == arg.security_origin && 83 expected.request_type == arg.request_type && 84 expected.requested_audio_device_id == arg.requested_audio_device_id && 85 expected.requested_video_device_id == arg.requested_video_device_id && 86 expected.audio_type == arg.audio_type && 87 expected.video_type == arg.video_type; 88 } 89 90 TEST_F(MediaStreamUIProxyTest, Deny) { 91 MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false, 92 MEDIA_GENERATE_STREAM, std::string(), 93 std::string(), 94 MEDIA_DEVICE_AUDIO_CAPTURE, 95 MEDIA_DEVICE_VIDEO_CAPTURE); 96 proxy_->RequestAccess( 97 request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, 98 base::Unretained(&response_callback_))); 99 MediaResponseCallback callback; 100 EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) 101 .WillOnce(SaveArg<1>(&callback)); 102 message_loop_.RunUntilIdle(); 103 ASSERT_FALSE(callback.is_null()); 104 105 MediaStreamDevices devices; 106 callback.Run(devices, MEDIA_DEVICE_OK, scoped_ptr<MediaStreamUI>()); 107 108 MediaStreamDevices response; 109 EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _)) 110 .WillOnce(SaveArg<0>(&response)); 111 message_loop_.RunUntilIdle(); 112 113 EXPECT_TRUE(response.empty()); 114 } 115 116 TEST_F(MediaStreamUIProxyTest, AcceptAndStart) { 117 MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false, 118 MEDIA_GENERATE_STREAM, std::string(), 119 std::string(), 120 MEDIA_DEVICE_AUDIO_CAPTURE, 121 MEDIA_DEVICE_VIDEO_CAPTURE); 122 proxy_->RequestAccess( 123 request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, 124 base::Unretained(&response_callback_))); 125 MediaResponseCallback callback; 126 EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) 127 .WillOnce(SaveArg<1>(&callback)); 128 message_loop_.RunUntilIdle(); 129 ASSERT_FALSE(callback.is_null()); 130 131 MediaStreamDevices devices; 132 devices.push_back( 133 MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic")); 134 scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI()); 135 EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(0)); 136 callback.Run(devices, MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>()); 137 138 MediaStreamDevices response; 139 EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _)) 140 .WillOnce(SaveArg<0>(&response)); 141 message_loop_.RunUntilIdle(); 142 143 EXPECT_FALSE(response.empty()); 144 145 proxy_->OnStarted(base::Closure(), MediaStreamUIProxy::WindowIdCallback()); 146 message_loop_.RunUntilIdle(); 147 } 148 149 // Verify that the proxy can be deleted before the request is processed. 150 TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) { 151 MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false, 152 MEDIA_GENERATE_STREAM, std::string(), 153 std::string(), 154 MEDIA_DEVICE_AUDIO_CAPTURE, 155 MEDIA_DEVICE_VIDEO_CAPTURE); 156 proxy_->RequestAccess( 157 request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, 158 base::Unretained(&response_callback_))); 159 MediaResponseCallback callback; 160 EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) 161 .WillOnce(SaveArg<1>(&callback)); 162 message_loop_.RunUntilIdle(); 163 ASSERT_FALSE(callback.is_null()); 164 165 proxy_.reset(); 166 167 MediaStreamDevices devices; 168 scoped_ptr<MediaStreamUI> ui; 169 callback.Run(devices, MEDIA_DEVICE_OK, ui.Pass()); 170 } 171 172 TEST_F(MediaStreamUIProxyTest, StopFromUI) { 173 MediaStreamRequest request(0, 0, 0, GURL("http://origin/"), false, 174 MEDIA_GENERATE_STREAM, std::string(), 175 std::string(), 176 MEDIA_DEVICE_AUDIO_CAPTURE, 177 MEDIA_DEVICE_VIDEO_CAPTURE); 178 proxy_->RequestAccess( 179 request, base::Bind(&MockResponseCallback::OnAccessRequestResponse, 180 base::Unretained(&response_callback_))); 181 MediaResponseCallback callback; 182 EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) 183 .WillOnce(SaveArg<1>(&callback)); 184 message_loop_.RunUntilIdle(); 185 ASSERT_FALSE(callback.is_null()); 186 187 base::Closure stop_callback; 188 189 MediaStreamDevices devices; 190 devices.push_back( 191 MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic")); 192 scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI()); 193 EXPECT_CALL(*ui, OnStarted(_)) 194 .WillOnce(testing::DoAll(SaveArg<0>(&stop_callback), Return(0))); 195 callback.Run(devices, MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>()); 196 197 MediaStreamDevices response; 198 EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _)) 199 .WillOnce(SaveArg<0>(&response)); 200 message_loop_.RunUntilIdle(); 201 202 EXPECT_FALSE(response.empty()); 203 204 MockStopStreamHandler stop_handler; 205 proxy_->OnStarted(base::Bind(&MockStopStreamHandler::OnStop, 206 base::Unretained(&stop_handler)), 207 MediaStreamUIProxy::WindowIdCallback()); 208 message_loop_.RunUntilIdle(); 209 210 ASSERT_FALSE(stop_callback.is_null()); 211 EXPECT_CALL(stop_handler, OnStop()); 212 stop_callback.Run(); 213 message_loop_.RunUntilIdle(); 214 } 215 216 TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) { 217 MediaStreamRequest request(0, 218 0, 219 0, 220 GURL("http://origin/"), 221 false, 222 MEDIA_GENERATE_STREAM, 223 std::string(), 224 std::string(), 225 MEDIA_NO_SERVICE, 226 MEDIA_DESKTOP_VIDEO_CAPTURE); 227 proxy_->RequestAccess( 228 request, 229 base::Bind(&MockResponseCallback::OnAccessRequestResponse, 230 base::Unretained(&response_callback_))); 231 MediaResponseCallback callback; 232 EXPECT_CALL(delegate_, RequestMediaAccessPermission(SameRequest(request), _)) 233 .WillOnce(SaveArg<1>(&callback)); 234 message_loop_.RunUntilIdle(); 235 236 const int kWindowId = 1; 237 scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI()); 238 EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(kWindowId)); 239 240 callback.Run( 241 MediaStreamDevices(), MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>()); 242 EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _)); 243 244 MockStopStreamHandler handler; 245 EXPECT_CALL(handler, OnWindowId(kWindowId)); 246 247 proxy_->OnStarted( 248 base::Bind(&MockStopStreamHandler::OnStop, base::Unretained(&handler)), 249 base::Bind(&MockStopStreamHandler::OnWindowId, 250 base::Unretained(&handler))); 251 message_loop_.RunUntilIdle(); 252 } 253 254 TEST_F(MediaStreamUIProxyTest, CheckAccess) { 255 proxy_->CheckAccess(GURL("http://origin/"), 256 MEDIA_DEVICE_AUDIO_CAPTURE, 257 0, 258 0, 259 base::Bind(&MockResponseCallback::OnCheckResponse, 260 base::Unretained(&response_callback_))); 261 EXPECT_CALL(delegate_, CheckMediaAccessPermission(_, _)); 262 EXPECT_CALL(response_callback_, OnCheckResponse(_)); 263 message_loop_.RunUntilIdle(); 264 } 265 266 } // content 267