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