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/memory/ref_counted.h"
6#include "base/message_loop/message_loop.h"
7#include "ppapi/c/pp_errors.h"
8#include "ppapi/c/ppb_var.h"
9#include "ppapi/c/ppb_websocket.h"
10#include "ppapi/proxy/locking_resource_releaser.h"
11#include "ppapi/proxy/plugin_message_filter.h"
12#include "ppapi/proxy/ppapi_messages.h"
13#include "ppapi/proxy/ppapi_proxy_test.h"
14#include "ppapi/proxy/websocket_resource.h"
15#include "ppapi/shared_impl/ppapi_globals.h"
16#include "ppapi/shared_impl/ppb_var_shared.h"
17#include "ppapi/shared_impl/proxy_lock.h"
18#include "ppapi/shared_impl/resource_tracker.h"
19#include "ppapi/shared_impl/scoped_pp_resource.h"
20#include "ppapi/shared_impl/scoped_pp_var.h"
21#include "ppapi/shared_impl/tracked_callback.h"
22#include "ppapi/shared_impl/var.h"
23#include "ppapi/thunk/thunk.h"
24
25namespace ppapi {
26namespace proxy {
27
28namespace {
29
30typedef PluginProxyTest WebSocketResourceTest;
31
32bool g_callback_called;
33int32_t g_callback_result;
34const PPB_Var* ppb_var_ = NULL;
35
36void Callback(void* user_data, int32_t result) {
37  g_callback_called = true;
38  g_callback_result = result;
39}
40
41PP_CompletionCallback MakeCallback() {
42  g_callback_called = false;
43  g_callback_result = PP_OK;
44  return PP_MakeCompletionCallback(Callback, NULL);
45}
46
47PP_Var MakeStringVar(const std::string& string) {
48  if (!ppb_var_)
49    ppb_var_ = ppapi::PPB_Var_Shared::GetVarInterface1_2();
50  return ppb_var_->VarFromUtf8(string.c_str(), string.length());
51}
52
53}  // namespace
54
55
56// Does a test of Connect().
57TEST_F(WebSocketResourceTest, Connect) {
58  const PPB_WebSocket_1_0* websocket_iface =
59      thunk::GetPPB_WebSocket_1_0_Thunk();
60
61  std::string url("ws://ws.google.com");
62  std::string protocol0("x-foo");
63  std::string protocol1("x-bar");
64  PP_Var url_var = MakeStringVar(url);
65  PP_Var protocols[] = { MakeStringVar(protocol0), MakeStringVar(protocol1) };
66
67  LockingResourceReleaser res(websocket_iface->Create(pp_instance()));
68
69  int32_t result = websocket_iface->Connect(res.get(), url_var, protocols, 2,
70                                            MakeCallback());
71  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
72
73  // Should be sent a "Connect" message.
74  ResourceMessageCallParams params;
75  IPC::Message msg;
76  ASSERT_TRUE(sink().GetFirstResourceCallMatching(
77      PpapiHostMsg_WebSocket_Connect::ID, &params, &msg));
78  PpapiHostMsg_WebSocket_Connect::Schema::Param p;
79  PpapiHostMsg_WebSocket_Connect::Read(&msg, &p);
80  EXPECT_EQ(url, p.a);
81  EXPECT_EQ(protocol0, p.b[0]);
82  EXPECT_EQ(protocol1, p.b[1]);
83
84  // Synthesize a response.
85  ResourceMessageReplyParams reply_params(params.pp_resource(),
86                                          params.sequence());
87  reply_params.set_result(PP_OK);
88  PluginMessageFilter::DispatchResourceReplyForTest(
89      reply_params, PpapiPluginMsg_WebSocket_ConnectReply(url, protocol1));
90
91  EXPECT_EQ(PP_OK, g_callback_result);
92  EXPECT_EQ(true, g_callback_called);
93}
94
95// Does a test for unsolicited replies.
96TEST_F(WebSocketResourceTest, UnsolicitedReplies) {
97  const PPB_WebSocket_1_0* websocket_iface =
98      thunk::GetPPB_WebSocket_1_0_Thunk();
99
100  LockingResourceReleaser res(websocket_iface->Create(pp_instance()));
101
102  // Check if BufferedAmountReply is handled.
103  ResourceMessageReplyParams reply_params(res.get(), 0);
104  reply_params.set_result(PP_OK);
105  PluginMessageFilter::DispatchResourceReplyForTest(
106      reply_params, PpapiPluginMsg_WebSocket_BufferedAmountReply(19760227u));
107
108  uint64_t amount = websocket_iface->GetBufferedAmount(res.get());
109  EXPECT_EQ(19760227u, amount);
110
111  // Check if StateReply is handled.
112  PluginMessageFilter::DispatchResourceReplyForTest(
113      reply_params,
114      PpapiPluginMsg_WebSocket_StateReply(
115          static_cast<int32_t>(PP_WEBSOCKETREADYSTATE_CLOSING)));
116
117  PP_WebSocketReadyState state = websocket_iface->GetReadyState(res.get());
118  EXPECT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, state);
119}
120
121TEST_F(WebSocketResourceTest, MessageError) {
122  const PPB_WebSocket_1_0* websocket_iface =
123      thunk::GetPPB_WebSocket_1_0_Thunk();
124
125  std::string url("ws://ws.google.com");
126  PP_Var url_var = MakeStringVar(url);
127
128  LockingResourceReleaser res(websocket_iface->Create(pp_instance()));
129
130  // Establish the connection virtually.
131  int32_t result =
132      websocket_iface->Connect(res.get(), url_var, NULL, 0, MakeCallback());
133  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
134
135  ResourceMessageCallParams params;
136  IPC::Message msg;
137  ASSERT_TRUE(sink().GetFirstResourceCallMatching(
138      PpapiHostMsg_WebSocket_Connect::ID, &params, &msg));
139
140  ResourceMessageReplyParams connect_reply_params(params.pp_resource(),
141                                                  params.sequence());
142  connect_reply_params.set_result(PP_OK);
143  PluginMessageFilter::DispatchResourceReplyForTest(
144      connect_reply_params,
145      PpapiPluginMsg_WebSocket_ConnectReply(url, std::string()));
146
147  EXPECT_EQ(PP_OK, g_callback_result);
148  EXPECT_TRUE(g_callback_called);
149
150  PP_Var message;
151  result = websocket_iface->ReceiveMessage(res.get(), &message, MakeCallback());
152  EXPECT_FALSE(g_callback_called);
153
154  // Synthesize a WebSocket_ErrorReply message.
155  ResourceMessageReplyParams error_reply_params(res.get(), 0);
156  error_reply_params.set_result(PP_OK);
157  PluginMessageFilter::DispatchResourceReplyForTest(
158      error_reply_params, PpapiPluginMsg_WebSocket_ErrorReply());
159
160  EXPECT_EQ(PP_ERROR_FAILED, g_callback_result);
161  EXPECT_TRUE(g_callback_called);
162}
163
164}  // namespace proxy
165}  // namespace ppapi
166