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_resource.h"
11 #include "ppapi/proxy/plugin_resource_tracker.h"
12 #include "ppapi/proxy/plugin_var_tracker.h"
13 #include "ppapi/proxy/ppapi_message_utils.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/proxy/ppapi_proxy_test.h"
16 #include "ppapi/shared_impl/ppb_device_ref_shared.h"
17 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/shared_impl/var.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/ppb_device_ref_api.h"
21 #include "ppapi/thunk/thunk.h"
28 typedef PluginProxyTest DeviceEnumerationResourceHelperTest;
30 Connection GetConnection(PluginProxyTestHarness* harness) {
31 CHECK(harness->GetGlobals()->IsPluginGlobals());
34 static_cast<PluginGlobals*>(harness->GetGlobals())->GetBrowserSender(),
35 harness->plugin_dispatcher());
38 bool CompareDeviceRef(PluginVarTracker* var_tracker,
40 const DeviceRefData& expected) {
41 thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter(resource, true);
45 if (expected.type != enter.object()->GetType())
48 PP_Var name_pp_var = enter.object()->GetName();
51 Var* name_var = var_tracker->GetVar(name_pp_var);
54 StringVar* name_string_var = name_var->AsStringVar();
57 if (expected.name != name_string_var->value())
62 var_tracker->ReleaseVar(name_pp_var);
66 class TestResource : public PluginResource {
68 TestResource(Connection connection, PP_Instance instance)
69 : PluginResource(connection, instance),
70 device_enumeration_(this) {
73 virtual ~TestResource() {}
75 virtual void OnReplyReceived(const ResourceMessageReplyParams& params,
76 const IPC::Message& msg) OVERRIDE {
77 if (!device_enumeration_.HandleReply(params, msg))
78 PluginResource::OnReplyReceived(params, msg);
81 DeviceEnumerationResourceHelper& device_enumeration() {
82 return device_enumeration_;
86 DeviceEnumerationResourceHelper device_enumeration_;
88 DISALLOW_COPY_AND_ASSIGN(TestResource);
93 TestCallback() : called_(false), result_(PP_ERROR_FAILED) {
99 PP_CompletionCallback MakeCompletionCallback() {
100 return PP_MakeCompletionCallback(&CompletionCallbackBody, this);
103 bool called() const { return called_; }
104 int32_t result() const { return result_; }
107 static void CompletionCallbackBody(void* user_data, int32_t result) {
108 TestCallback* callback = static_cast<TestCallback*>(user_data);
110 CHECK(!callback->called_);
111 callback->called_ = true;
112 callback->result_ = result;
118 DISALLOW_COPY_AND_ASSIGN(TestCallback);
121 class TestArrayOutput {
123 explicit TestArrayOutput(PluginResourceTracker* resource_tracker)
126 resource_tracker_(resource_tracker) {
131 for (size_t i = 0; i < count_; ++i)
132 resource_tracker_->ReleaseResource(data_[i]);
137 PP_ArrayOutput MakeArrayOutput() {
138 PP_ArrayOutput array_output = { &GetDataBuffer, this };
142 const PP_Resource* data() const { return data_; }
143 uint32_t count() const { return count_; }
146 static void* GetDataBuffer(void* user_data,
147 uint32_t element_count,
148 uint32_t element_size) {
149 CHECK_EQ(element_size, sizeof(PP_Resource));
151 TestArrayOutput* output = static_cast<TestArrayOutput*>(user_data);
152 CHECK(!output->data_);
154 output->count_ = element_count;
155 if (element_count > 0)
156 output->data_ = new PP_Resource[element_count];
158 output->data_ = NULL;
160 return output->data_;
165 PluginResourceTracker* resource_tracker_;
167 DISALLOW_COPY_AND_ASSIGN(TestArrayOutput);
170 class TestMonitorDeviceChange {
172 explicit TestMonitorDeviceChange(PluginVarTracker* var_tracker)
174 same_as_expected_(false),
175 var_tracker_(var_tracker) {
178 ~TestMonitorDeviceChange() {}
180 void SetExpectedResult(const std::vector<DeviceRefData>& expected) {
182 same_as_expected_ = false;
183 expected_ = expected;
186 bool called() const { return called_; }
188 bool same_as_expected() const { return same_as_expected_; }
190 static void MonitorDeviceChangeCallback(void* user_data,
191 uint32_t device_count,
192 const PP_Resource devices[]) {
194 TestMonitorDeviceChange* helper =
195 static_cast<TestMonitorDeviceChange*>(user_data);
196 CHECK(!helper->called_);
198 helper->called_ = true;
199 helper->same_as_expected_ = false;
200 if (device_count != helper->expected_.size())
202 for (size_t i = 0; i < device_count; ++i) {
203 if (!CompareDeviceRef(helper->var_tracker_, devices[i],
204 helper->expected_[i])) {
208 helper->same_as_expected_ = true;
213 bool same_as_expected_;
214 std::vector<DeviceRefData> expected_;
215 PluginVarTracker* var_tracker_;
217 DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange);
222 TEST_F(DeviceEnumerationResourceHelperTest, EnumerateDevices) {
225 scoped_refptr<TestResource> resource(
226 new TestResource(GetConnection(this), pp_instance()));
227 DeviceEnumerationResourceHelper& device_enumeration =
228 resource->device_enumeration();
230 TestArrayOutput output(&resource_tracker());
231 TestCallback callback;
232 scoped_refptr<TrackedCallback> tracked_callback(
233 new TrackedCallback(resource.get(), callback.MakeCompletionCallback()));
234 int32_t result = device_enumeration.EnumerateDevices(output.MakeArrayOutput(),
236 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
238 // Should have sent an EnumerateDevices message.
239 ResourceMessageCallParams params;
241 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
242 PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, ¶ms, &msg));
244 // Synthesize a response.
245 ResourceMessageReplyParams reply_params(params.pp_resource(),
247 reply_params.set_result(PP_OK);
248 std::vector<DeviceRefData> data;
249 DeviceRefData data_item;
250 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE;
251 data_item.name = "name_1";
252 data_item.id = "id_1";
253 data.push_back(data_item);
254 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE;
255 data_item.name = "name_2";
256 data_item.id = "id_2";
257 data.push_back(data_item);
260 ProxyAutoUnlock unlock;
261 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
262 PpapiPluginMsg_ResourceReply(
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 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
308 PpapiPluginMsg_ResourceReply(
310 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
311 callback_id, data))));
313 EXPECT_TRUE(helper.called() && helper.same_as_expected());
315 DeviceRefData data_item;
316 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE;
317 data_item.name = "name_1";
318 data_item.id = "id_1";
319 data.push_back(data_item);
320 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE;
321 data_item.name = "name_2";
322 data_item.id = "id_2";
323 data.push_back(data_item);
325 helper.SetExpectedResult(data);
328 ProxyAutoUnlock unlock;
329 // Synthesize a response with some devices.
330 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
331 PpapiPluginMsg_ResourceReply(
333 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
334 callback_id, data))));
336 EXPECT_TRUE(helper.called() && helper.same_as_expected());
338 TestMonitorDeviceChange helper2(&var_tracker());
340 result = device_enumeration.MonitorDeviceChange(
341 &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper2);
342 ASSERT_EQ(PP_OK, result);
344 // Should have sent another MonitorDeviceChange message.
345 ResourceMessageCallParams params2;
347 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
348 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms2, &msg2));
349 sink().ClearMessages();
351 uint32_t callback_id2 = 0;
352 ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>(
353 msg2, &callback_id2));
355 helper.SetExpectedResult(data);
356 helper2.SetExpectedResult(data);
358 ProxyAutoUnlock unlock;
359 // |helper2| should receive the result while |helper| shouldn't.
360 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
361 PpapiPluginMsg_ResourceReply(
363 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
364 callback_id2, data))));
366 EXPECT_TRUE(helper2.called() && helper2.same_as_expected());
367 EXPECT_FALSE(helper.called());
369 helper.SetExpectedResult(data);
370 helper2.SetExpectedResult(data);
372 ProxyAutoUnlock unlock;
373 // Even if a message with |callback_id| arrives. |helper| shouldn't receive
375 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
376 PpapiPluginMsg_ResourceReply(
378 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
379 callback_id, data))));
381 EXPECT_FALSE(helper2.called());
382 EXPECT_FALSE(helper.called());
384 result = device_enumeration.MonitorDeviceChange(NULL, NULL);
385 ASSERT_EQ(PP_OK, result);
387 // Should have sent a StopMonitoringDeviceChange message.
388 ResourceMessageCallParams params3;
390 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
391 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID,
393 sink().ClearMessages();
395 helper2.SetExpectedResult(data);
397 ProxyAutoUnlock unlock;
398 // |helper2| shouldn't receive any result any more.
399 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
400 PpapiPluginMsg_ResourceReply(
402 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
403 callback_id2, data))));
405 EXPECT_FALSE(helper2.called());