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