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 <map> 6 7 #include "base/basictypes.h" 8 #include "base/compiler_specific.h" 9 #include "base/logging.h" 10 #include "content/renderer/pepper/pepper_device_enumeration_host_helper.h" 11 #include "ppapi/c/pp_errors.h" 12 #include "ppapi/host/host_message_context.h" 13 #include "ppapi/host/ppapi_host.h" 14 #include "ppapi/host/resource_host.h" 15 #include "ppapi/proxy/ppapi_message_utils.h" 16 #include "ppapi/proxy/ppapi_messages.h" 17 #include "ppapi/proxy/resource_message_params.h" 18 #include "ppapi/proxy/resource_message_test_sink.h" 19 #include "ppapi/shared_impl/ppapi_permissions.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "url/gurl.h" 22 23 namespace content { 24 25 namespace { 26 27 class TestDelegate : public PepperDeviceEnumerationHostHelper::Delegate { 28 public: 29 TestDelegate() : last_used_id_(0) {} 30 31 virtual ~TestDelegate() { CHECK(callbacks_.empty()); } 32 33 virtual int EnumerateDevices(PP_DeviceType_Dev /* type */, 34 const GURL& /* document_url */, 35 const EnumerateDevicesCallback& callback) 36 OVERRIDE { 37 last_used_id_++; 38 callbacks_[last_used_id_] = callback; 39 return last_used_id_; 40 } 41 42 virtual void StopEnumerateDevices(int request_id) OVERRIDE { 43 std::map<int, EnumerateDevicesCallback>::iterator iter = 44 callbacks_.find(request_id); 45 CHECK(iter != callbacks_.end()); 46 callbacks_.erase(iter); 47 } 48 49 // Returns false if |request_id| is not found. 50 bool SimulateEnumerateResult( 51 int request_id, 52 const std::vector<ppapi::DeviceRefData>& devices) { 53 std::map<int, EnumerateDevicesCallback>::iterator iter = 54 callbacks_.find(request_id); 55 if (iter == callbacks_.end()) 56 return false; 57 58 iter->second.Run(request_id, devices); 59 return true; 60 } 61 62 size_t GetRegisteredCallbackCount() const { return callbacks_.size(); } 63 64 int last_used_id() const { return last_used_id_; } 65 66 private: 67 std::map<int, EnumerateDevicesCallback> callbacks_; 68 int last_used_id_; 69 70 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 71 }; 72 73 class PepperDeviceEnumerationHostHelperTest : public testing::Test { 74 protected: 75 PepperDeviceEnumerationHostHelperTest() 76 : ppapi_host_(&sink_, ppapi::PpapiPermissions()), 77 resource_host_(&ppapi_host_, 12345, 67890), 78 device_enumeration_(&resource_host_, 79 &delegate_, 80 PP_DEVICETYPE_DEV_AUDIOCAPTURE, 81 GURL("http://example.com")) {} 82 83 virtual ~PepperDeviceEnumerationHostHelperTest() {} 84 85 void SimulateMonitorDeviceChangeReceived(uint32_t callback_id) { 86 PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange msg(callback_id); 87 ppapi::proxy::ResourceMessageCallParams call_params( 88 resource_host_.pp_resource(), 123); 89 ppapi::host::HostMessageContext context(call_params); 90 int32_t result = PP_ERROR_FAILED; 91 ASSERT_TRUE( 92 device_enumeration_.HandleResourceMessage(msg, &context, &result)); 93 EXPECT_EQ(PP_OK, result); 94 } 95 96 void CheckNotifyDeviceChangeMessage( 97 uint32_t callback_id, 98 const std::vector<ppapi::DeviceRefData>& expected) { 99 ppapi::proxy::ResourceMessageReplyParams reply_params; 100 IPC::Message reply_msg; 101 ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( 102 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange::ID, 103 &reply_params, 104 &reply_msg)); 105 sink_.ClearMessages(); 106 107 EXPECT_EQ(PP_OK, reply_params.result()); 108 109 uint32_t reply_callback_id = 0; 110 std::vector<ppapi::DeviceRefData> reply_data; 111 ASSERT_TRUE(ppapi::UnpackMessage< 112 PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange>( 113 reply_msg, &reply_callback_id, &reply_data)); 114 EXPECT_EQ(callback_id, reply_callback_id); 115 EXPECT_EQ(expected, reply_data); 116 } 117 118 TestDelegate delegate_; 119 ppapi::proxy::ResourceMessageTestSink sink_; 120 ppapi::host::PpapiHost ppapi_host_; 121 ppapi::host::ResourceHost resource_host_; 122 PepperDeviceEnumerationHostHelper device_enumeration_; 123 124 private: 125 DISALLOW_COPY_AND_ASSIGN(PepperDeviceEnumerationHostHelperTest); 126 }; 127 128 } // namespace 129 130 TEST_F(PepperDeviceEnumerationHostHelperTest, EnumerateDevices) { 131 PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg; 132 ppapi::proxy::ResourceMessageCallParams call_params( 133 resource_host_.pp_resource(), 123); 134 ppapi::host::HostMessageContext context(call_params); 135 int32_t result = PP_ERROR_FAILED; 136 ASSERT_TRUE( 137 device_enumeration_.HandleResourceMessage(msg, &context, &result)); 138 EXPECT_EQ(PP_OK_COMPLETIONPENDING, result); 139 140 EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); 141 int request_id = delegate_.last_used_id(); 142 143 std::vector<ppapi::DeviceRefData> data; 144 ppapi::DeviceRefData data_item; 145 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; 146 data_item.name = "name_1"; 147 data_item.id = "id_1"; 148 data.push_back(data_item); 149 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; 150 data_item.name = "name_2"; 151 data_item.id = "id_2"; 152 data.push_back(data_item); 153 ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, data)); 154 155 // StopEnumerateDevices() should have been called since the EnumerateDevices 156 // message is not a persistent request. 157 EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount()); 158 159 // A reply message should have been sent to the test sink. 160 ppapi::proxy::ResourceMessageReplyParams reply_params; 161 IPC::Message reply_msg; 162 ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( 163 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply::ID, 164 &reply_params, 165 &reply_msg)); 166 167 EXPECT_EQ(call_params.sequence(), reply_params.sequence()); 168 EXPECT_EQ(PP_OK, reply_params.result()); 169 170 std::vector<ppapi::DeviceRefData> reply_data; 171 ASSERT_TRUE(ppapi::UnpackMessage< 172 PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(reply_msg, 173 &reply_data)); 174 EXPECT_EQ(data, reply_data); 175 } 176 177 TEST_F(PepperDeviceEnumerationHostHelperTest, MonitorDeviceChange) { 178 uint32_t callback_id = 456; 179 SimulateMonitorDeviceChangeReceived(callback_id); 180 181 EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); 182 int request_id = delegate_.last_used_id(); 183 184 std::vector<ppapi::DeviceRefData> data; 185 ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, data)); 186 187 // StopEnumerateDevices() shouldn't be called because the MonitorDeviceChange 188 // message is a persistent request. 189 EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); 190 191 CheckNotifyDeviceChangeMessage(callback_id, data); 192 193 ppapi::DeviceRefData data_item; 194 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; 195 data_item.name = "name_1"; 196 data_item.id = "id_1"; 197 data.push_back(data_item); 198 data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; 199 data_item.name = "name_2"; 200 data_item.id = "id_2"; 201 data.push_back(data_item); 202 ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, data)); 203 EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); 204 205 CheckNotifyDeviceChangeMessage(callback_id, data); 206 207 uint32_t callback_id2 = 789; 208 SimulateMonitorDeviceChangeReceived(callback_id2); 209 210 // StopEnumerateDevice() should have been called for the previous request. 211 EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); 212 int request_id2 = delegate_.last_used_id(); 213 214 data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; 215 data_item.name = "name_3"; 216 data_item.id = "id_3"; 217 data.push_back(data_item); 218 ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id2, data)); 219 220 CheckNotifyDeviceChangeMessage(callback_id2, data); 221 222 PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange msg; 223 ppapi::proxy::ResourceMessageCallParams call_params( 224 resource_host_.pp_resource(), 123); 225 ppapi::host::HostMessageContext context(call_params); 226 int32_t result = PP_ERROR_FAILED; 227 ASSERT_TRUE( 228 device_enumeration_.HandleResourceMessage(msg, &context, &result)); 229 EXPECT_EQ(PP_OK, result); 230 231 EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount()); 232 } 233 234 } // namespace content 235