// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "content/renderer/pepper/pepper_device_enumeration_host_helper.h" #include "ppapi/c/pp_errors.h" #include "ppapi/host/host_message_context.h" #include "ppapi/host/ppapi_host.h" #include "ppapi/host/resource_host.h" #include "ppapi/proxy/ppapi_message_utils.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/resource_message_params.h" #include "ppapi/proxy/resource_message_test_sink.h" #include "ppapi/shared_impl/ppapi_permissions.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace content { namespace { std::vector TestEnumerationData() { std::vector data; ppapi::DeviceRefData data_item; data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; data_item.name = "name_1"; data_item.id = "id_1"; data.push_back(data_item); data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; data_item.name = "name_2"; data_item.id = "id_2"; data.push_back(data_item); return data; } class TestDelegate : public PepperDeviceEnumerationHostHelper::Delegate, public base::SupportsWeakPtr { public: TestDelegate() : last_used_id_(0) {} ~TestDelegate() override { CHECK(monitoring_callbacks_.empty()); } void EnumerateDevices(PP_DeviceType_Dev /* type */, const DevicesCallback& callback) override { callback.Run(TestEnumerationData()); } uint32_t StartMonitoringDevices(PP_DeviceType_Dev /* type */, const DevicesCallback& callback) override { last_used_id_++; monitoring_callbacks_[last_used_id_] = callback; return last_used_id_; } void StopMonitoringDevices(PP_DeviceType_Dev /* type */, uint32_t subscription_id) override { auto iter = monitoring_callbacks_.find(subscription_id); CHECK(iter != monitoring_callbacks_.end()); monitoring_callbacks_.erase(iter); } // Returns false if |request_id| is not found. bool SimulateDevicesChanged( uint32_t subscription_id, const std::vector& devices) { auto iter = monitoring_callbacks_.find(subscription_id); if (iter == monitoring_callbacks_.end()) return false; iter->second.Run(devices); return true; } size_t GetRegisteredCallbackCount() const { return monitoring_callbacks_.size(); } int last_used_id() const { return last_used_id_; } private: std::map monitoring_callbacks_; int last_used_id_; DISALLOW_COPY_AND_ASSIGN(TestDelegate); }; class PepperDeviceEnumerationHostHelperTest : public testing::Test { protected: PepperDeviceEnumerationHostHelperTest() : ppapi_host_(&sink_, ppapi::PpapiPermissions()), resource_host_(&ppapi_host_, 12345, 67890), device_enumeration_(&resource_host_, delegate_.AsWeakPtr(), PP_DEVICETYPE_DEV_AUDIOCAPTURE, GURL("http://example.com")) {} ~PepperDeviceEnumerationHostHelperTest() override {} void SimulateMonitorDeviceChangeReceived(uint32_t callback_id) { PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange msg(callback_id); ppapi::proxy::ResourceMessageCallParams call_params( resource_host_.pp_resource(), 123); ppapi::host::HostMessageContext context(call_params); int32_t result = PP_ERROR_FAILED; ASSERT_TRUE( device_enumeration_.HandleResourceMessage(msg, &context, &result)); EXPECT_EQ(PP_OK, result); } void CheckNotifyDeviceChangeMessage( uint32_t callback_id, const std::vector& expected) { ppapi::proxy::ResourceMessageReplyParams reply_params; IPC::Message reply_msg; ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange::ID, &reply_params, &reply_msg)); sink_.ClearMessages(); EXPECT_EQ(PP_OK, reply_params.result()); uint32_t reply_callback_id = 0; std::vector reply_data; ASSERT_TRUE(ppapi::UnpackMessage< PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange>( reply_msg, &reply_callback_id, &reply_data)); EXPECT_EQ(callback_id, reply_callback_id); EXPECT_EQ(expected, reply_data); } TestDelegate delegate_; ppapi::proxy::ResourceMessageTestSink sink_; ppapi::host::PpapiHost ppapi_host_; ppapi::host::ResourceHost resource_host_; PepperDeviceEnumerationHostHelper device_enumeration_; base::MessageLoop message_loop_; // required for async calls to work. private: DISALLOW_COPY_AND_ASSIGN(PepperDeviceEnumerationHostHelperTest); }; } // namespace TEST_F(PepperDeviceEnumerationHostHelperTest, EnumerateDevices) { PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg; ppapi::proxy::ResourceMessageCallParams call_params( resource_host_.pp_resource(), 123); ppapi::host::HostMessageContext context(call_params); int32_t result = PP_ERROR_FAILED; ASSERT_TRUE( device_enumeration_.HandleResourceMessage(msg, &context, &result)); EXPECT_EQ(PP_OK_COMPLETIONPENDING, result); base::RunLoop().RunUntilIdle(); // A reply message should have been sent to the test sink. ppapi::proxy::ResourceMessageReplyParams reply_params; IPC::Message reply_msg; ASSERT_TRUE(sink_.GetFirstResourceReplyMatching( PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply::ID, &reply_params, &reply_msg)); EXPECT_EQ(call_params.sequence(), reply_params.sequence()); EXPECT_EQ(PP_OK, reply_params.result()); std::vector reply_data; ASSERT_TRUE(ppapi::UnpackMessage< PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(reply_msg, &reply_data)); EXPECT_EQ(TestEnumerationData(), reply_data); } TEST_F(PepperDeviceEnumerationHostHelperTest, MonitorDeviceChange) { uint32_t callback_id = 456; SimulateMonitorDeviceChangeReceived(callback_id); EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); int request_id = delegate_.last_used_id(); std::vector data; ASSERT_TRUE(delegate_.SimulateDevicesChanged(request_id, data)); // StopEnumerateDevices() shouldn't be called because the MonitorDeviceChange // message is a persistent request. EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); CheckNotifyDeviceChangeMessage(callback_id, data); ppapi::DeviceRefData data_item; data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; data_item.name = "name_1"; data_item.id = "id_1"; data.push_back(data_item); data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; data_item.name = "name_2"; data_item.id = "id_2"; data.push_back(data_item); ASSERT_TRUE(delegate_.SimulateDevicesChanged(request_id, data)); EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); CheckNotifyDeviceChangeMessage(callback_id, data); uint32_t callback_id2 = 789; SimulateMonitorDeviceChangeReceived(callback_id2); // StopEnumerateDevice() should have been called for the previous request. EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount()); int request_id2 = delegate_.last_used_id(); data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; data_item.name = "name_3"; data_item.id = "id_3"; data.push_back(data_item); ASSERT_TRUE(delegate_.SimulateDevicesChanged(request_id2, data)); CheckNotifyDeviceChangeMessage(callback_id2, data); PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange msg; ppapi::proxy::ResourceMessageCallParams call_params( resource_host_.pp_resource(), 123); ppapi::host::HostMessageContext context(call_params); int32_t result = PP_ERROR_FAILED; ASSERT_TRUE( device_enumeration_.HandleResourceMessage(msg, &context, &result)); EXPECT_EQ(PP_OK, result); EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount()); } } // namespace content