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 "ppapi/tests/test_websocket.h"
6 
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <algorithm>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #include "ppapi/c/pp_bool.h"
17 #include "ppapi/c/pp_completion_callback.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/c/pp_instance.h"
20 #include "ppapi/c/pp_resource.h"
21 #include "ppapi/c/pp_var.h"
22 #include "ppapi/c/ppb_core.h"
23 #include "ppapi/c/ppb_var.h"
24 #include "ppapi/c/ppb_var_array_buffer.h"
25 #include "ppapi/c/ppb_websocket.h"
26 #include "ppapi/c/private/ppb_testing_private.h"
27 #include "ppapi/cpp/instance.h"
28 #include "ppapi/cpp/module.h"
29 #include "ppapi/cpp/var_array_buffer.h"
30 #include "ppapi/cpp/websocket.h"
31 #include "ppapi/tests/test_utils.h"
32 #include "ppapi/tests/testing_instance.h"
33 #include "ppapi/utility/websocket/websocket_api.h"
34 
35 // net::SpawnedTestServer serves WebSocket service for testing.
36 // Following URLs are handled by pywebsocket handlers in
37 // net/data/websocket/*_wsh.py.
38 const char kEchoServerURL[] = "echo-with-no-extension";
39 const char kCloseServerURL[] = "close";
40 const char kCloseWithCodeAndReasonServerURL[] = "close-code-and-reason";
41 const char kProtocolTestServerURL[] = "protocol-test?protocol=";
42 
43 const char* const kInvalidURLs[] = {"http://www.google.com/invalid_scheme",
44                                     "ws://www.google.com/invalid#fragment",
45                                     "ws://www.google.com:7/invalid_port",
46                                     NULL};
47 
48 // Internal packet sizes.
49 const uint64_t kMessageFrameOverhead = 6;
50 
51 namespace {
52 
53 struct WebSocketEvent {
54   enum EventType {
55     EVENT_OPEN,
56     EVENT_MESSAGE,
57     EVENT_ERROR,
58     EVENT_CLOSE
59   };
60 
WebSocketEvent__anon5d07696a0111::WebSocketEvent61   WebSocketEvent(EventType type,
62                  bool was_clean,
63                  uint16_t close_code,
64                  const pp::Var& var)
65       : event_type(type),
66         was_clean(was_clean),
67         close_code(close_code),
68         var(var) {
69   }
70   EventType event_type;
71   bool was_clean;
72   uint16_t close_code;
73   pp::Var var;
74 };
75 
76 class ReleaseResourceDelegate : public TestCompletionCallback::Delegate {
77  public:
ReleaseResourceDelegate(const PPB_Core * core_interface,PP_Resource resource)78   explicit ReleaseResourceDelegate(const PPB_Core* core_interface,
79                                    PP_Resource resource)
80       : core_interface_(core_interface),
81         resource_(resource) {
82   }
83 
84   // TestCompletionCallback::Delegate implementation.
OnCallback(void * user_data,int32_t result)85   virtual void OnCallback(void* user_data, int32_t result) {
86     if (resource_)
87       core_interface_->ReleaseResource(resource_);
88   }
89 
90  private:
91   const PPB_Core* core_interface_;
92   PP_Resource resource_;
93 };
94 
95 class TestWebSocketAPI : public pp::WebSocketAPI {
96  public:
TestWebSocketAPI(pp::Instance * instance)97   explicit TestWebSocketAPI(pp::Instance* instance)
98       : pp::WebSocketAPI(instance),
99         connected_(false),
100         received_(false),
101         closed_(false),
102         wait_for_connected_(false),
103         wait_for_received_(false),
104         wait_for_closed_(false),
105         instance_(instance->pp_instance()) {
106   }
107 
WebSocketDidOpen()108   virtual void WebSocketDidOpen() {
109     events_.push_back(
110         WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var()));
111     connected_ = true;
112     if (wait_for_connected_) {
113       GetTestingInterface()->QuitMessageLoop(instance_);
114       wait_for_connected_ = false;
115     }
116   }
117 
WebSocketDidClose(bool was_clean,uint16_t code,const pp::Var & reason)118   virtual void WebSocketDidClose(
119       bool was_clean, uint16_t code, const pp::Var& reason) {
120     events_.push_back(
121         WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason));
122     connected_ = true;
123     closed_ = true;
124     if (wait_for_connected_ || wait_for_closed_) {
125       GetTestingInterface()->QuitMessageLoop(instance_);
126       wait_for_connected_ = false;
127       wait_for_closed_ = false;
128     }
129   }
130 
HandleWebSocketMessage(const pp::Var & message)131   virtual void HandleWebSocketMessage(const pp::Var &message) {
132     events_.push_back(
133         WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message));
134     received_ = true;
135     if (wait_for_received_) {
136       GetTestingInterface()->QuitMessageLoop(instance_);
137       wait_for_received_ = false;
138       received_ = false;
139     }
140   }
141 
HandleWebSocketError()142   virtual void HandleWebSocketError() {
143     events_.push_back(
144         WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var()));
145   }
146 
WaitForConnected()147   void WaitForConnected() {
148     if (!connected_) {
149       wait_for_connected_ = true;
150       GetTestingInterface()->RunMessageLoop(instance_);
151     }
152   }
153 
WaitForReceived()154   void WaitForReceived() {
155     if (!received_) {
156       wait_for_received_ = true;
157       GetTestingInterface()->RunMessageLoop(instance_);
158     }
159   }
160 
WaitForClosed()161   void WaitForClosed() {
162     if (!closed_) {
163       wait_for_closed_ = true;
164       GetTestingInterface()->RunMessageLoop(instance_);
165     }
166   }
167 
GetSeenEvents() const168   const std::vector<WebSocketEvent>& GetSeenEvents() const {
169     return events_;
170   }
171 
172  private:
173   std::vector<WebSocketEvent> events_;
174   bool connected_;
175   bool received_;
176   bool closed_;
177   bool wait_for_connected_;
178   bool wait_for_received_;
179   bool wait_for_closed_;
180   PP_Instance instance_;
181 };
182 
183 }  // namespace
184 
185 REGISTER_TEST_CASE(WebSocket);
186 
Init()187 bool TestWebSocket::Init() {
188   websocket_interface_ = static_cast<const PPB_WebSocket*>(
189       pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE));
190   var_interface_ = static_cast<const PPB_Var*>(
191       pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
192   arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>(
193       pp::Module::Get()->GetBrowserInterface(
194           PPB_VAR_ARRAY_BUFFER_INTERFACE));
195   core_interface_ = static_cast<const PPB_Core*>(
196       pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
197   if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ ||
198       !core_interface_)
199     return false;
200 
201   return CheckTestingInterface();
202 }
203 
RunTests(const std::string & filter)204 void TestWebSocket::RunTests(const std::string& filter) {
205   RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter);
206   RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter);
207   RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter);
208   RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter);
209   RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter);
210   RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter);
211   RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter);
212   RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter);
213   RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter);
214   RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter);
215   RUN_TEST_BACKGROUND(TestWebSocket, TextSendReceiveTwice, filter);
216   RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive, filter);
217   RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive, filter);
218   RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount, filter);
219   // PP_Resource for WebSocket may be released later because of an internal
220   // reference for asynchronous IPC handling. So, suppress reference check on
221   // the following AbortCallsWithCallback test.
222   RUN_TEST(AbortCallsWithCallback, filter);
223   RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall, filter);
224   RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall, filter);
225   RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall, filter);
226   RUN_TEST_WITH_REFERENCE_CHECK(ClosedFromServerWhileSending, filter);
227 
228   RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter);
229 
230   RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect, filter);
231   RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols, filter);
232   RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL, filter);
233   RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect, filter);
234   RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose, filter);
235   RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose, filter);
236   RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol, filter);
237   RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive, filter);
238   RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive, filter);
239   RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount, filter);
240 }
241 
GetFullURL(const char * url)242 std::string TestWebSocket::GetFullURL(const char* url) {
243   std::string rv = "ws://";
244   // Some WebSocket tests don't start the server so there'll be no host and
245   // port.
246   if (instance_->websocket_host().empty())
247     rv += "127.0.0.1";
248   else
249     rv += instance_->websocket_host();
250   if (instance_->websocket_port() != -1) {
251     char buffer[10];
252     sprintf(buffer, ":%d", instance_->websocket_port());
253     rv += std::string(buffer);
254   }
255   rv += "/";
256   rv += url;
257   return rv;
258 }
259 
CreateVarString(const std::string & string)260 PP_Var TestWebSocket::CreateVarString(const std::string& string) {
261   return var_interface_->VarFromUtf8(string.c_str(),
262                                      static_cast<uint32_t>(string.size()));
263 }
264 
CreateVarBinary(const std::vector<uint8_t> & binary)265 PP_Var TestWebSocket::CreateVarBinary(const std::vector<uint8_t>& binary) {
266   PP_Var var =
267       arraybuffer_interface_->Create(static_cast<uint32_t>(binary.size()));
268   uint8_t* var_data = static_cast<uint8_t*>(arraybuffer_interface_->Map(var));
269   std::copy(binary.begin(), binary.end(), var_data);
270   return var;
271 }
272 
ReleaseVar(const PP_Var & var)273 void TestWebSocket::ReleaseVar(const PP_Var& var) {
274   var_interface_->Release(var);
275 }
276 
AreEqualWithString(const PP_Var & var,const std::string & string)277 bool TestWebSocket::AreEqualWithString(const PP_Var& var,
278                                        const std::string& string) {
279   if (var.type != PP_VARTYPE_STRING)
280     return false;
281   uint32_t utf8_length;
282   const char* utf8 = var_interface_->VarToUtf8(var, &utf8_length);
283   if (utf8_length != string.size())
284     return false;
285   if (string.compare(utf8))
286     return false;
287   return true;
288 }
289 
AreEqualWithBinary(const PP_Var & var,const std::vector<uint8_t> & binary)290 bool TestWebSocket::AreEqualWithBinary(const PP_Var& var,
291                                        const std::vector<uint8_t>& binary) {
292   uint32_t buffer_size = 0;
293   PP_Bool success = arraybuffer_interface_->ByteLength(var, &buffer_size);
294   if (!success || buffer_size != binary.size())
295     return false;
296   if (!std::equal(binary.begin(), binary.end(),
297       static_cast<uint8_t*>(arraybuffer_interface_->Map(var))))
298     return false;
299   return true;
300 }
301 
Connect(const std::string & url,int32_t * result,const std::string & protocol)302 PP_Resource TestWebSocket::Connect(const std::string& url,
303                                    int32_t* result,
304                                    const std::string& protocol) {
305   PP_Var protocols[] = { PP_MakeUndefined() };
306   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
307   if (!ws)
308     return 0;
309   PP_Var url_var = CreateVarString(url);
310   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
311   uint32_t protocol_count = 0U;
312   if (protocol.size()) {
313     protocols[0] = CreateVarString(protocol);
314     protocol_count = 1U;
315   }
316   callback.WaitForResult(websocket_interface_->Connect(
317       ws, url_var, protocols, protocol_count,
318       callback.GetCallback().pp_completion_callback()));
319   ReleaseVar(url_var);
320   if (protocol.size())
321     ReleaseVar(protocols[0]);
322   *result = callback.result();
323   return ws;
324 }
325 
Send(int32_t,PP_Resource ws,const std::string & message)326 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws,
327                          const std::string& message) {
328   PP_Var message_var = CreateVarString(message);
329   websocket_interface_->SendMessage(ws, message_var);
330   ReleaseVar(message_var);
331 }
332 
TestIsWebSocket()333 std::string TestWebSocket::TestIsWebSocket() {
334   // Test that a NULL resource isn't a websocket.
335   pp::Resource null_resource;
336   PP_Bool result =
337       websocket_interface_->IsWebSocket(null_resource.pp_resource());
338   ASSERT_FALSE(result);
339 
340   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
341   ASSERT_TRUE(ws);
342 
343   result = websocket_interface_->IsWebSocket(ws);
344   ASSERT_TRUE(result);
345 
346   core_interface_->ReleaseResource(ws);
347 
348   PASS();
349 }
350 
TestUninitializedPropertiesAccess()351 std::string TestWebSocket::TestUninitializedPropertiesAccess() {
352   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
353   ASSERT_TRUE(ws);
354 
355   uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws);
356   ASSERT_EQ(0U, bufferedAmount);
357 
358   uint16_t close_code = websocket_interface_->GetCloseCode(ws);
359   ASSERT_EQ(0U, close_code);
360 
361   PP_Var close_reason = websocket_interface_->GetCloseReason(ws);
362   ASSERT_TRUE(AreEqualWithString(close_reason, std::string()));
363   ReleaseVar(close_reason);
364 
365   PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws);
366   ASSERT_EQ(PP_FALSE, close_was_clean);
367 
368   PP_Var extensions = websocket_interface_->GetExtensions(ws);
369   ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
370   ReleaseVar(extensions);
371 
372   PP_Var protocol = websocket_interface_->GetProtocol(ws);
373   ASSERT_TRUE(AreEqualWithString(protocol, std::string()));
374   ReleaseVar(protocol);
375 
376   PP_WebSocketReadyState ready_state =
377       websocket_interface_->GetReadyState(ws);
378   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state);
379 
380   PP_Var url = websocket_interface_->GetURL(ws);
381   ASSERT_TRUE(AreEqualWithString(url, std::string()));
382   ReleaseVar(url);
383 
384   core_interface_->ReleaseResource(ws);
385 
386   PASS();
387 }
388 
TestInvalidConnect()389 std::string TestWebSocket::TestInvalidConnect() {
390   PP_Var protocols[] = { PP_MakeUndefined() };
391 
392   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
393   ASSERT_TRUE(ws);
394 
395   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
396   callback.WaitForResult(websocket_interface_->Connect(
397       ws, PP_MakeUndefined(), protocols, 1U,
398       callback.GetCallback().pp_completion_callback()));
399   ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
400 
401   callback.WaitForResult(websocket_interface_->Connect(
402       ws, PP_MakeUndefined(), protocols, 1U,
403       callback.GetCallback().pp_completion_callback()));
404   ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result());
405 
406   core_interface_->ReleaseResource(ws);
407 
408   for (int i = 0; kInvalidURLs[i]; ++i) {
409     int32_t result;
410     ws = Connect(kInvalidURLs[i], &result, std::string());
411     ASSERT_TRUE(ws);
412     ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
413 
414     core_interface_->ReleaseResource(ws);
415   }
416 
417   PASS();
418 }
419 
TestProtocols()420 std::string TestWebSocket::TestProtocols() {
421   PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
422   PP_Var bad_protocols[] = {
423     CreateVarString("x-test"),
424     CreateVarString("x-test")
425   };
426   PP_Var good_protocols[] = {
427     CreateVarString("x-test"),
428     CreateVarString("x-yatest")
429   };
430 
431   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
432   ASSERT_TRUE(ws);
433   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
434   callback.WaitForResult(websocket_interface_->Connect(
435       ws, url, bad_protocols, 2U,
436       callback.GetCallback().pp_completion_callback()));
437   ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
438   core_interface_->ReleaseResource(ws);
439 
440   ws = websocket_interface_->Create(instance_->pp_instance());
441   ASSERT_TRUE(ws);
442   int32_t result = websocket_interface_->Connect(
443       ws, url, good_protocols, 2U, PP_BlockUntilComplete());
444   ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result);
445   core_interface_->ReleaseResource(ws);
446 
447   ReleaseVar(url);
448   for (int i = 0; i < 2; ++i) {
449     ReleaseVar(bad_protocols[i]);
450     ReleaseVar(good_protocols[i]);
451   }
452   core_interface_->ReleaseResource(ws);
453 
454   PASS();
455 }
456 
TestGetURL()457 std::string TestWebSocket::TestGetURL() {
458   for (int i = 0; kInvalidURLs[i]; ++i) {
459     int32_t result;
460     PP_Resource ws = Connect(kInvalidURLs[i], &result, std::string());
461     ASSERT_TRUE(ws);
462     PP_Var url = websocket_interface_->GetURL(ws);
463     ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i]));
464     ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
465 
466     ReleaseVar(url);
467     core_interface_->ReleaseResource(ws);
468   }
469 
470   PASS();
471 }
472 
TestValidConnect()473 std::string TestWebSocket::TestValidConnect() {
474   int32_t result;
475   PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
476   ASSERT_TRUE(ws);
477   ASSERT_EQ(PP_OK, result);
478   PP_Var extensions = websocket_interface_->GetExtensions(ws);
479   ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
480   core_interface_->ReleaseResource(ws);
481   ReleaseVar(extensions);
482 
483   PASS();
484 }
485 
TestInvalidClose()486 std::string TestWebSocket::TestInvalidClose() {
487   PP_Var reason = CreateVarString("close for test");
488   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
489   TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED);
490 
491   // Close before connect.
492   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
493   callback.WaitForResult(websocket_interface_->Close(
494       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
495       callback.GetCallback().pp_completion_callback()));
496   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
497   core_interface_->ReleaseResource(ws);
498 
499   // Close with bad arguments.
500   int32_t result;
501   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
502   ASSERT_TRUE(ws);
503   ASSERT_EQ(PP_OK, result);
504   callback.WaitForResult(websocket_interface_->Close(
505       ws, 1U, reason, callback.GetCallback().pp_completion_callback()));
506   ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
507   core_interface_->ReleaseResource(ws);
508 
509   // Close with PP_VARTYPE_NULL.
510   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
511   ASSERT_TRUE(ws);
512   ASSERT_EQ(PP_OK, result);
513   callback.WaitForResult(websocket_interface_->Close(
514       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
515       callback.GetCallback().pp_completion_callback()));
516   ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
517   core_interface_->ReleaseResource(ws);
518 
519   // Close with PP_VARTYPE_NULL and ongoing receive message.
520   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
521   ASSERT_TRUE(ws);
522   ASSERT_EQ(PP_OK, result);
523   PP_Var receive_message_var;
524   result = websocket_interface_->ReceiveMessage(
525       ws, &receive_message_var,
526       async_callback.GetCallback().pp_completion_callback());
527   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
528   callback.WaitForResult(websocket_interface_->Close(
529       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
530       callback.GetCallback().pp_completion_callback()));
531   ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
532   const char* send_message = "hi";
533   PP_Var send_message_var = CreateVarString(send_message);
534   result = websocket_interface_->SendMessage(ws, send_message_var);
535   ReleaseVar(send_message_var);
536   ASSERT_EQ(PP_OK, result);
537   async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
538   ASSERT_EQ(PP_OK, async_callback.result());
539   ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message));
540   ReleaseVar(receive_message_var);
541   core_interface_->ReleaseResource(ws);
542 
543   // Close twice.
544   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
545   ASSERT_TRUE(ws);
546   ASSERT_EQ(PP_OK, result);
547   result = websocket_interface_->Close(
548       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
549       async_callback.GetCallback().pp_completion_callback());
550   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
551   // Call another Close() before previous one is in progress.
552   result = websocket_interface_->Close(
553       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
554       callback.GetCallback().pp_completion_callback());
555   ASSERT_EQ(PP_ERROR_INPROGRESS, result);
556   async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
557   ASSERT_EQ(PP_OK, async_callback.result());
558   // Call another Close() after previous one is completed.
559   // This Close() must do nothing and reports no error.
560   callback.WaitForResult(websocket_interface_->Close(
561       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
562       callback.GetCallback().pp_completion_callback()));
563   ASSERT_EQ(PP_OK, callback.result());
564   core_interface_->ReleaseResource(ws);
565 
566   ReleaseVar(reason);
567 
568   PASS();
569 }
570 
571 // TODO(tyoshino): Consider splitting this test into smaller ones.
572 // http://crbug.com/397035
TestValidClose()573 std::string TestWebSocket::TestValidClose() {
574   PP_Var reason = CreateVarString("close for test");
575   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
576   TestCompletionCallback another_callback(
577       instance_->pp_instance(), callback_type());
578 
579   // Close.
580   int32_t result;
581   PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
582   ASSERT_TRUE(ws);
583   ASSERT_EQ(PP_OK, result);
584   callback.WaitForResult(websocket_interface_->Close(
585       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
586       callback.GetCallback().pp_completion_callback()));
587   CHECK_CALLBACK_BEHAVIOR(callback);
588   ASSERT_EQ(PP_OK, callback.result());
589   core_interface_->ReleaseResource(ws);
590 
591   // Close without code and reason.
592   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
593   ASSERT_TRUE(ws);
594   ASSERT_EQ(PP_OK, result);
595   callback.WaitForResult(websocket_interface_->Close(
596       ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason,
597       callback.GetCallback().pp_completion_callback()));
598   CHECK_CALLBACK_BEHAVIOR(callback);
599   ASSERT_EQ(PP_OK, callback.result());
600   core_interface_->ReleaseResource(ws);
601 
602   // Close with PP_VARTYPE_UNDEFINED.
603   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
604   ASSERT_TRUE(ws);
605   ASSERT_EQ(PP_OK, result);
606   callback.WaitForResult(websocket_interface_->Close(
607       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
608       callback.GetCallback().pp_completion_callback()));
609   CHECK_CALLBACK_BEHAVIOR(callback);
610   ASSERT_EQ(PP_OK, callback.result());
611   core_interface_->ReleaseResource(ws);
612 
613   // Close in CONNECTING state.
614   // The ongoing Connect() fails with PP_ERROR_ABORTED, then the Close()
615   // completes successfully.
616   ws = websocket_interface_->Create(instance_->pp_instance());
617   PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
618   PP_Var protocols[] = { PP_MakeUndefined() };
619   result = websocket_interface_->Connect(
620       ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback());
621   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
622   result = websocket_interface_->Close(
623       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
624       another_callback.GetCallback().pp_completion_callback());
625   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
626   callback.WaitForResult(PP_OK_COMPLETIONPENDING);
627   ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
628   another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
629   ASSERT_EQ(PP_OK, another_callback.result());
630   core_interface_->ReleaseResource(ws);
631   ReleaseVar(url);
632 
633   // Close while already closing.
634   // The first Close will succeed, and the second one will synchronously fail
635   // with PP_ERROR_INPROGRESS.
636   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
637   ASSERT_TRUE(ws);
638   ASSERT_EQ(PP_OK, result);
639   result = websocket_interface_->Close(
640       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
641       callback.GetCallback().pp_completion_callback());
642   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
643   result = websocket_interface_->Close(
644       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
645       another_callback.GetCallback().pp_completion_callback());
646   ASSERT_EQ(PP_ERROR_INPROGRESS, result);
647   callback.WaitForResult(PP_OK_COMPLETIONPENDING);
648   ASSERT_EQ(PP_OK, callback.result());
649   core_interface_->ReleaseResource(ws);
650 
651   // Close with ongoing ReceiveMessage.
652   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
653   ASSERT_TRUE(ws);
654   ASSERT_EQ(PP_OK, result);
655   PP_Var receive_message_var;
656   result = websocket_interface_->ReceiveMessage(
657       ws, &receive_message_var,
658       callback.GetCallback().pp_completion_callback());
659   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
660   result = websocket_interface_->Close(
661       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
662       another_callback.GetCallback().pp_completion_callback());
663   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
664   callback.WaitForResult(PP_OK_COMPLETIONPENDING);
665   ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
666   another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
667   ASSERT_EQ(PP_OK, another_callback.result());
668   core_interface_->ReleaseResource(ws);
669 
670   // Close with PP_VARTYPE_UNDEFINED for reason and ongoing ReceiveMessage.
671   ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
672   ASSERT_TRUE(ws);
673   ASSERT_EQ(PP_OK, result);
674   result = websocket_interface_->ReceiveMessage(
675       ws, &receive_message_var,
676       callback.GetCallback().pp_completion_callback());
677   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
678   result = websocket_interface_->Close(
679       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
680       another_callback.GetCallback().pp_completion_callback());
681   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
682   callback.WaitForResult(PP_OK_COMPLETIONPENDING);
683   ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
684   another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
685   ASSERT_EQ(PP_OK, another_callback.result());
686   core_interface_->ReleaseResource(ws);
687 
688   // Server initiated closing handshake.
689   ws = Connect(
690       GetFullURL(kCloseWithCodeAndReasonServerURL), &result, std::string());
691   ASSERT_TRUE(ws);
692   ASSERT_EQ(PP_OK, result);
693   // Text messsage "1000 bye" requests the server to initiate closing handshake
694   // with code being 1000 and reason being "bye".
695   PP_Var close_request_var = CreateVarString("1000 bye");
696   result = websocket_interface_->SendMessage(ws, close_request_var);
697   ReleaseVar(close_request_var);
698   callback.WaitForResult(websocket_interface_->ReceiveMessage(
699       ws, &receive_message_var,
700       callback.GetCallback().pp_completion_callback()));
701   ASSERT_EQ(PP_ERROR_FAILED, callback.result());
702   core_interface_->ReleaseResource(ws);
703 
704   ReleaseVar(reason);
705 
706   PASS();
707 }
708 
TestGetProtocol()709 std::string TestWebSocket::TestGetProtocol() {
710   const char* expected_protocols[] = {
711     "x-chat",
712     "hoehoe",
713     NULL
714   };
715   for (int i = 0; expected_protocols[i]; ++i) {
716     std::string url(GetFullURL(kProtocolTestServerURL));
717     url += expected_protocols[i];
718     int32_t result;
719     PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]);
720     ASSERT_TRUE(ws);
721     ASSERT_EQ(PP_OK, result);
722 
723     PP_Var protocol = websocket_interface_->GetProtocol(ws);
724     ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i]));
725 
726     ReleaseVar(protocol);
727     core_interface_->ReleaseResource(ws);
728   }
729 
730   PASS();
731 }
732 
TestTextSendReceive()733 std::string TestWebSocket::TestTextSendReceive() {
734   // Connect to test echo server.
735   int32_t connect_result;
736   PP_Resource ws =
737       Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
738   ASSERT_TRUE(ws);
739   ASSERT_EQ(PP_OK, connect_result);
740 
741   // Send 'hello pepper' text message.
742   const char* message = "hello pepper";
743   PP_Var message_var = CreateVarString(message);
744   int32_t result = websocket_interface_->SendMessage(ws, message_var);
745   ReleaseVar(message_var);
746   ASSERT_EQ(PP_OK, result);
747 
748   // Receive echoed 'hello pepper'.
749   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
750   PP_Var received_message;
751   callback.WaitForResult(websocket_interface_->ReceiveMessage(
752       ws, &received_message, callback.GetCallback().pp_completion_callback()));
753   ASSERT_EQ(PP_OK, callback.result());
754   ASSERT_TRUE(AreEqualWithString(received_message, message));
755   ReleaseVar(received_message);
756   core_interface_->ReleaseResource(ws);
757 
758   PASS();
759 }
760 
761 // Run as a BACKGROUND test.
TestTextSendReceiveTwice()762 std::string TestWebSocket::TestTextSendReceiveTwice() {
763   // Connect to test echo server.
764   int32_t connect_result;
765   PP_Resource ws =
766       Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
767   ASSERT_TRUE(ws);
768   ASSERT_EQ(PP_OK, connect_result);
769   pp::MessageLoop message_loop = pp::MessageLoop::GetCurrent();
770   pp::CompletionCallbackFactory<TestWebSocket> factory(this);
771 
772   message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send,
773                                             ws, std::string("hello")));
774   // When the server receives 'Goodbye', it closes the session.
775   message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send,
776                                             ws, std::string("Goodbye")));
777   message_loop.PostQuit(false);
778   message_loop.Run();
779 
780   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
781   PP_Var received_message;
782   int32_t result = websocket_interface_->ReceiveMessage(
783       ws, &received_message, callback.GetCallback().pp_completion_callback());
784   ASSERT_EQ(PP_OK, result);
785   // Since we don't run the message loop, the callback will stay
786   // "pending and scheduled to run" state.
787 
788   // Waiting for the connection close which will be done by the server.
789   while (true) {
790     PP_WebSocketReadyState ready_state =
791         websocket_interface_->GetReadyState(ws);
792     if (ready_state != PP_WEBSOCKETREADYSTATE_CONNECTING &&
793         ready_state != PP_WEBSOCKETREADYSTATE_OPEN) {
794       break;
795     }
796     PlatformSleep(100);  // 100ms
797   }
798 
799   // Cleanup the message loop
800   message_loop.PostQuit(false);
801   message_loop.Run();
802 
803   ASSERT_EQ(PP_OK, callback.result());
804   ASSERT_TRUE(AreEqualWithString(received_message, "hello"));
805   ReleaseVar(received_message);
806   core_interface_->ReleaseResource(ws);
807   PASS();
808 }
809 
TestBinarySendReceive()810 std::string TestWebSocket::TestBinarySendReceive() {
811   // Connect to test echo server.
812   int32_t connect_result;
813   PP_Resource ws =
814       Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
815   ASSERT_TRUE(ws);
816   ASSERT_EQ(PP_OK, connect_result);
817 
818   // Send binary message.
819   std::vector<uint8_t> binary(256);
820   for (uint32_t i = 0; i < binary.size(); ++i)
821     binary[i] = i;
822   PP_Var message_var = CreateVarBinary(binary);
823   int32_t result = websocket_interface_->SendMessage(ws, message_var);
824   ReleaseVar(message_var);
825   ASSERT_EQ(PP_OK, result);
826 
827   // Receive echoed binary.
828   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
829   PP_Var received_message;
830   callback.WaitForResult(websocket_interface_->ReceiveMessage(
831       ws, &received_message, callback.GetCallback().pp_completion_callback()));
832   ASSERT_EQ(PP_OK, callback.result());
833   ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
834   ReleaseVar(received_message);
835   core_interface_->ReleaseResource(ws);
836 
837   PASS();
838 }
839 
TestStressedSendReceive()840 std::string TestWebSocket::TestStressedSendReceive() {
841   // Connect to test echo server.
842   int32_t connect_result;
843   PP_Resource ws =
844       Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
845   ASSERT_TRUE(ws);
846   ASSERT_EQ(PP_OK, connect_result);
847 
848   // Prepare PP_Var objects to send.
849   const char* text = "hello pepper";
850   PP_Var text_var = CreateVarString(text);
851   std::vector<uint8_t> binary(256);
852   for (uint32_t i = 0; i < binary.size(); ++i)
853     binary[i] = i;
854   PP_Var binary_var = CreateVarBinary(binary);
855   // Prepare very large binary data over 64KiB. Object serializer in
856   // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
857   // to SRPC. In case received data over 64KiB exists, a specific code handles
858   // this large data via asynchronous callback from main thread. This data
859   // intends to test the code.
860   std::vector<uint8_t> large_binary(65 * 1024);
861   for (uint32_t i = 0; i < large_binary.size(); ++i)
862     large_binary[i] = i & 0xff;
863   PP_Var large_binary_var = CreateVarBinary(large_binary);
864 
865   // Send many messages.
866   int32_t result;
867   for (int i = 0; i < 256; ++i) {
868     result = websocket_interface_->SendMessage(ws, text_var);
869     ASSERT_EQ(PP_OK, result);
870     result = websocket_interface_->SendMessage(ws, binary_var);
871     ASSERT_EQ(PP_OK, result);
872   }
873   result = websocket_interface_->SendMessage(ws, large_binary_var);
874   ASSERT_EQ(PP_OK, result);
875   ReleaseVar(text_var);
876   ReleaseVar(binary_var);
877   ReleaseVar(large_binary_var);
878 
879   // Receive echoed data.
880   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
881   for (int i = 0; i <= 512; ++i) {
882     PP_Var received_message;
883     callback.WaitForResult(websocket_interface_->ReceiveMessage(
884         ws, &received_message,
885         callback.GetCallback().pp_completion_callback()));
886     ASSERT_EQ(PP_OK, callback.result());
887     if (i == 512) {
888       ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary));
889     } else if (i & 1) {
890       ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
891     } else {
892       ASSERT_TRUE(AreEqualWithString(received_message, text));
893     }
894     ReleaseVar(received_message);
895   }
896   core_interface_->ReleaseResource(ws);
897 
898   PASS();
899 }
900 
TestBufferedAmount()901 std::string TestWebSocket::TestBufferedAmount() {
902   // Connect to test echo server.
903   int32_t connect_result;
904   PP_Resource ws =
905       Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
906   ASSERT_TRUE(ws);
907   ASSERT_EQ(PP_OK, connect_result);
908 
909   // Prepare a large message that is not aligned with the internal buffer
910   // sizes.
911   std::string message(8193, 'x');
912   PP_Var message_var = CreateVarString(message);
913 
914   uint64_t buffered_amount = 0;
915   int32_t result;
916   for (int i = 0; i < 100; i++) {
917     result = websocket_interface_->SendMessage(ws, message_var);
918     ASSERT_EQ(PP_OK, result);
919     buffered_amount = websocket_interface_->GetBufferedAmount(ws);
920     // Buffered amount size 262144 is too big for the internal buffer size.
921     if (buffered_amount > 262144)
922       break;
923   }
924 
925   // Close connection.
926   std::string reason_str = "close while busy";
927   PP_Var reason = CreateVarString(reason_str.c_str());
928   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
929   result = websocket_interface_->Close(
930       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
931       callback.GetCallback().pp_completion_callback());
932   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
933   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING,
934       websocket_interface_->GetReadyState(ws));
935 
936   callback.WaitForResult(result);
937   ASSERT_EQ(PP_OK, callback.result());
938   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED,
939       websocket_interface_->GetReadyState(ws));
940 
941   uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws);
942 
943   // After connection closure, all sending requests fail and just increase
944   // the bufferedAmount property.
945   PP_Var empty_string = CreateVarString(std::string());
946   result = websocket_interface_->SendMessage(ws, empty_string);
947   ASSERT_EQ(PP_ERROR_FAILED, result);
948   buffered_amount = websocket_interface_->GetBufferedAmount(ws);
949   ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
950   base_buffered_amount = buffered_amount;
951 
952   result = websocket_interface_->SendMessage(ws, reason);
953   ASSERT_EQ(PP_ERROR_FAILED, result);
954   buffered_amount = websocket_interface_->GetBufferedAmount(ws);
955   uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length();
956   ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
957 
958   ReleaseVar(message_var);
959   ReleaseVar(reason);
960   ReleaseVar(empty_string);
961   core_interface_->ReleaseResource(ws);
962 
963   PASS();
964 }
965 
966 // Test abort behaviors where a WebSocket PP_Resource is released while each
967 // function is in-flight on the WebSocket PP_Resource.
TestAbortCallsWithCallback()968 std::string TestWebSocket::TestAbortCallsWithCallback() {
969   // Following tests make sure the behavior for functions which require a
970   // callback. The callback must get a PP_ERROR_ABORTED.
971 
972   // Test the behavior for Connect().
973   PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
974   ASSERT_TRUE(ws);
975   std::string url = GetFullURL(kEchoServerURL);
976   PP_Var url_var = CreateVarString(url);
977   TestCompletionCallback connect_callback(
978       instance_->pp_instance(), callback_type());
979   int32_t result = websocket_interface_->Connect(
980       ws, url_var, NULL, 0,
981       connect_callback.GetCallback().pp_completion_callback());
982   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
983   core_interface_->ReleaseResource(ws);
984   connect_callback.WaitForResult(result);
985   ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result());
986 
987   // Test the behavior for Close().
988   ws = Connect(url, &result, std::string());
989   ASSERT_TRUE(ws);
990   ASSERT_EQ(PP_OK, result);
991   PP_Var reason_var = CreateVarString("abort");
992   TestCompletionCallback close_callback(
993       instance_->pp_instance(), callback_type());
994   result = websocket_interface_->Close(
995       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var,
996       close_callback.GetCallback().pp_completion_callback());
997   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
998   core_interface_->ReleaseResource(ws);
999   close_callback.WaitForResult(result);
1000   ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
1001   ReleaseVar(reason_var);
1002 
1003   // Test the behavior for ReceiveMessage().
1004   // Make sure the simplest case to wait for data which never arrives, here.
1005   ws = Connect(url, &result, std::string());
1006   ASSERT_TRUE(ws);
1007   ASSERT_EQ(PP_OK, result);
1008   PP_Var receive_var;
1009   TestCompletionCallback receive_callback(
1010       instance_->pp_instance(), callback_type());
1011   result = websocket_interface_->ReceiveMessage(
1012       ws, &receive_var,
1013       receive_callback.GetCallback().pp_completion_callback());
1014   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1015   core_interface_->ReleaseResource(ws);
1016   receive_callback.WaitForResult(result);
1017   ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
1018 
1019   // Release the resource in the aborting receive completion callback which is
1020   // introduced by calling Close().
1021   ws = Connect(url, &result, std::string());
1022   ASSERT_TRUE(ws);
1023   ASSERT_EQ(PP_OK, result);
1024   result = websocket_interface_->ReceiveMessage(
1025       ws, &receive_var,
1026       receive_callback.GetCallback().pp_completion_callback());
1027   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1028   ReleaseResourceDelegate receive_delegate(core_interface_, ws);
1029   receive_callback.SetDelegate(&receive_delegate);
1030   result = websocket_interface_->Close(
1031       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
1032       close_callback.GetCallback().pp_completion_callback());
1033   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1034   receive_callback.WaitForResult(result);
1035   CHECK_CALLBACK_BEHAVIOR(receive_callback);
1036   ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
1037   close_callback.WaitForResult(result);
1038   CHECK_CALLBACK_BEHAVIOR(close_callback);
1039   ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
1040 
1041   ReleaseVar(url_var);
1042 
1043   PASS();
1044 }
1045 
TestAbortSendMessageCall()1046 std::string TestWebSocket::TestAbortSendMessageCall() {
1047   // Test the behavior for SendMessage().
1048   // This function doesn't require a callback, but operation will be done
1049   // asynchronously in WebKit and browser process.
1050   std::vector<uint8_t> large_binary(65 * 1024);
1051   PP_Var large_var = CreateVarBinary(large_binary);
1052 
1053   int32_t result;
1054   std::string url = GetFullURL(kEchoServerURL);
1055   PP_Resource ws = Connect(url, &result, std::string());
1056   ASSERT_TRUE(ws);
1057   ASSERT_EQ(PP_OK, result);
1058   result = websocket_interface_->SendMessage(ws, large_var);
1059   ASSERT_EQ(PP_OK, result);
1060   core_interface_->ReleaseResource(ws);
1061   ReleaseVar(large_var);
1062 
1063   PASS();
1064 }
1065 
TestAbortCloseCall()1066 std::string TestWebSocket::TestAbortCloseCall() {
1067   // Release the resource in the close completion callback.
1068   int32_t result;
1069   std::string url = GetFullURL(kEchoServerURL);
1070   PP_Resource ws = Connect(url, &result, std::string());
1071   ASSERT_TRUE(ws);
1072   ASSERT_EQ(PP_OK, result);
1073   TestCompletionCallback close_callback(
1074       instance_->pp_instance(), callback_type());
1075   result = websocket_interface_->Close(
1076       ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
1077       close_callback.GetCallback().pp_completion_callback());
1078   ReleaseResourceDelegate close_delegate(core_interface_, ws);
1079   close_callback.SetDelegate(&close_delegate);
1080   close_callback.WaitForResult(result);
1081   CHECK_CALLBACK_BEHAVIOR(close_callback);
1082   ASSERT_EQ(PP_OK, close_callback.result());
1083 
1084   PASS();
1085 }
1086 
TestAbortReceiveMessageCall()1087 std::string TestWebSocket::TestAbortReceiveMessageCall() {
1088   // Test the behavior where receive process might be in-flight.
1089   std::vector<uint8_t> large_binary(65 * 1024);
1090   PP_Var large_var = CreateVarBinary(large_binary);
1091   const char* text = "yukarin";
1092   PP_Var text_var = CreateVarString(text);
1093 
1094   std::string url = GetFullURL(kEchoServerURL);
1095   int32_t result;
1096   PP_Resource ws;
1097 
1098   // Each trial sends |trial_count| + 1 messages and receives just |trial|
1099   // number of message(s) before releasing the WebSocket. The WebSocket is
1100   // released while the next message is going to be received.
1101   const int trial_count = 8;
1102   for (int trial = 1; trial <= trial_count; trial++) {
1103     ws = Connect(url, &result, std::string());
1104     ASSERT_TRUE(ws);
1105     ASSERT_EQ(PP_OK, result);
1106     for (int i = 0; i <= trial_count; ++i) {
1107       result = websocket_interface_->SendMessage(ws, text_var);
1108       ASSERT_EQ(PP_OK, result);
1109     }
1110     TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1111     PP_Var var;
1112     for (int i = 0; i < trial; ++i) {
1113       callback.WaitForResult(websocket_interface_->ReceiveMessage(
1114           ws, &var, callback.GetCallback().pp_completion_callback()));
1115       ASSERT_EQ(PP_OK, callback.result());
1116       ASSERT_TRUE(AreEqualWithString(var, text));
1117       ReleaseVar(var);
1118     }
1119     result = websocket_interface_->ReceiveMessage(
1120         ws, &var, callback.GetCallback().pp_completion_callback());
1121     core_interface_->ReleaseResource(ws);
1122     if (result != PP_OK) {
1123       callback.WaitForResult(result);
1124       ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1125     }
1126   }
1127   // Same test, but the last receiving message is large message over 64KiB.
1128   for (int trial = 1; trial <= trial_count; trial++) {
1129     ws = Connect(url, &result, std::string());
1130     ASSERT_TRUE(ws);
1131     ASSERT_EQ(PP_OK, result);
1132     for (int i = 0; i <= trial_count; ++i) {
1133       if (i == trial)
1134         result = websocket_interface_->SendMessage(ws, large_var);
1135       else
1136         result = websocket_interface_->SendMessage(ws, text_var);
1137       ASSERT_EQ(PP_OK, result);
1138     }
1139     TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1140     PP_Var var;
1141     for (int i = 0; i < trial; ++i) {
1142       callback.WaitForResult(websocket_interface_->ReceiveMessage(
1143           ws, &var, callback.GetCallback().pp_completion_callback()));
1144       ASSERT_EQ(PP_OK, callback.result());
1145       ASSERT_TRUE(AreEqualWithString(var, text));
1146       ReleaseVar(var);
1147     }
1148     result = websocket_interface_->ReceiveMessage(
1149         ws, &var, callback.GetCallback().pp_completion_callback());
1150     core_interface_->ReleaseResource(ws);
1151     if (result != PP_OK) {
1152       callback.WaitForResult(result);
1153       ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1154     }
1155   }
1156 
1157   ReleaseVar(large_var);
1158   ReleaseVar(text_var);
1159 
1160   PASS();
1161 }
1162 
TestClosedFromServerWhileSending()1163 std::string TestWebSocket::TestClosedFromServerWhileSending() {
1164   // Connect to test echo server.
1165   const pp::Var protocols[] = { pp::Var() };
1166   TestWebSocketAPI websocket(instance_);
1167   int32_t result =
1168       websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1169   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1170   websocket.WaitForConnected();
1171 
1172   result = websocket.Send(pp::Var("hello"));
1173   ASSERT_EQ(PP_OK, result);
1174   result = websocket.Send(pp::Var("Goodbye"));
1175   // We send many messages so that PepperWebSocketHost::SendText is called
1176   // after PepperWebSocketHost::didClose is called.
1177   // Note: We must not wait for CLOSED event here because
1178   // WebSocketResource::SendMessage doesn't call PepperWebSocketHost::SendText
1179   // when its internal state is CLOSING or CLOSED. We want to test if the
1180   // pepper WebSocket works well when WebSocketResource is OPEN and
1181   // PepperWebSocketHost is CLOSED.
1182   for (size_t i = 0; i < 10000; ++i) {
1183     result = websocket.Send(pp::Var(""));
1184     ASSERT_EQ(PP_OK, result);
1185   }
1186 
1187   PASS();
1188 }
1189 
TestCcInterfaces()1190 std::string TestWebSocket::TestCcInterfaces() {
1191   // C++ bindings is simple straightforward, then just verifies interfaces work
1192   // as a interface bridge fine.
1193   pp::WebSocket ws(instance_);
1194 
1195   // Check uninitialized properties access.
1196   ASSERT_EQ(0, ws.GetBufferedAmount());
1197   ASSERT_EQ(0, ws.GetCloseCode());
1198   ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), std::string()));
1199   ASSERT_FALSE(ws.GetCloseWasClean());
1200   ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), std::string()));
1201   ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1202   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState());
1203   ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), std::string()));
1204 
1205   // Check communication interfaces (connect, send, receive, and close).
1206   TestCompletionCallback connect_callback(
1207       instance_->pp_instance(), callback_type());
1208   connect_callback.WaitForResult(ws.Connect(
1209       pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U,
1210               connect_callback.GetCallback()));
1211   CHECK_CALLBACK_BEHAVIOR(connect_callback);
1212   ASSERT_EQ(PP_OK, connect_callback.result());
1213 
1214   std::string text_message("hello C++");
1215   int32_t result = ws.SendMessage(pp::Var(text_message));
1216   ASSERT_EQ(PP_OK, result);
1217 
1218   std::vector<uint8_t> binary(256);
1219   for (uint32_t i = 0; i < binary.size(); ++i)
1220     binary[i] = i;
1221   result = ws.SendMessage(
1222       pp::Var(pp::PASS_REF, CreateVarBinary(binary)));
1223   ASSERT_EQ(PP_OK, result);
1224 
1225   pp::Var text_receive_var;
1226   TestCompletionCallback text_receive_callback(
1227       instance_->pp_instance(), callback_type());
1228   text_receive_callback.WaitForResult(
1229       ws.ReceiveMessage(&text_receive_var,
1230                         text_receive_callback.GetCallback()));
1231   ASSERT_EQ(PP_OK, text_receive_callback.result());
1232   ASSERT_TRUE(
1233       AreEqualWithString(text_receive_var.pp_var(), text_message.c_str()));
1234 
1235   pp::Var binary_receive_var;
1236   TestCompletionCallback binary_receive_callback(
1237       instance_->pp_instance(), callback_type());
1238   binary_receive_callback.WaitForResult(
1239       ws.ReceiveMessage(&binary_receive_var,
1240                         binary_receive_callback.GetCallback()));
1241   ASSERT_EQ(PP_OK, binary_receive_callback.result());
1242   ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary));
1243 
1244   TestCompletionCallback close_callback(
1245       instance_->pp_instance(), callback_type());
1246   std::string reason("bye");
1247   close_callback.WaitForResult(ws.Close(
1248       PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason),
1249       close_callback.GetCallback()));
1250   CHECK_CALLBACK_BEHAVIOR(close_callback);
1251   ASSERT_EQ(PP_OK, close_callback.result());
1252 
1253   // Check initialized properties access.
1254   ASSERT_EQ(0, ws.GetBufferedAmount());
1255   ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode());
1256   ASSERT_TRUE(
1257       AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str()));
1258   ASSERT_EQ(true, ws.GetCloseWasClean());
1259   ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1260   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState());
1261   ASSERT_TRUE(AreEqualWithString(
1262       ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str()));
1263 
1264   PASS();
1265 }
1266 
TestUtilityInvalidConnect()1267 std::string TestWebSocket::TestUtilityInvalidConnect() {
1268   const pp::Var protocols[] = { pp::Var() };
1269 
1270   TestWebSocketAPI websocket(instance_);
1271   int32_t result = websocket.Connect(pp::Var(), protocols, 1U);
1272   ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1273   ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1274 
1275   result = websocket.Connect(pp::Var(), protocols, 1U);
1276   ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1277   ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1278 
1279   for (int i = 0; kInvalidURLs[i]; ++i) {
1280     TestWebSocketAPI ws(instance_);
1281     result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1282     if (result == PP_OK_COMPLETIONPENDING) {
1283       ws.WaitForClosed();
1284       const std::vector<WebSocketEvent>& events = ws.GetSeenEvents();
1285       ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1286       ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1287       ASSERT_EQ(2U, ws.GetSeenEvents().size());
1288     } else {
1289       ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1290       ASSERT_EQ(0U, ws.GetSeenEvents().size());
1291     }
1292   }
1293 
1294   PASS();
1295 }
1296 
TestUtilityProtocols()1297 std::string TestWebSocket::TestUtilityProtocols() {
1298   const pp::Var bad_protocols[] = {
1299       pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1300   const pp::Var good_protocols[] = {
1301       pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1302 
1303   {
1304     TestWebSocketAPI websocket(instance_);
1305     int32_t result = websocket.Connect(
1306         pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U);
1307     ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1308     ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1309   }
1310 
1311   {
1312     TestWebSocketAPI websocket(instance_);
1313     int32_t result = websocket.Connect(
1314         pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U);
1315     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1316     websocket.WaitForConnected();
1317     const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1318     // Protocol arguments are valid, but this test run without a WebSocket
1319     // server. As a result, OnError() and OnClose() are invoked because of
1320     // a connection establishment failure.
1321     ASSERT_EQ(2U, events.size());
1322     ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1323     ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1324     ASSERT_FALSE(events[1].was_clean);
1325   }
1326 
1327   PASS();
1328 }
1329 
TestUtilityGetURL()1330 std::string TestWebSocket::TestUtilityGetURL() {
1331   const pp::Var protocols[] = { pp::Var() };
1332 
1333   for (int i = 0; kInvalidURLs[i]; ++i) {
1334     TestWebSocketAPI websocket(instance_);
1335     int32_t result = websocket.Connect(
1336         pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1337     if (result == PP_OK_COMPLETIONPENDING) {
1338       websocket.WaitForClosed();
1339       const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1340       ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1341       ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1342       ASSERT_EQ(2U, events.size());
1343     } else {
1344       ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1345       ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1346     }
1347     pp::Var url = websocket.GetURL();
1348     ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i]));
1349   }
1350 
1351   PASS();
1352 }
1353 
TestUtilityValidConnect()1354 std::string TestWebSocket::TestUtilityValidConnect() {
1355   const pp::Var protocols[] = { pp::Var() };
1356   TestWebSocketAPI websocket(instance_);
1357   int32_t result = websocket.Connect(
1358       pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1359   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1360   websocket.WaitForConnected();
1361   const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1362   ASSERT_EQ(1U, events.size());
1363   ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1364   ASSERT_TRUE(
1365       AreEqualWithString(websocket.GetExtensions().pp_var(), std::string()));
1366 
1367   PASS();
1368 }
1369 
TestUtilityInvalidClose()1370 std::string TestWebSocket::TestUtilityInvalidClose() {
1371   const pp::Var reason = pp::Var(std::string("close for test"));
1372 
1373   // Close before connect.
1374   {
1375     TestWebSocketAPI websocket(instance_);
1376     int32_t result = websocket.Close(
1377         PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason);
1378     ASSERT_EQ(PP_ERROR_FAILED, result);
1379     ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1380   }
1381 
1382   // Close with bad arguments.
1383   {
1384     TestWebSocketAPI websocket(instance_);
1385     int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)),
1386         NULL, 0);
1387     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1388     websocket.WaitForConnected();
1389     result = websocket.Close(1U, reason);
1390     ASSERT_EQ(PP_ERROR_NOACCESS, result);
1391     const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1392     ASSERT_EQ(1U, events.size());
1393     ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1394   }
1395 
1396   PASS();
1397 }
1398 
TestUtilityValidClose()1399 std::string TestWebSocket::TestUtilityValidClose() {
1400   std::string reason("close for test");
1401   pp::Var url = pp::Var(GetFullURL(kCloseServerURL));
1402 
1403   // Close.
1404   {
1405     TestWebSocketAPI websocket(instance_);
1406     int32_t result = websocket.Connect(url, NULL, 0U);
1407     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1408     websocket.WaitForConnected();
1409     result = websocket.Close(
1410         PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1411     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1412     websocket.WaitForClosed();
1413     const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1414     ASSERT_EQ(2U, events.size());
1415     ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1416     ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1417     ASSERT_TRUE(events[1].was_clean);
1418     ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code);
1419     ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str()));
1420   }
1421 
1422   // Close in connecting.
1423   // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1424   // successfully.
1425   {
1426     TestWebSocketAPI websocket(instance_);
1427     int32_t result = websocket.Connect(url, NULL, 0U);
1428     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1429     result = websocket.Close(
1430         PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1431     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1432     websocket.WaitForClosed();
1433     const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1434     ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1435     int index = 0;
1436     if (events.size() == 3)
1437       ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1438     ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1439     ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1440     ASSERT_FALSE(events[index].was_clean);
1441   }
1442 
1443   // Close in closing.
1444   // The first close will be done successfully, then the second one failed with
1445   // with PP_ERROR_INPROGRESS immediately.
1446   {
1447     TestWebSocketAPI websocket(instance_);
1448     int32_t result = websocket.Connect(url, NULL, 0U);
1449     result = websocket.Close(
1450         PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1451     ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1452     result = websocket.Close(
1453         PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1454     ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1455     websocket.WaitForClosed();
1456     const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1457     ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1458     int index = 0;
1459     if (events.size() == 3)
1460       ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1461     ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1462     ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1463     ASSERT_FALSE(events[index].was_clean);
1464   }
1465 
1466   PASS();
1467 }
1468 
TestUtilityGetProtocol()1469 std::string TestWebSocket::TestUtilityGetProtocol() {
1470   const std::string protocol("x-chat");
1471   const pp::Var protocols[] = { pp::Var(protocol) };
1472   std::string url(GetFullURL(kProtocolTestServerURL));
1473   url += protocol;
1474   TestWebSocketAPI websocket(instance_);
1475   int32_t result = websocket.Connect(pp::Var(url), protocols, 1U);
1476   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1477   websocket.WaitForReceived();
1478   ASSERT_TRUE(AreEqualWithString(
1479       websocket.GetProtocol().pp_var(), protocol.c_str()));
1480   const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1481   // The server to which this test connect returns the decided protocol as a
1482   // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1483   // after EVENT_OPEN event.
1484   ASSERT_EQ(2U, events.size());
1485   ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1486   ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1487   ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str()));
1488 
1489   PASS();
1490 }
1491 
TestUtilityTextSendReceive()1492 std::string TestWebSocket::TestUtilityTextSendReceive() {
1493   const pp::Var protocols[] = { pp::Var() };
1494   TestWebSocketAPI websocket(instance_);
1495   int32_t result =
1496       websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1497   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1498   websocket.WaitForConnected();
1499 
1500   // Send 'hello pepper'.
1501   std::string message1("hello pepper");
1502   result = websocket.Send(pp::Var(std::string(message1)));
1503   ASSERT_EQ(PP_OK, result);
1504 
1505   // Receive echoed 'hello pepper'.
1506   websocket.WaitForReceived();
1507 
1508   // Send 'goodbye pepper'.
1509   std::string message2("goodbye pepper");
1510   result = websocket.Send(pp::Var(std::string(message2)));
1511 
1512   // Receive echoed 'goodbye pepper'.
1513   websocket.WaitForReceived();
1514 
1515   const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1516   ASSERT_EQ(3U, events.size());
1517   ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1518   ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1519   ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str()));
1520   ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type);
1521   ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str()));
1522 
1523   PASS();
1524 }
1525 
TestUtilityBinarySendReceive()1526 std::string TestWebSocket::TestUtilityBinarySendReceive() {
1527   const pp::Var protocols[] = { pp::Var() };
1528   TestWebSocketAPI websocket(instance_);
1529   int32_t result =
1530       websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1531   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1532   websocket.WaitForConnected();
1533 
1534   // Send binary message.
1535   uint32_t len = 256;
1536   std::vector<uint8_t> binary(len);
1537   for (uint32_t i = 0; i < len; ++i)
1538     binary[i] = i;
1539   pp::VarArrayBuffer message(len);
1540   uint8_t* var_data = static_cast<uint8_t*>(message.Map());
1541   std::copy(binary.begin(), binary.end(), var_data);
1542   result = websocket.Send(message);
1543   ASSERT_EQ(PP_OK, result);
1544 
1545   // Receive echoed binary message.
1546   websocket.WaitForReceived();
1547 
1548   const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1549   ASSERT_EQ(2U, events.size());
1550   ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1551   ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1552   ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary));
1553 
1554   PASS();
1555 }
1556 
TestUtilityBufferedAmount()1557 std::string TestWebSocket::TestUtilityBufferedAmount() {
1558   // Connect to test echo server.
1559   const pp::Var protocols[] = { pp::Var() };
1560   TestWebSocketAPI websocket(instance_);
1561   int32_t result =
1562       websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1563   ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1564   websocket.WaitForConnected();
1565 
1566   // Prepare a large message that is not aligned with the internal buffer
1567   // sizes.
1568   std::string message(8193, 'x');
1569   uint64_t buffered_amount = 0;
1570   uint32_t sent;
1571   for (sent = 0; sent < 100; sent++) {
1572     result = websocket.Send(pp::Var(message));
1573     ASSERT_EQ(PP_OK, result);
1574     buffered_amount = websocket.GetBufferedAmount();
1575     // Buffered amount size 262144 is too big for the internal buffer size.
1576     if (buffered_amount > 262144)
1577       break;
1578   }
1579 
1580   // Close connection.
1581   std::string reason = "close while busy";
1582   result = websocket.Close(
1583       PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1584   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState());
1585   websocket.WaitForClosed();
1586   ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState());
1587 
1588   uint64_t base_buffered_amount = websocket.GetBufferedAmount();
1589   size_t events_on_closed = websocket.GetSeenEvents().size();
1590 
1591   // After connection closure, all sending requests fail and just increase
1592   // the bufferedAmount property.
1593   result = websocket.Send(pp::Var(std::string()));
1594   ASSERT_EQ(PP_ERROR_FAILED, result);
1595   buffered_amount = websocket.GetBufferedAmount();
1596   ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
1597   base_buffered_amount = buffered_amount;
1598 
1599   result = websocket.Send(pp::Var(reason));
1600   ASSERT_EQ(PP_ERROR_FAILED, result);
1601   buffered_amount = websocket.GetBufferedAmount();
1602   uint64_t reason_frame_size = kMessageFrameOverhead + reason.length();
1603   ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
1604 
1605   const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1606   ASSERT_EQ(events_on_closed, events.size());
1607   ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1608   size_t last_event = events_on_closed - 1;
1609   for (uint32_t i = 1; i < last_event; ++i) {
1610     ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type);
1611     ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message));
1612   }
1613   ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type);
1614   ASSERT_TRUE(events[last_event].was_clean);
1615 
1616   PASS();
1617 }
1618