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
22namespace content {
23
24namespace {
25
26class TestDelegate : public PepperDeviceEnumerationHostHelper::Delegate {
27 public:
28  TestDelegate() : last_used_id_(0) {
29  }
30
31  virtual ~TestDelegate() {
32    CHECK(callbacks_.empty());
33  }
34
35  virtual int EnumerateDevices(
36      PP_DeviceType_Dev /* type */,
37      const EnumerateDevicesCallback& callback) OVERRIDE {
38    last_used_id_++;
39    callbacks_[last_used_id_] = callback;
40    return last_used_id_;
41  }
42
43  virtual void StopEnumerateDevices(int request_id) OVERRIDE {
44    std::map<int, EnumerateDevicesCallback>::iterator iter =
45        callbacks_.find(request_id);
46    CHECK(iter != callbacks_.end());
47    callbacks_.erase(iter);
48  }
49
50  // Returns false if |request_id| is not found.
51  bool SimulateEnumerateResult(
52      int request_id,
53      bool succeeded,
54      const std::vector<ppapi::DeviceRefData>& devices) {
55    std::map<int, EnumerateDevicesCallback>::iterator iter =
56        callbacks_.find(request_id);
57    if (iter == callbacks_.end())
58      return false;
59
60    iter->second.Run(request_id, succeeded, devices);
61    return true;
62  }
63
64  size_t GetRegisteredCallbackCount() const { return callbacks_.size(); }
65
66  int last_used_id() const { return last_used_id_; }
67
68 private:
69  std::map<int, EnumerateDevicesCallback> callbacks_;
70  int last_used_id_;
71
72  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
73};
74
75class PepperDeviceEnumerationHostHelperTest : public testing::Test {
76 protected:
77  PepperDeviceEnumerationHostHelperTest()
78      : ppapi_host_(&sink_, ppapi::PpapiPermissions()),
79        resource_host_(&ppapi_host_, 12345, 67890),
80        device_enumeration_(&resource_host_, &delegate_,
81                            PP_DEVICETYPE_DEV_AUDIOCAPTURE) {
82  }
83
84  virtual ~PepperDeviceEnumerationHostHelperTest() {}
85
86  void SimulateMonitorDeviceChangeReceived(uint32_t callback_id) {
87    PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange msg(callback_id);
88    ppapi::proxy::ResourceMessageCallParams call_params(
89        resource_host_.pp_resource(), 123);
90    ppapi::host::HostMessageContext context(call_params);
91    int32_t result = PP_ERROR_FAILED;
92    ASSERT_TRUE(device_enumeration_.HandleResourceMessage(
93        msg, &context, &result));
94    EXPECT_EQ(PP_OK, result);
95  }
96
97  void CheckNotifyDeviceChangeMessage(
98      uint32_t callback_id,
99      const std::vector<ppapi::DeviceRefData>& expected) {
100    ppapi::proxy::ResourceMessageReplyParams reply_params;
101    IPC::Message reply_msg;
102    ASSERT_TRUE(sink_.GetFirstResourceReplyMatching(
103        PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange::ID,
104        &reply_params, &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
130TEST_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(device_enumeration_.HandleResourceMessage(msg, &context,
137                                                        &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, true, 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, &reply_msg));
165
166  EXPECT_EQ(call_params.sequence(), reply_params.sequence());
167  EXPECT_EQ(PP_OK, reply_params.result());
168
169  std::vector<ppapi::DeviceRefData> reply_data;
170  ASSERT_TRUE(ppapi::UnpackMessage<
171      PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>(
172          reply_msg, &reply_data));
173  EXPECT_EQ(data, reply_data);
174}
175
176TEST_F(PepperDeviceEnumerationHostHelperTest, MonitorDeviceChange) {
177  uint32_t callback_id = 456;
178  SimulateMonitorDeviceChangeReceived(callback_id);
179
180  EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount());
181  int request_id = delegate_.last_used_id();
182
183  std::vector<ppapi::DeviceRefData> data;
184  ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, true, data));
185
186  // StopEnumerateDevices() shouldn't be called because the MonitorDeviceChange
187  // message is a persistent request.
188  EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount());
189
190  CheckNotifyDeviceChangeMessage(callback_id, data);
191
192  ppapi::DeviceRefData data_item;
193  data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE;
194  data_item.name = "name_1";
195  data_item.id = "id_1";
196  data.push_back(data_item);
197  data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE;
198  data_item.name = "name_2";
199  data_item.id = "id_2";
200  data.push_back(data_item);
201  ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id, true, data));
202  EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount());
203
204  CheckNotifyDeviceChangeMessage(callback_id, data);
205
206  uint32_t callback_id2 = 789;
207  SimulateMonitorDeviceChangeReceived(callback_id2);
208
209  // StopEnumerateDevice() should have been called for the previous request.
210  EXPECT_EQ(1U, delegate_.GetRegisteredCallbackCount());
211  int request_id2 = delegate_.last_used_id();
212
213  data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE;
214  data_item.name = "name_3";
215  data_item.id = "id_3";
216  data.push_back(data_item);
217  ASSERT_TRUE(delegate_.SimulateEnumerateResult(request_id2, true, data));
218
219  CheckNotifyDeviceChangeMessage(callback_id2, data);
220
221  PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange msg;
222  ppapi::proxy::ResourceMessageCallParams call_params(
223      resource_host_.pp_resource(), 123);
224  ppapi::host::HostMessageContext context(call_params);
225  int32_t result = PP_ERROR_FAILED;
226  ASSERT_TRUE(device_enumeration_.HandleResourceMessage(
227      msg, &context, &result));
228  EXPECT_EQ(PP_OK, result);
229
230  EXPECT_EQ(0U, delegate_.GetRegisteredCallbackCount());
231}
232
233}  // namespace content
234