// 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 "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/ppb_var.h" #include "ppapi/c/ppb_websocket.h" #include "ppapi/proxy/locking_resource_releaser.h" #include "ppapi/proxy/plugin_message_filter.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppapi_proxy_test.h" #include "ppapi/proxy/websocket_resource.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/ppb_var_shared.h" #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/resource_tracker.h" #include "ppapi/shared_impl/scoped_pp_resource.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "ppapi/shared_impl/tracked_callback.h" #include "ppapi/shared_impl/var.h" #include "ppapi/thunk/thunk.h" namespace ppapi { namespace proxy { namespace { typedef PluginProxyTest WebSocketResourceTest; bool g_callback_called; int32_t g_callback_result; const PPB_Var* ppb_var_ = NULL; void Callback(void* user_data, int32_t result) { g_callback_called = true; g_callback_result = result; } PP_CompletionCallback MakeCallback() { g_callback_called = false; g_callback_result = PP_OK; return PP_MakeCompletionCallback(Callback, NULL); } PP_Var MakeStringVar(const std::string& string) { if (!ppb_var_) ppb_var_ = ppapi::PPB_Var_Shared::GetVarInterface1_2(); return ppb_var_->VarFromUtf8(string.c_str(), static_cast(string.length())); } } // namespace // Does a test of Connect(). TEST_F(WebSocketResourceTest, Connect) { const PPB_WebSocket_1_0* websocket_iface = thunk::GetPPB_WebSocket_1_0_Thunk(); std::string url("ws://ws.google.com"); std::string protocol0("x-foo"); std::string protocol1("x-bar"); PP_Var url_var = MakeStringVar(url); PP_Var protocols[] = { MakeStringVar(protocol0), MakeStringVar(protocol1) }; LockingResourceReleaser res(websocket_iface->Create(pp_instance())); int32_t result = websocket_iface->Connect(res.get(), url_var, protocols, 2, MakeCallback()); ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); // Should be sent a "Connect" message. ResourceMessageCallParams params; IPC::Message msg; ASSERT_TRUE(sink().GetFirstResourceCallMatching( PpapiHostMsg_WebSocket_Connect::ID, ¶ms, &msg)); PpapiHostMsg_WebSocket_Connect::Schema::Param p; PpapiHostMsg_WebSocket_Connect::Read(&msg, &p); EXPECT_EQ(url, base::get<0>(p)); EXPECT_EQ(protocol0, base::get<1>(p)[0]); EXPECT_EQ(protocol1, base::get<1>(p)[1]); // Synthesize a response. ResourceMessageReplyParams reply_params(params.pp_resource(), params.sequence()); reply_params.set_result(PP_OK); PluginMessageFilter::DispatchResourceReplyForTest( reply_params, PpapiPluginMsg_WebSocket_ConnectReply(url, protocol1)); EXPECT_EQ(PP_OK, g_callback_result); EXPECT_EQ(true, g_callback_called); } // Does a test for unsolicited replies. TEST_F(WebSocketResourceTest, UnsolicitedReplies) { const PPB_WebSocket_1_0* websocket_iface = thunk::GetPPB_WebSocket_1_0_Thunk(); LockingResourceReleaser res(websocket_iface->Create(pp_instance())); // Check if BufferedAmountReply is handled. ResourceMessageReplyParams reply_params(res.get(), 0); reply_params.set_result(PP_OK); PluginMessageFilter::DispatchResourceReplyForTest( reply_params, PpapiPluginMsg_WebSocket_BufferedAmountReply(19760227u)); uint64_t amount = websocket_iface->GetBufferedAmount(res.get()); EXPECT_EQ(19760227u, amount); // Check if StateReply is handled. PluginMessageFilter::DispatchResourceReplyForTest( reply_params, PpapiPluginMsg_WebSocket_StateReply( static_cast(PP_WEBSOCKETREADYSTATE_CLOSING))); PP_WebSocketReadyState state = websocket_iface->GetReadyState(res.get()); EXPECT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, state); } TEST_F(WebSocketResourceTest, MessageError) { const PPB_WebSocket_1_0* websocket_iface = thunk::GetPPB_WebSocket_1_0_Thunk(); std::string url("ws://ws.google.com"); PP_Var url_var = MakeStringVar(url); LockingResourceReleaser res(websocket_iface->Create(pp_instance())); // Establish the connection virtually. int32_t result = websocket_iface->Connect(res.get(), url_var, NULL, 0, MakeCallback()); ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); ResourceMessageCallParams params; IPC::Message msg; ASSERT_TRUE(sink().GetFirstResourceCallMatching( PpapiHostMsg_WebSocket_Connect::ID, ¶ms, &msg)); ResourceMessageReplyParams connect_reply_params(params.pp_resource(), params.sequence()); connect_reply_params.set_result(PP_OK); PluginMessageFilter::DispatchResourceReplyForTest( connect_reply_params, PpapiPluginMsg_WebSocket_ConnectReply(url, std::string())); EXPECT_EQ(PP_OK, g_callback_result); EXPECT_TRUE(g_callback_called); PP_Var message; result = websocket_iface->ReceiveMessage(res.get(), &message, MakeCallback()); EXPECT_FALSE(g_callback_called); // Synthesize a WebSocket_ErrorReply message. ResourceMessageReplyParams error_reply_params(res.get(), 0); error_reply_params.set_result(PP_OK); PluginMessageFilter::DispatchResourceReplyForTest( error_reply_params, PpapiPluginMsg_WebSocket_ErrorReply()); EXPECT_EQ(PP_ERROR_FAILED, g_callback_result); EXPECT_TRUE(g_callback_called); } } // namespace proxy } // namespace ppapi