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 25 namespace ppapi { 26 namespace proxy { 27 28 namespace { 29 30 typedef PluginProxyTest WebSocketResourceTest; 31 32 bool g_callback_called; 33 int32_t g_callback_result; 34 const PPB_Var* ppb_var_ = NULL; 35 36 void Callback(void* user_data, int32_t result) { 37 g_callback_called = true; 38 g_callback_result = result; 39 } 40 41 PP_CompletionCallback MakeCallback() { 42 g_callback_called = false; 43 g_callback_result = PP_OK; 44 return PP_MakeCompletionCallback(Callback, NULL); 45 } 46 47 PP_Var MakeStringVar(const std::string& string) { 48 if (!ppb_var_) 49 ppb_var_ = ppapi::PPB_Var_Shared::GetVarInterface1_1(); 50 return ppb_var_->VarFromUtf8(string.c_str(), string.length()); 51 } 52 53 } // namespace 54 55 56 // Does a test of Connect(). 57 TEST_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, ¶ms, &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. 96 TEST_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 121 TEST_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, ¶ms, &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