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