1 // Copyright (c) 2012 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.
5 #include "base/basictypes.h"
6 #include "base/compiler_specific.h"
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/proxy/connection.h"
9 #include "ppapi/proxy/device_enumeration_resource_helper.h"
10 #include "ppapi/proxy/plugin_message_filter.h"
11 #include "ppapi/proxy/plugin_resource.h"
12 #include "ppapi/proxy/plugin_resource_tracker.h"
13 #include "ppapi/proxy/plugin_var_tracker.h"
14 #include "ppapi/proxy/ppapi_message_utils.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/proxy/ppapi_proxy_test.h"
17 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
18 #include "ppapi/shared_impl/proxy_lock.h"
19 #include "ppapi/shared_impl/var.h"
20 #include "ppapi/thunk/enter.h"
21 #include "ppapi/thunk/ppb_device_ref_api.h"
22 #include "ppapi/thunk/thunk.h"
29 typedef PluginProxyTest DeviceEnumerationResourceHelperTest
;
31 Connection
GetConnection(PluginProxyTestHarness
* harness
) {
32 CHECK(harness
->GetGlobals()->IsPluginGlobals());
35 static_cast<PluginGlobals
*>(harness
->GetGlobals())->GetBrowserSender(),
36 harness
->plugin_dispatcher());
39 bool CompareDeviceRef(PluginVarTracker
* var_tracker
,
41 const DeviceRefData
& expected
) {
42 thunk::EnterResourceNoLock
<thunk::PPB_DeviceRef_API
> enter(resource
, true);
46 if (expected
.type
!= enter
.object()->GetType())
49 PP_Var name_pp_var
= enter
.object()->GetName();
52 Var
* name_var
= var_tracker
->GetVar(name_pp_var
);
55 StringVar
* name_string_var
= name_var
->AsStringVar();
58 if (expected
.name
!= name_string_var
->value())
63 var_tracker
->ReleaseVar(name_pp_var
);
67 class TestResource
: public PluginResource
{
69 TestResource(Connection connection
, PP_Instance instance
)
70 : PluginResource(connection
, instance
),
71 device_enumeration_(this) {
74 virtual ~TestResource() {}
76 virtual void OnReplyReceived(const ResourceMessageReplyParams
& params
,
77 const IPC::Message
& msg
) OVERRIDE
{
78 if (!device_enumeration_
.HandleReply(params
, msg
))
79 PluginResource::OnReplyReceived(params
, msg
);
82 DeviceEnumerationResourceHelper
& device_enumeration() {
83 return device_enumeration_
;
87 DeviceEnumerationResourceHelper device_enumeration_
;
89 DISALLOW_COPY_AND_ASSIGN(TestResource
);
94 TestCallback() : called_(false), result_(PP_ERROR_FAILED
) {
100 PP_CompletionCallback
MakeCompletionCallback() {
101 return PP_MakeCompletionCallback(&CompletionCallbackBody
, this);
104 bool called() const { return called_
; }
105 int32_t result() const { return result_
; }
108 static void CompletionCallbackBody(void* user_data
, int32_t result
) {
109 TestCallback
* callback
= static_cast<TestCallback
*>(user_data
);
111 CHECK(!callback
->called_
);
112 callback
->called_
= true;
113 callback
->result_
= result
;
119 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
122 class TestArrayOutput
{
124 explicit TestArrayOutput(PluginResourceTracker
* resource_tracker
)
127 resource_tracker_(resource_tracker
) {
132 for (size_t i
= 0; i
< count_
; ++i
)
133 resource_tracker_
->ReleaseResource(data_
[i
]);
138 PP_ArrayOutput
MakeArrayOutput() {
139 PP_ArrayOutput array_output
= { &GetDataBuffer
, this };
143 const PP_Resource
* data() const { return data_
; }
144 uint32_t count() const { return count_
; }
147 static void* GetDataBuffer(void* user_data
,
148 uint32_t element_count
,
149 uint32_t element_size
) {
150 CHECK_EQ(element_size
, sizeof(PP_Resource
));
152 TestArrayOutput
* output
= static_cast<TestArrayOutput
*>(user_data
);
153 CHECK(!output
->data_
);
155 output
->count_
= element_count
;
156 if (element_count
> 0)
157 output
->data_
= new PP_Resource
[element_count
];
159 output
->data_
= NULL
;
161 return output
->data_
;
166 PluginResourceTracker
* resource_tracker_
;
168 DISALLOW_COPY_AND_ASSIGN(TestArrayOutput
);
171 class TestMonitorDeviceChange
{
173 explicit TestMonitorDeviceChange(PluginVarTracker
* var_tracker
)
175 same_as_expected_(false),
176 var_tracker_(var_tracker
) {
179 ~TestMonitorDeviceChange() {}
181 void SetExpectedResult(const std::vector
<DeviceRefData
>& expected
) {
183 same_as_expected_
= false;
184 expected_
= expected
;
187 bool called() const { return called_
; }
189 bool same_as_expected() const { return same_as_expected_
; }
191 static void MonitorDeviceChangeCallback(void* user_data
,
192 uint32_t device_count
,
193 const PP_Resource devices
[]) {
195 TestMonitorDeviceChange
* helper
=
196 static_cast<TestMonitorDeviceChange
*>(user_data
);
197 CHECK(!helper
->called_
);
199 helper
->called_
= true;
200 helper
->same_as_expected_
= false;
201 if (device_count
!= helper
->expected_
.size())
203 for (size_t i
= 0; i
< device_count
; ++i
) {
204 if (!CompareDeviceRef(helper
->var_tracker_
, devices
[i
],
205 helper
->expected_
[i
])) {
209 helper
->same_as_expected_
= true;
214 bool same_as_expected_
;
215 std::vector
<DeviceRefData
> expected_
;
216 PluginVarTracker
* var_tracker_
;
218 DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange
);
223 TEST_F(DeviceEnumerationResourceHelperTest
, EnumerateDevices
) {
226 scoped_refptr
<TestResource
> resource(
227 new TestResource(GetConnection(this), pp_instance()));
228 DeviceEnumerationResourceHelper
& device_enumeration
=
229 resource
->device_enumeration();
231 TestArrayOutput
output(&resource_tracker());
232 TestCallback callback
;
233 scoped_refptr
<TrackedCallback
> tracked_callback(
234 new TrackedCallback(resource
.get(), callback
.MakeCompletionCallback()));
235 int32_t result
= device_enumeration
.EnumerateDevices(output
.MakeArrayOutput(),
237 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
239 // Should have sent an EnumerateDevices message.
240 ResourceMessageCallParams params
;
242 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
243 PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID
, ¶ms
, &msg
));
245 // Synthesize a response.
246 ResourceMessageReplyParams
reply_params(params
.pp_resource(),
248 reply_params
.set_result(PP_OK
);
249 std::vector
<DeviceRefData
> data
;
250 DeviceRefData data_item
;
251 data_item
.type
= PP_DEVICETYPE_DEV_AUDIOCAPTURE
;
252 data_item
.name
= "name_1";
253 data_item
.id
= "id_1";
254 data
.push_back(data_item
);
255 data_item
.type
= PP_DEVICETYPE_DEV_VIDEOCAPTURE
;
256 data_item
.name
= "name_2";
257 data_item
.id
= "id_2";
258 data
.push_back(data_item
);
261 ProxyAutoUnlock unlock
;
262 PluginMessageFilter::DispatchResourceReplyForTest(
264 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(data
));
266 EXPECT_TRUE(callback
.called());
267 EXPECT_EQ(PP_OK
, callback
.result());
268 EXPECT_EQ(2U, output
.count());
269 for (size_t i
= 0; i
< output
.count(); ++i
)
270 EXPECT_TRUE(CompareDeviceRef(&var_tracker(), output
.data()[i
], data
[i
]));
273 TEST_F(DeviceEnumerationResourceHelperTest
, MonitorDeviceChange
) {
276 scoped_refptr
<TestResource
> resource(
277 new TestResource(GetConnection(this), pp_instance()));
278 DeviceEnumerationResourceHelper
& device_enumeration
=
279 resource
->device_enumeration();
281 TestMonitorDeviceChange
helper(&var_tracker());
283 int32_t result
= device_enumeration
.MonitorDeviceChange(
284 &TestMonitorDeviceChange::MonitorDeviceChangeCallback
, &helper
);
285 ASSERT_EQ(PP_OK
, result
);
287 // Should have sent a MonitorDeviceChange message.
288 ResourceMessageCallParams params
;
290 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
291 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID
, ¶ms
, &msg
));
292 sink().ClearMessages();
294 uint32_t callback_id
= 0;
295 ASSERT_TRUE(UnpackMessage
<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange
>(
298 ResourceMessageReplyParams
reply_params(params
.pp_resource(), 0);
299 reply_params
.set_result(PP_OK
);
300 std::vector
<DeviceRefData
> data
;
302 helper
.SetExpectedResult(data
);
305 ProxyAutoUnlock unlock
;
306 // Synthesize a response with no device.
307 PluginMessageFilter::DispatchResourceReplyForTest(
309 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
312 EXPECT_TRUE(helper
.called() && helper
.same_as_expected());
314 DeviceRefData data_item
;
315 data_item
.type
= PP_DEVICETYPE_DEV_AUDIOCAPTURE
;
316 data_item
.name
= "name_1";
317 data_item
.id
= "id_1";
318 data
.push_back(data_item
);
319 data_item
.type
= PP_DEVICETYPE_DEV_VIDEOCAPTURE
;
320 data_item
.name
= "name_2";
321 data_item
.id
= "id_2";
322 data
.push_back(data_item
);
324 helper
.SetExpectedResult(data
);
327 ProxyAutoUnlock unlock
;
328 // Synthesize a response with some devices.
329 PluginMessageFilter::DispatchResourceReplyForTest(
331 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
334 EXPECT_TRUE(helper
.called() && helper
.same_as_expected());
336 TestMonitorDeviceChange
helper2(&var_tracker());
338 result
= device_enumeration
.MonitorDeviceChange(
339 &TestMonitorDeviceChange::MonitorDeviceChangeCallback
, &helper2
);
340 ASSERT_EQ(PP_OK
, result
);
342 // Should have sent another MonitorDeviceChange message.
343 ResourceMessageCallParams params2
;
345 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
346 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID
, ¶ms2
, &msg2
));
347 sink().ClearMessages();
349 uint32_t callback_id2
= 0;
350 ASSERT_TRUE(UnpackMessage
<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange
>(
351 msg2
, &callback_id2
));
353 helper
.SetExpectedResult(data
);
354 helper2
.SetExpectedResult(data
);
356 ProxyAutoUnlock unlock
;
357 // |helper2| should receive the result while |helper| shouldn't.
358 PluginMessageFilter::DispatchResourceReplyForTest(
360 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
361 callback_id2
, data
));
363 EXPECT_TRUE(helper2
.called() && helper2
.same_as_expected());
364 EXPECT_FALSE(helper
.called());
366 helper
.SetExpectedResult(data
);
367 helper2
.SetExpectedResult(data
);
369 ProxyAutoUnlock unlock
;
370 // Even if a message with |callback_id| arrives. |helper| shouldn't receive
372 PluginMessageFilter::DispatchResourceReplyForTest(
374 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
377 EXPECT_FALSE(helper2
.called());
378 EXPECT_FALSE(helper
.called());
380 result
= device_enumeration
.MonitorDeviceChange(NULL
, NULL
);
381 ASSERT_EQ(PP_OK
, result
);
383 // Should have sent a StopMonitoringDeviceChange message.
384 ResourceMessageCallParams params3
;
386 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
387 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID
,
389 sink().ClearMessages();
391 helper2
.SetExpectedResult(data
);
393 ProxyAutoUnlock unlock
;
394 // |helper2| shouldn't receive any result any more.
395 PluginMessageFilter::DispatchResourceReplyForTest(
397 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
398 callback_id2
, data
));
400 EXPECT_FALSE(helper2
.called());