Roll src/third_party/WebKit ef7cfd7:80927b2 (svn 194570:194575)
[chromium-blink-merge.git] / ppapi / proxy / device_enumeration_resource_helper_unittest.cc
blob32bc68a0dde8d4332cdbb28a2cfbe6987a0ec10f
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"
24 namespace ppapi {
25 namespace proxy {
27 namespace {
29 typedef PluginProxyTest DeviceEnumerationResourceHelperTest;
31 Connection GetConnection(PluginProxyTestHarness* harness) {
32 CHECK(harness->GetGlobals()->IsPluginGlobals());
34 return Connection(
35 static_cast<PluginGlobals*>(harness->GetGlobals())->GetBrowserSender(),
36 harness->plugin_dispatcher());
39 bool CompareDeviceRef(PluginVarTracker* var_tracker,
40 PP_Resource resource,
41 const DeviceRefData& expected) {
42 thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter(resource, true);
43 if (enter.failed())
44 return false;
46 if (expected.type != enter.object()->GetType())
47 return false;
49 PP_Var name_pp_var = enter.object()->GetName();
50 bool result = false;
51 do {
52 Var* name_var = var_tracker->GetVar(name_pp_var);
53 if (!name_var)
54 break;
55 StringVar* name_string_var = name_var->AsStringVar();
56 if (!name_string_var)
57 break;
58 if (expected.name != name_string_var->value())
59 break;
61 result = true;
62 } while (false);
63 var_tracker->ReleaseVar(name_pp_var);
64 return result;
67 class TestResource : public PluginResource {
68 public:
69 TestResource(Connection connection, PP_Instance instance)
70 : PluginResource(connection, instance),
71 device_enumeration_(this) {
74 ~TestResource() override {}
76 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_;
86 private:
87 DeviceEnumerationResourceHelper device_enumeration_;
89 DISALLOW_COPY_AND_ASSIGN(TestResource);
92 class TestCallback {
93 public:
94 TestCallback() : called_(false), result_(PP_ERROR_FAILED) {
96 ~TestCallback() {
97 CHECK(called_);
100 PP_CompletionCallback MakeCompletionCallback() {
101 return PP_MakeCompletionCallback(&CompletionCallbackBody, this);
104 bool called() const { return called_; }
105 int32_t result() const { return result_; }
107 private:
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;
116 bool called_;
117 int32_t result_;
119 DISALLOW_COPY_AND_ASSIGN(TestCallback);
122 class TestArrayOutput {
123 public:
124 explicit TestArrayOutput(PluginResourceTracker* resource_tracker)
125 : data_(NULL),
126 count_(0),
127 resource_tracker_(resource_tracker) {
130 ~TestArrayOutput() {
131 if (count_ > 0) {
132 for (size_t i = 0; i < count_; ++i)
133 resource_tracker_->ReleaseResource(data_[i]);
134 delete [] data_;
138 PP_ArrayOutput MakeArrayOutput() {
139 PP_ArrayOutput array_output = { &GetDataBuffer, this };
140 return array_output;
143 const PP_Resource* data() const { return data_; }
144 uint32_t count() const { return count_; }
146 private:
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];
158 else
159 output->data_ = NULL;
161 return output->data_;
164 PP_Resource* data_;
165 uint32_t count_;
166 PluginResourceTracker* resource_tracker_;
168 DISALLOW_COPY_AND_ASSIGN(TestArrayOutput);
171 class TestMonitorDeviceChange {
172 public:
173 explicit TestMonitorDeviceChange(PluginVarTracker* var_tracker)
174 : called_(false),
175 same_as_expected_(false),
176 var_tracker_(var_tracker) {
179 ~TestMonitorDeviceChange() {}
181 void SetExpectedResult(const std::vector<DeviceRefData>& expected) {
182 called_ = false;
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[]) {
194 ProxyAutoLock lock;
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())
202 return;
203 for (size_t i = 0; i < device_count; ++i) {
204 if (!CompareDeviceRef(helper->var_tracker_, devices[i],
205 helper->expected_[i])) {
206 return;
209 helper->same_as_expected_ = true;
212 private:
213 bool called_;
214 bool same_as_expected_;
215 std::vector<DeviceRefData> expected_;
216 PluginVarTracker* var_tracker_;
218 DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange);
221 } // namespace
223 TEST_F(DeviceEnumerationResourceHelperTest, EnumerateDevices) {
224 ProxyAutoLock lock;
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(),
236 tracked_callback);
237 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
239 // Should have sent an EnumerateDevices message.
240 ResourceMessageCallParams params;
241 IPC::Message msg;
242 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
243 PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, &params, &msg));
245 // Synthesize a response.
246 ResourceMessageReplyParams reply_params(params.pp_resource(),
247 params.sequence());
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(
263 reply_params,
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) {
274 ProxyAutoLock lock;
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;
289 IPC::Message msg;
290 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
291 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, &params, &msg));
292 sink().ClearMessages();
294 uint32_t callback_id = 0;
295 ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>(
296 msg, &callback_id));
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(
308 reply_params,
309 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
310 callback_id, data));
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(
330 reply_params,
331 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
332 callback_id, data));
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;
344 IPC::Message msg2;
345 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
346 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, &params2, &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(
359 reply_params,
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
371 // the result.
372 PluginMessageFilter::DispatchResourceReplyForTest(
373 reply_params,
374 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
375 callback_id, data));
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;
385 IPC::Message msg3;
386 ASSERT_TRUE(sink().GetFirstResourceCallMatching(
387 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID,
388 &params3, &msg3));
389 sink().ClearMessages();
391 helper2.SetExpectedResult(data);
393 ProxyAutoUnlock unlock;
394 // |helper2| shouldn't receive any result any more.
395 PluginMessageFilter::DispatchResourceReplyForTest(
396 reply_params,
397 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange(
398 callback_id2, data));
400 EXPECT_FALSE(helper2.called());
403 } // namespace proxy
404 } // namespace ppapi