blob: 8e20a934c21f28bcc4623e9ff311d906af983758 [file] [log] [blame]
// 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 <stddef.h>
#include <stdint.h>
#include <map>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.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<ppapi::DeviceRefData> TestEnumerationData() {
std::vector<ppapi::DeviceRefData> 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<TestDelegate> {
public:
TestDelegate() : last_used_id_(0u) {}
~TestDelegate() override { CHECK(monitoring_callbacks_.empty()); }
void EnumerateDevices(PP_DeviceType_Dev /* type */,
const DevicesCallback& callback) override {
callback.Run(TestEnumerationData());
}
size_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 */,
size_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(
size_t subscription_id,
const std::vector<ppapi::DeviceRefData>& 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();
}
size_t last_used_id() const { return last_used_id_; }
private:
std::map<size_t, DevicesCallback> monitoring_callbacks_;
size_t 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<ppapi::DeviceRefData>& 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<ppapi::DeviceRefData> 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::test::ScopedTaskEnvironment
task_environment_; // 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<ppapi::DeviceRefData> 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());
size_t request_id = delegate_.last_used_id();
std::vector<ppapi::DeviceRefData> 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());
size_t 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