OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 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/var.h" |
| 18 #include "ppapi/thunk/enter.h" |
| 19 #include "ppapi/thunk/ppb_device_ref_api.h" |
| 20 #include "ppapi/thunk/thunk.h" |
| 21 |
| 22 namespace ppapi { |
| 23 namespace proxy { |
| 24 |
| 25 namespace { |
| 26 |
| 27 typedef PluginProxyTest DeviceEnumerationResourceHelperTest; |
| 28 |
| 29 Connection GetConnection(PluginProxyTestHarness* harness) { |
| 30 CHECK(harness->GetGlobals()->IsPluginGlobals()); |
| 31 |
| 32 return Connection( |
| 33 static_cast<PluginGlobals*>(harness->GetGlobals())-> |
| 34 plugin_proxy_delegate()->GetBrowserSender(), |
| 35 harness->plugin_dispatcher()); |
| 36 } |
| 37 |
| 38 bool CompareDeviceRef(PluginVarTracker* var_tracker, |
| 39 PP_Resource resource, |
| 40 const DeviceRefData& expected) { |
| 41 thunk::EnterResource<thunk::PPB_DeviceRef_API> enter(resource, true); |
| 42 if (enter.failed()) |
| 43 return false; |
| 44 |
| 45 if (expected.type != enter.object()->GetType()) |
| 46 return false; |
| 47 |
| 48 PP_Var name_pp_var = enter.object()->GetName(); |
| 49 bool result = false; |
| 50 do { |
| 51 Var* name_var = var_tracker->GetVar(name_pp_var); |
| 52 if (!name_var) |
| 53 break; |
| 54 StringVar* name_string_var = name_var->AsStringVar(); |
| 55 if (!name_string_var) |
| 56 break; |
| 57 if (expected.name != name_string_var->value()) |
| 58 break; |
| 59 |
| 60 result = true; |
| 61 } while (false); |
| 62 var_tracker->ReleaseVar(name_pp_var); |
| 63 return result; |
| 64 } |
| 65 |
| 66 class TestResource : public PluginResource { |
| 67 public: |
| 68 TestResource(Connection connection, PP_Instance instance) |
| 69 : PluginResource(connection, instance), |
| 70 ALLOW_THIS_IN_INITIALIZER_LIST(device_enumeration_(this)) { |
| 71 } |
| 72 |
| 73 virtual ~TestResource() {} |
| 74 |
| 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); |
| 79 } |
| 80 |
| 81 DeviceEnumerationResourceHelper& device_enumeration() { |
| 82 return device_enumeration_; |
| 83 } |
| 84 |
| 85 private: |
| 86 DeviceEnumerationResourceHelper device_enumeration_; |
| 87 |
| 88 DISALLOW_COPY_AND_ASSIGN(TestResource); |
| 89 }; |
| 90 |
| 91 class TestCallback { |
| 92 public: |
| 93 TestCallback() : called_(false), result_(PP_ERROR_FAILED) { |
| 94 } |
| 95 ~TestCallback() { |
| 96 CHECK(called_); |
| 97 } |
| 98 |
| 99 PP_CompletionCallback MakeCompletionCallback() { |
| 100 return PP_MakeCompletionCallback(&CompletionCallbackBody, this); |
| 101 } |
| 102 |
| 103 bool called() const { return called_; } |
| 104 int32_t result() const { return result_; } |
| 105 |
| 106 private: |
| 107 static void CompletionCallbackBody(void* user_data, int32_t result) { |
| 108 TestCallback* callback = static_cast<TestCallback*>(user_data); |
| 109 |
| 110 CHECK(!callback->called_); |
| 111 callback->called_ = true; |
| 112 callback->result_ = result; |
| 113 } |
| 114 |
| 115 bool called_; |
| 116 int32_t result_; |
| 117 |
| 118 DISALLOW_COPY_AND_ASSIGN(TestCallback); |
| 119 }; |
| 120 |
| 121 class TestArrayOutput { |
| 122 public: |
| 123 explicit TestArrayOutput(PluginResourceTracker* resource_tracker) |
| 124 : data_(NULL), |
| 125 count_(0), |
| 126 resource_tracker_(resource_tracker) { |
| 127 } |
| 128 |
| 129 ~TestArrayOutput() { |
| 130 if (count_ > 0) { |
| 131 for (size_t i = 0; i < count_; ++i) |
| 132 resource_tracker_->ReleaseResource(data_[i]); |
| 133 delete [] data_; |
| 134 } |
| 135 } |
| 136 |
| 137 PP_ArrayOutput MakeArrayOutput() { |
| 138 PP_ArrayOutput array_output = { &GetDataBuffer, this }; |
| 139 return array_output; |
| 140 } |
| 141 |
| 142 const PP_Resource* data() const { return data_; } |
| 143 uint32_t count() const { return count_; } |
| 144 |
| 145 private: |
| 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)); |
| 150 |
| 151 TestArrayOutput* output = static_cast<TestArrayOutput*>(user_data); |
| 152 CHECK(!output->data_); |
| 153 |
| 154 output->count_ = element_count; |
| 155 if (element_count > 0) |
| 156 output->data_ = new PP_Resource[element_count]; |
| 157 else |
| 158 output->data_ = NULL; |
| 159 |
| 160 return output->data_; |
| 161 } |
| 162 |
| 163 PP_Resource* data_; |
| 164 uint32_t count_; |
| 165 PluginResourceTracker* resource_tracker_; |
| 166 |
| 167 DISALLOW_COPY_AND_ASSIGN(TestArrayOutput); |
| 168 }; |
| 169 |
| 170 class TestMonitorDeviceChange { |
| 171 public: |
| 172 explicit TestMonitorDeviceChange(PluginVarTracker* var_tracker) |
| 173 : called_(false), |
| 174 same_as_expected_(false), |
| 175 var_tracker_(var_tracker) { |
| 176 } |
| 177 |
| 178 ~TestMonitorDeviceChange() {} |
| 179 |
| 180 void SetExpectedResult(const std::vector<DeviceRefData>& expected) { |
| 181 called_ = false; |
| 182 same_as_expected_ = false; |
| 183 expected_ = expected; |
| 184 } |
| 185 |
| 186 bool called() const { return called_; } |
| 187 |
| 188 bool same_as_expected() const { return same_as_expected_; } |
| 189 |
| 190 static void MonitorDeviceChangeCallback(void* user_data, |
| 191 uint32_t device_count, |
| 192 const PP_Resource devices[]) { |
| 193 TestMonitorDeviceChange* helper = |
| 194 static_cast<TestMonitorDeviceChange*>(user_data); |
| 195 CHECK(!helper->called_); |
| 196 |
| 197 helper->called_ = true; |
| 198 helper->same_as_expected_ = false; |
| 199 if (device_count != helper->expected_.size()) |
| 200 return; |
| 201 for (size_t i = 0; i < device_count; ++i) { |
| 202 if (!CompareDeviceRef(helper->var_tracker_, devices[i], |
| 203 helper->expected_[i])) { |
| 204 return; |
| 205 } |
| 206 } |
| 207 helper->same_as_expected_ = true; |
| 208 } |
| 209 |
| 210 private: |
| 211 bool called_; |
| 212 bool same_as_expected_; |
| 213 std::vector<DeviceRefData> expected_; |
| 214 PluginVarTracker* var_tracker_; |
| 215 |
| 216 DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange); |
| 217 }; |
| 218 |
| 219 } // namespace |
| 220 |
| 221 TEST_F(DeviceEnumerationResourceHelperTest, EnumerateDevices) { |
| 222 scoped_refptr<TestResource> resource( |
| 223 new TestResource(GetConnection(this), pp_instance())); |
| 224 DeviceEnumerationResourceHelper& device_enumeration = |
| 225 resource->device_enumeration(); |
| 226 |
| 227 TestArrayOutput output(&resource_tracker()); |
| 228 TestCallback callback; |
| 229 scoped_refptr<TrackedCallback> tracked_callback( |
| 230 new TrackedCallback(resource.get(), callback.MakeCompletionCallback())); |
| 231 int32_t result = device_enumeration.EnumerateDevices(output.MakeArrayOutput(), |
| 232 tracked_callback); |
| 233 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
| 234 |
| 235 // Should have sent an EnumerateDevices message. |
| 236 ResourceMessageCallParams params; |
| 237 IPC::Message msg; |
| 238 ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
| 239 PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, ¶ms, &msg)); |
| 240 |
| 241 // Synthesize a response. |
| 242 ResourceMessageReplyParams reply_params(params.pp_resource(), |
| 243 params.sequence()); |
| 244 reply_params.set_result(PP_OK); |
| 245 std::vector<DeviceRefData> data; |
| 246 DeviceRefData data_item; |
| 247 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; |
| 248 data_item.name = "name_1"; |
| 249 data_item.id = "id_1"; |
| 250 data.push_back(data_item); |
| 251 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; |
| 252 data_item.name = "name_2"; |
| 253 data_item.id = "id_2"; |
| 254 data.push_back(data_item); |
| 255 |
| 256 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 257 PpapiPluginMsg_ResourceReply( |
| 258 reply_params, |
| 259 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(data)))); |
| 260 |
| 261 EXPECT_TRUE(callback.called()); |
| 262 EXPECT_EQ(PP_OK, callback.result()); |
| 263 EXPECT_EQ(2, output.count()); |
| 264 for (size_t i = 0; i < output.count(); ++i) |
| 265 EXPECT_TRUE(CompareDeviceRef(&var_tracker(), output.data()[i], data[i])); |
| 266 } |
| 267 |
| 268 TEST_F(DeviceEnumerationResourceHelperTest, MonitorDeviceChange) { |
| 269 scoped_refptr<TestResource> resource( |
| 270 new TestResource(GetConnection(this), pp_instance())); |
| 271 DeviceEnumerationResourceHelper& device_enumeration = |
| 272 resource->device_enumeration(); |
| 273 |
| 274 TestMonitorDeviceChange helper(&var_tracker()); |
| 275 |
| 276 int32_t result = device_enumeration.MonitorDeviceChange( |
| 277 &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper); |
| 278 ASSERT_EQ(PP_OK, result); |
| 279 |
| 280 // Should have sent a MonitorDeviceChange message. |
| 281 ResourceMessageCallParams params; |
| 282 IPC::Message msg; |
| 283 ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
| 284 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms, &msg)); |
| 285 sink().ClearMessages(); |
| 286 |
| 287 uint32_t callback_id = 0; |
| 288 ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( |
| 289 msg, &callback_id)); |
| 290 |
| 291 ResourceMessageReplyParams reply_params(params.pp_resource(), 0); |
| 292 reply_params.set_result(PP_OK); |
| 293 std::vector<DeviceRefData> data; |
| 294 |
| 295 helper.SetExpectedResult(data); |
| 296 |
| 297 // Synthesize a response with no device. |
| 298 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 299 PpapiPluginMsg_ResourceReply( |
| 300 reply_params, |
| 301 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
| 302 callback_id, data)))); |
| 303 EXPECT_TRUE(helper.called() && helper.same_as_expected()); |
| 304 |
| 305 DeviceRefData data_item; |
| 306 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; |
| 307 data_item.name = "name_1"; |
| 308 data_item.id = "id_1"; |
| 309 data.push_back(data_item); |
| 310 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; |
| 311 data_item.name = "name_2"; |
| 312 data_item.id = "id_2"; |
| 313 data.push_back(data_item); |
| 314 |
| 315 helper.SetExpectedResult(data); |
| 316 |
| 317 // Synthesize a response with some devices. |
| 318 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 319 PpapiPluginMsg_ResourceReply( |
| 320 reply_params, |
| 321 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
| 322 callback_id, data)))); |
| 323 EXPECT_TRUE(helper.called() && helper.same_as_expected()); |
| 324 |
| 325 TestMonitorDeviceChange helper2(&var_tracker()); |
| 326 |
| 327 result = device_enumeration.MonitorDeviceChange( |
| 328 &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper2); |
| 329 ASSERT_EQ(PP_OK, result); |
| 330 |
| 331 // Should have sent another MonitorDeviceChange message. |
| 332 ResourceMessageCallParams params2; |
| 333 IPC::Message msg2; |
| 334 ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
| 335 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms2, &msg2)); |
| 336 sink().ClearMessages(); |
| 337 |
| 338 uint32_t callback_id2 = 0; |
| 339 ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( |
| 340 msg2, &callback_id2)); |
| 341 |
| 342 helper.SetExpectedResult(data); |
| 343 helper2.SetExpectedResult(data); |
| 344 // |helper2| should receive the result while |helper| shouldn't. |
| 345 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 346 PpapiPluginMsg_ResourceReply( |
| 347 reply_params, |
| 348 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
| 349 callback_id2, data)))); |
| 350 EXPECT_TRUE(helper2.called() && helper2.same_as_expected()); |
| 351 EXPECT_FALSE(helper.called()); |
| 352 |
| 353 helper.SetExpectedResult(data); |
| 354 helper2.SetExpectedResult(data); |
| 355 // Even if a message with |callback_id| arrives. |helper| shouldn't receive |
| 356 // the result. |
| 357 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 358 PpapiPluginMsg_ResourceReply( |
| 359 reply_params, |
| 360 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
| 361 callback_id, data)))); |
| 362 EXPECT_FALSE(helper2.called()); |
| 363 EXPECT_FALSE(helper.called()); |
| 364 |
| 365 result = device_enumeration.MonitorDeviceChange(NULL, NULL); |
| 366 ASSERT_EQ(PP_OK, result); |
| 367 |
| 368 // Should have sent a StopMonitoringDeviceChange message. |
| 369 ResourceMessageCallParams params3; |
| 370 IPC::Message msg3; |
| 371 ASSERT_TRUE(sink().GetFirstResourceCallMatching( |
| 372 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID, |
| 373 ¶ms3, &msg3)); |
| 374 sink().ClearMessages(); |
| 375 |
| 376 helper2.SetExpectedResult(data); |
| 377 // |helper2| shouldn't receive any result any more. |
| 378 ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( |
| 379 PpapiPluginMsg_ResourceReply( |
| 380 reply_params, |
| 381 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( |
| 382 callback_id2, data)))); |
| 383 EXPECT_FALSE(helper2.called()); |
| 384 } |
| 385 |
| 386 } // namespace proxy |
| 387 } // namespace ppapi |
OLD | NEW |