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.
5 #include "ppapi/tests/test_websocket.h"
15 #include "ppapi/c/dev/ppb_testing_dev.h"
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/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"
34 // These servers are provided by pywebsocket server side handlers in
35 // LayoutTests/http/tests/websocket/tests/hybi/*_wsh.
36 // pywebsocket server itself is launched in ppapi_ui_test.cc.
37 const char kEchoServerURL
[] = "websocket/tests/hybi/echo-with-no-extension";
39 const char kCloseServerURL
[] = "websocket/tests/hybi/close";
41 const char kCloseWithCodeAndReasonServerURL
[] =
42 "websocket/tests/hybi/close-code-and-reason";
44 const char kProtocolTestServerURL
[] =
45 "websocket/tests/hybi/protocol-test?protocol=";
47 const char* const kInvalidURLs
[] = {
48 "http://www.google.com/invalid_scheme",
49 "ws://www.google.com/invalid#fragment",
50 "ws://www.google.com:65535/invalid_port",
54 // Internal packet sizes.
55 const uint64_t kCloseFrameSize
= 6;
56 const uint64_t kMessageFrameOverhead
= 6;
60 struct WebSocketEvent
{
68 WebSocketEvent(EventType type
,
74 close_code(close_code
),
83 class ReleaseResourceDelegate
: public TestCompletionCallback::Delegate
{
85 explicit ReleaseResourceDelegate(const PPB_Core
* core_interface
,
87 : core_interface_(core_interface
),
91 // TestCompletionCallback::Delegate implementation.
92 virtual void OnCallback(void* user_data
, int32_t result
) {
94 core_interface_
->ReleaseResource(resource_
);
98 const PPB_Core
* core_interface_
;
99 PP_Resource resource_
;
102 class TestWebSocketAPI
: public pp::WebSocketAPI
{
104 explicit TestWebSocketAPI(pp::Instance
* instance
)
105 : pp::WebSocketAPI(instance
),
109 wait_for_connected_(false),
110 wait_for_received_(false),
111 wait_for_closed_(false),
112 instance_(instance
->pp_instance()) {
115 virtual void WebSocketDidOpen() {
117 WebSocketEvent(WebSocketEvent::EVENT_OPEN
, true, 0U, pp::Var()));
119 if (wait_for_connected_
) {
120 GetTestingInterface()->QuitMessageLoop(instance_
);
121 wait_for_connected_
= false;
125 virtual void WebSocketDidClose(
126 bool was_clean
, uint16_t code
, const pp::Var
& reason
) {
128 WebSocketEvent(WebSocketEvent::EVENT_CLOSE
, was_clean
, code
, reason
));
131 if (wait_for_connected_
|| wait_for_closed_
) {
132 GetTestingInterface()->QuitMessageLoop(instance_
);
133 wait_for_connected_
= false;
134 wait_for_closed_
= false;
138 virtual void HandleWebSocketMessage(const pp::Var
&message
) {
140 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE
, true, 0U, message
));
142 if (wait_for_received_
) {
143 GetTestingInterface()->QuitMessageLoop(instance_
);
144 wait_for_received_
= false;
149 virtual void HandleWebSocketError() {
151 WebSocketEvent(WebSocketEvent::EVENT_ERROR
, true, 0U, pp::Var()));
154 void WaitForConnected() {
156 wait_for_connected_
= true;
157 GetTestingInterface()->RunMessageLoop(instance_
);
161 void WaitForReceived() {
163 wait_for_received_
= true;
164 GetTestingInterface()->RunMessageLoop(instance_
);
168 void WaitForClosed() {
170 wait_for_closed_
= true;
171 GetTestingInterface()->RunMessageLoop(instance_
);
175 const std::vector
<WebSocketEvent
>& GetSeenEvents() const {
180 std::vector
<WebSocketEvent
> events_
;
184 bool wait_for_connected_
;
185 bool wait_for_received_
;
186 bool wait_for_closed_
;
187 PP_Instance instance_
;
192 REGISTER_TEST_CASE(WebSocket
);
194 bool TestWebSocket::Init() {
195 websocket_interface_
= static_cast<const PPB_WebSocket
*>(
196 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE
));
197 var_interface_
= static_cast<const PPB_Var
*>(
198 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
199 arraybuffer_interface_
= static_cast<const PPB_VarArrayBuffer
*>(
200 pp::Module::Get()->GetBrowserInterface(
201 PPB_VAR_ARRAY_BUFFER_INTERFACE
));
202 core_interface_
= static_cast<const PPB_Core
*>(
203 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
204 if (!websocket_interface_
|| !var_interface_
|| !arraybuffer_interface_
||
208 return CheckTestingInterface();
211 void TestWebSocket::RunTests(const std::string
& filter
) {
212 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket
, filter
);
213 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess
, filter
);
214 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect
, filter
);
215 RUN_TEST_WITH_REFERENCE_CHECK(Protocols
, filter
);
216 RUN_TEST_WITH_REFERENCE_CHECK(GetURL
, filter
);
217 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect
, filter
);
218 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose
, filter
);
219 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose
, filter
);
220 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol
, filter
);
221 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive
, filter
);
222 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive
, filter
);
223 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive
, filter
);
224 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount
, filter
);
225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCalls
, filter
);
227 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces
, filter
);
229 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect
, filter
);
230 RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols
, filter
);
231 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL
, filter
);
232 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect
, filter
);
233 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose
, filter
);
234 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose
, filter
);
235 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol
, filter
);
236 RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive
, filter
);
237 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive
, filter
);
238 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount
, filter
);
241 std::string
TestWebSocket::GetFullURL(const char* url
) {
242 std::string rv
= "ws://localhost";
243 // Some WebSocket tests don't start the server so there'll be no port.
244 if (instance_
->websocket_port() != -1) {
246 sprintf(buffer
, ":%d", instance_
->websocket_port());
247 rv
+= std::string(buffer
);
254 PP_Var
TestWebSocket::CreateVarString(const std::string
& string
) {
255 return var_interface_
->VarFromUtf8(string
.c_str(), string
.size());
258 PP_Var
TestWebSocket::CreateVarBinary(const std::vector
<uint8_t>& binary
) {
259 PP_Var var
= arraybuffer_interface_
->Create(binary
.size());
260 uint8_t* var_data
= static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
));
261 std::copy(binary
.begin(), binary
.end(), var_data
);
265 void TestWebSocket::ReleaseVar(const PP_Var
& var
) {
266 var_interface_
->Release(var
);
269 bool TestWebSocket::AreEqualWithString(const PP_Var
& var
,
270 const std::string
& string
) {
271 if (var
.type
!= PP_VARTYPE_STRING
)
273 uint32_t utf8_length
;
274 const char* utf8
= var_interface_
->VarToUtf8(var
, &utf8_length
);
275 if (utf8_length
!= string
.size())
277 if (string
.compare(utf8
))
282 bool TestWebSocket::AreEqualWithBinary(const PP_Var
& var
,
283 const std::vector
<uint8_t>& binary
) {
284 uint32_t buffer_size
= 0;
285 PP_Bool success
= arraybuffer_interface_
->ByteLength(var
, &buffer_size
);
286 if (!success
|| buffer_size
!= binary
.size())
288 if (!std::equal(binary
.begin(), binary
.end(),
289 static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
))))
294 PP_Resource
TestWebSocket::Connect(const std::string
& url
,
296 const std::string
& protocol
) {
297 PP_Var protocols
[] = { PP_MakeUndefined() };
298 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
301 PP_Var url_var
= CreateVarString(url
);
302 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
303 uint32_t protocol_count
= 0U;
304 if (protocol
.size()) {
305 protocols
[0] = CreateVarString(protocol
);
308 callback
.WaitForResult(websocket_interface_
->Connect(
309 ws
, url_var
, protocols
, protocol_count
,
310 callback
.GetCallback().pp_completion_callback()));
313 ReleaseVar(protocols
[0]);
314 *result
= callback
.result();
318 std::string
TestWebSocket::TestIsWebSocket() {
319 // Test that a NULL resource isn't a websocket.
320 pp::Resource null_resource
;
322 websocket_interface_
->IsWebSocket(null_resource
.pp_resource());
323 ASSERT_FALSE(result
);
325 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
328 result
= websocket_interface_
->IsWebSocket(ws
);
331 core_interface_
->ReleaseResource(ws
);
336 std::string
TestWebSocket::TestUninitializedPropertiesAccess() {
337 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
340 uint64_t bufferedAmount
= websocket_interface_
->GetBufferedAmount(ws
);
341 ASSERT_EQ(0U, bufferedAmount
);
343 uint16_t close_code
= websocket_interface_
->GetCloseCode(ws
);
344 ASSERT_EQ(0U, close_code
);
346 PP_Var close_reason
= websocket_interface_
->GetCloseReason(ws
);
347 ASSERT_TRUE(AreEqualWithString(close_reason
, ""));
348 ReleaseVar(close_reason
);
350 PP_Bool close_was_clean
= websocket_interface_
->GetCloseWasClean(ws
);
351 ASSERT_EQ(PP_FALSE
, close_was_clean
);
353 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
354 ASSERT_TRUE(AreEqualWithString(extensions
, ""));
355 ReleaseVar(extensions
);
357 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
358 ASSERT_TRUE(AreEqualWithString(protocol
, ""));
359 ReleaseVar(protocol
);
361 PP_WebSocketReadyState ready_state
=
362 websocket_interface_
->GetReadyState(ws
);
363 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ready_state
);
365 PP_Var url
= websocket_interface_
->GetURL(ws
);
366 ASSERT_TRUE(AreEqualWithString(url
, ""));
369 core_interface_
->ReleaseResource(ws
);
374 std::string
TestWebSocket::TestInvalidConnect() {
375 PP_Var protocols
[] = { PP_MakeUndefined() };
377 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
380 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
381 callback
.WaitForResult(websocket_interface_
->Connect(
382 ws
, PP_MakeUndefined(), protocols
, 1U,
383 callback
.GetCallback().pp_completion_callback()));
384 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
386 callback
.WaitForResult(websocket_interface_
->Connect(
387 ws
, PP_MakeUndefined(), protocols
, 1U,
388 callback
.GetCallback().pp_completion_callback()));
389 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback
.result());
391 core_interface_
->ReleaseResource(ws
);
393 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
395 ws
= Connect(kInvalidURLs
[i
], &result
, "");
397 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
399 core_interface_
->ReleaseResource(ws
);
405 std::string
TestWebSocket::TestProtocols() {
406 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
407 PP_Var bad_protocols
[] = {
408 CreateVarString("x-test"),
409 CreateVarString("x-test")
411 PP_Var good_protocols
[] = {
412 CreateVarString("x-test"),
413 CreateVarString("x-yatest")
416 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
418 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
419 callback
.WaitForResult(websocket_interface_
->Connect(
420 ws
, url
, bad_protocols
, 2U,
421 callback
.GetCallback().pp_completion_callback()));
422 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
423 core_interface_
->ReleaseResource(ws
);
425 ws
= websocket_interface_
->Create(instance_
->pp_instance());
427 int32_t result
= websocket_interface_
->Connect(
428 ws
, url
, good_protocols
, 2U, PP_BlockUntilComplete());
429 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, result
);
430 core_interface_
->ReleaseResource(ws
);
433 for (int i
= 0; i
< 2; ++i
) {
434 ReleaseVar(bad_protocols
[i
]);
435 ReleaseVar(good_protocols
[i
]);
437 core_interface_
->ReleaseResource(ws
);
442 std::string
TestWebSocket::TestGetURL() {
443 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
445 PP_Resource ws
= Connect(kInvalidURLs
[i
], &result
, "");
447 PP_Var url
= websocket_interface_
->GetURL(ws
);
448 ASSERT_TRUE(AreEqualWithString(url
, kInvalidURLs
[i
]));
449 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
452 core_interface_
->ReleaseResource(ws
);
458 std::string
TestWebSocket::TestValidConnect() {
460 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
462 ASSERT_EQ(PP_OK
, result
);
463 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
464 ASSERT_TRUE(AreEqualWithString(extensions
, ""));
465 core_interface_
->ReleaseResource(ws
);
470 std::string
TestWebSocket::TestInvalidClose() {
471 PP_Var reason
= CreateVarString("close for test");
472 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
473 TestCompletionCallback
async_callback(instance_
->pp_instance(), PP_REQUIRED
);
475 // Close before connect.
476 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
477 callback
.WaitForResult(websocket_interface_
->Close(
478 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
479 callback
.GetCallback().pp_completion_callback()));
480 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
481 core_interface_
->ReleaseResource(ws
);
483 // Close with bad arguments.
485 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
487 ASSERT_EQ(PP_OK
, result
);
488 callback
.WaitForResult(websocket_interface_
->Close(
489 ws
, 1U, reason
, callback
.GetCallback().pp_completion_callback()));
490 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
491 core_interface_
->ReleaseResource(ws
);
493 // Close with PP_VARTYPE_NULL.
494 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
496 ASSERT_EQ(PP_OK
, result
);
497 callback
.WaitForResult(websocket_interface_
->Close(
498 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
499 callback
.GetCallback().pp_completion_callback()));
500 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
501 core_interface_
->ReleaseResource(ws
);
503 // Close with PP_VARTYPE_NULL and ongoing receive message.
504 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
506 ASSERT_EQ(PP_OK
, result
);
507 PP_Var receive_message_var
;
508 result
= websocket_interface_
->ReceiveMessage(
509 ws
, &receive_message_var
,
510 async_callback
.GetCallback().pp_completion_callback());
511 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, 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 const char* send_message
= "hi";
517 PP_Var send_message_var
= CreateVarString(send_message
);
518 result
= websocket_interface_
->SendMessage(ws
, send_message_var
);
519 ReleaseVar(send_message_var
);
520 ASSERT_EQ(PP_OK
, result
);
521 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
522 ASSERT_EQ(PP_OK
, async_callback
.result());
523 ASSERT_TRUE(AreEqualWithString(receive_message_var
, send_message
));
524 ReleaseVar(receive_message_var
);
525 core_interface_
->ReleaseResource(ws
);
528 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
530 ASSERT_EQ(PP_OK
, result
);
531 result
= websocket_interface_
->Close(
532 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
533 async_callback
.GetCallback().pp_completion_callback());
534 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
535 // Call another Close() before previous one is in progress.
536 result
= websocket_interface_
->Close(
537 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
538 callback
.GetCallback().pp_completion_callback());
539 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
540 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
541 ASSERT_EQ(PP_OK
, async_callback
.result());
542 // Call another Close() after previous one is completed.
543 // This Close() must do nothing and reports no error.
544 callback
.WaitForResult(websocket_interface_
->Close(
545 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
546 callback
.GetCallback().pp_completion_callback()));
547 ASSERT_EQ(PP_OK
, callback
.result());
548 core_interface_
->ReleaseResource(ws
);
555 std::string
TestWebSocket::TestValidClose() {
556 PP_Var reason
= CreateVarString("close for test");
557 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
558 PP_Var protocols
[] = { PP_MakeUndefined() };
559 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
560 TestCompletionCallback
another_callback(
561 instance_
->pp_instance(), callback_type());
565 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
567 ASSERT_EQ(PP_OK
, result
);
568 callback
.WaitForResult(websocket_interface_
->Close(
569 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
570 callback
.GetCallback().pp_completion_callback()));
571 CHECK_CALLBACK_BEHAVIOR(callback
);
572 ASSERT_EQ(PP_OK
, callback
.result());
573 core_interface_
->ReleaseResource(ws
);
575 // Close without code and reason.
576 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
578 ASSERT_EQ(PP_OK
, result
);
579 callback
.WaitForResult(websocket_interface_
->Close(
580 ws
, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED
, reason
,
581 callback
.GetCallback().pp_completion_callback()));
582 ASSERT_EQ(PP_OK
, callback
.result());
583 core_interface_
->ReleaseResource(ws
);
585 // Close with PP_VARTYPE_UNDEFINED.
586 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
588 ASSERT_EQ(PP_OK
, result
);
589 callback
.WaitForResult(websocket_interface_
->Close(
590 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
591 callback
.GetCallback().pp_completion_callback()));
592 CHECK_CALLBACK_BEHAVIOR(callback
);
593 ASSERT_EQ(PP_OK
, callback
.result());
594 core_interface_
->ReleaseResource(ws
);
596 // Close in connecting.
597 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
599 ws
= websocket_interface_
->Create(instance_
->pp_instance());
600 result
= websocket_interface_
->Connect(
601 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
602 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
603 result
= websocket_interface_
->Close(
604 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
605 another_callback
.GetCallback().pp_completion_callback());
606 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
607 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
608 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
609 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
610 ASSERT_EQ(PP_OK
, another_callback
.result());
611 core_interface_
->ReleaseResource(ws
);
614 // The first close will be done successfully, then the second one failed with
615 // with PP_ERROR_INPROGRESS immediately.
616 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
618 ASSERT_EQ(PP_OK
, result
);
619 result
= websocket_interface_
->Close(
620 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
621 callback
.GetCallback().pp_completion_callback());
622 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
623 result
= websocket_interface_
->Close(
624 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
625 another_callback
.GetCallback().pp_completion_callback());
626 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
627 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
628 ASSERT_EQ(PP_OK
, callback
.result());
629 core_interface_
->ReleaseResource(ws
);
631 // Close with ongoing receive message.
632 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
634 ASSERT_EQ(PP_OK
, result
);
635 PP_Var receive_message_var
;
636 result
= websocket_interface_
->ReceiveMessage(
637 ws
, &receive_message_var
,
638 callback
.GetCallback().pp_completion_callback());
639 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
640 result
= websocket_interface_
->Close(
641 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
642 another_callback
.GetCallback().pp_completion_callback());
643 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
644 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
645 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
646 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
647 ASSERT_EQ(PP_OK
, another_callback
.result());
648 core_interface_
->ReleaseResource(ws
);
650 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
651 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
653 ASSERT_EQ(PP_OK
, result
);
654 result
= websocket_interface_
->ReceiveMessage(
655 ws
, &receive_message_var
,
656 callback
.GetCallback().pp_completion_callback());
657 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
658 result
= websocket_interface_
->Close(
659 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
660 another_callback
.GetCallback().pp_completion_callback());
661 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
662 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
663 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
664 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
665 ASSERT_EQ(PP_OK
, another_callback
.result());
666 core_interface_
->ReleaseResource(ws
);
668 // Server initiated closing handshake.
669 ws
= Connect(GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, "");
671 ASSERT_EQ(PP_OK
, result
);
672 // Text messsage "1000 bye" requests the server to initiate closing handshake
673 // with code being 1000 and reason being "bye".
674 PP_Var close_request_var
= CreateVarString("1000 bye");
675 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
676 ReleaseVar(close_request_var
);
677 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
678 ws
, &receive_message_var
,
679 callback
.GetCallback().pp_completion_callback()));
680 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
681 core_interface_
->ReleaseResource(ws
);
689 std::string
TestWebSocket::TestGetProtocol() {
690 const char* expected_protocols
[] = {
695 for (int i
= 0; expected_protocols
[i
]; ++i
) {
696 std::string
url(GetFullURL(kProtocolTestServerURL
));
697 url
+= expected_protocols
[i
];
699 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
701 ASSERT_EQ(PP_OK
, result
);
703 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
704 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
706 ReleaseVar(protocol
);
707 core_interface_
->ReleaseResource(ws
);
713 std::string
TestWebSocket::TestTextSendReceive() {
714 // Connect to test echo server.
715 int32_t connect_result
;
716 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
718 ASSERT_EQ(PP_OK
, connect_result
);
720 // Send 'hello pepper' text message.
721 const char* message
= "hello pepper";
722 PP_Var message_var
= CreateVarString(message
);
723 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
724 ReleaseVar(message_var
);
725 ASSERT_EQ(PP_OK
, result
);
727 // Receive echoed 'hello pepper'.
728 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
729 PP_Var received_message
;
730 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
731 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
732 ASSERT_EQ(PP_OK
, callback
.result());
733 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
734 ReleaseVar(received_message
);
735 core_interface_
->ReleaseResource(ws
);
740 std::string
TestWebSocket::TestBinarySendReceive() {
741 // Connect to test echo server.
742 int32_t connect_result
;
743 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
745 ASSERT_EQ(PP_OK
, connect_result
);
747 // Send binary message.
748 std::vector
<uint8_t> binary(256);
749 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
751 PP_Var message_var
= CreateVarBinary(binary
);
752 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
753 ReleaseVar(message_var
);
754 ASSERT_EQ(PP_OK
, result
);
756 // Receive echoed binary.
757 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
758 PP_Var received_message
;
759 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
760 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
761 ASSERT_EQ(PP_OK
, callback
.result());
762 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
763 ReleaseVar(received_message
);
764 core_interface_
->ReleaseResource(ws
);
769 std::string
TestWebSocket::TestStressedSendReceive() {
770 // Connect to test echo server.
771 int32_t connect_result
;
772 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
774 ASSERT_EQ(PP_OK
, connect_result
);
776 // Prepare PP_Var objects to send.
777 const char* text
= "hello pepper";
778 PP_Var text_var
= CreateVarString(text
);
779 std::vector
<uint8_t> binary(256);
780 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
782 PP_Var binary_var
= CreateVarBinary(binary
);
783 // Prepare very large binary data over 64KiB. Object serializer in
784 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
785 // to SRPC. In case received data over 64KiB exists, a specific code handles
786 // this large data via asynchronous callback from main thread. This data
787 // intends to test the code.
788 std::vector
<uint8_t> large_binary(65 * 1024);
789 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
790 large_binary
[i
] = i
& 0xff;
791 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
793 // Send many messages.
795 for (int i
= 0; i
< 256; ++i
) {
796 result
= websocket_interface_
->SendMessage(ws
, text_var
);
797 ASSERT_EQ(PP_OK
, result
);
798 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
799 ASSERT_EQ(PP_OK
, result
);
801 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
802 ASSERT_EQ(PP_OK
, result
);
803 ReleaseVar(text_var
);
804 ReleaseVar(binary_var
);
805 ReleaseVar(large_binary_var
);
807 // Receive echoed data.
808 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
809 for (int i
= 0; i
<= 512; ++i
) {
810 PP_Var received_message
;
811 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
812 ws
, &received_message
,
813 callback
.GetCallback().pp_completion_callback()));
814 ASSERT_EQ(PP_OK
, callback
.result());
816 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
818 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
820 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
822 ReleaseVar(received_message
);
824 core_interface_
->ReleaseResource(ws
);
829 std::string
TestWebSocket::TestBufferedAmount() {
830 // Connect to test echo server.
831 int32_t connect_result
;
832 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
834 ASSERT_EQ(PP_OK
, connect_result
);
836 // Prepare a large message that is not aligned with the internal buffer
838 std::string
message(8193, 'x');
839 PP_Var message_var
= CreateVarString(message
);
841 uint64_t buffered_amount
= 0;
843 for (int i
= 0; i
< 100; i
++) {
844 result
= websocket_interface_
->SendMessage(ws
, message_var
);
845 ASSERT_EQ(PP_OK
, result
);
846 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
847 // Buffered amount size 262144 is too big for the internal buffer size.
848 if (buffered_amount
> 262144)
853 std::string reason_str
= "close while busy";
854 PP_Var reason
= CreateVarString(reason_str
.c_str());
855 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
856 result
= websocket_interface_
->Close(
857 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
858 callback
.GetCallback().pp_completion_callback());
859 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
860 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
861 websocket_interface_
->GetReadyState(ws
));
863 callback
.WaitForResult(result
);
864 ASSERT_EQ(PP_OK
, callback
.result());
865 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
866 websocket_interface_
->GetReadyState(ws
));
868 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
870 // After connection closure, all sending requests fail and just increase
871 // the bufferedAmount property.
872 PP_Var empty_string
= CreateVarString("");
873 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
874 ASSERT_EQ(PP_ERROR_FAILED
, result
);
875 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
876 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
877 base_buffered_amount
= buffered_amount
;
879 result
= websocket_interface_
->SendMessage(ws
, reason
);
880 ASSERT_EQ(PP_ERROR_FAILED
, result
);
881 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
882 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
883 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
885 ReleaseVar(message_var
);
887 ReleaseVar(empty_string
);
888 core_interface_
->ReleaseResource(ws
);
893 std::string
TestWebSocket::TestAbortCalls() {
894 // Test abort behaviors where a WebSocket PP_Resource is released while
895 // each function is in-flight on the WebSocket PP_Resource.
896 std::vector
<uint8_t> large_binary(65 * 1024);
897 PP_Var large_var
= CreateVarBinary(large_binary
);
899 // Firstly, test the behavior for SendMessage().
900 // This function doesn't require a callback, but operation will be done
901 // asynchronously in WebKit and browser process.
903 std::string url
= GetFullURL(kEchoServerURL
);
904 PP_Resource ws
= Connect(url
, &result
, "");
906 ASSERT_EQ(PP_OK
, result
);
907 result
= websocket_interface_
->SendMessage(ws
, large_var
);
908 ASSERT_EQ(PP_OK
, result
);
909 core_interface_
->ReleaseResource(ws
);
911 // Following tests make sure the behavior for functions which require a
912 // callback. The callback must get a PP_ERROR_ABORTED.
913 // Test the behavior for Connect().
914 ws
= websocket_interface_
->Create(instance_
->pp_instance());
916 PP_Var url_var
= CreateVarString(url
);
917 TestCompletionCallback
connect_callback(
918 instance_
->pp_instance(), callback_type());
919 result
= websocket_interface_
->Connect(
920 ws
, url_var
, NULL
, 0,
921 connect_callback
.GetCallback().pp_completion_callback());
922 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
923 core_interface_
->ReleaseResource(ws
);
924 connect_callback
.WaitForResult(result
);
925 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
928 // Test the behavior for Close().
929 ws
= Connect(url
, &result
, "");
931 ASSERT_EQ(PP_OK
, result
);
932 PP_Var reason_var
= CreateVarString("abort");
933 TestCompletionCallback
close_callback(
934 instance_
->pp_instance(), callback_type());
935 result
= websocket_interface_
->Close(
936 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
937 close_callback
.GetCallback().pp_completion_callback());
938 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
939 core_interface_
->ReleaseResource(ws
);
940 close_callback
.WaitForResult(result
);
941 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
942 ReleaseVar(reason_var
);
944 // Test the behavior for ReceiveMessage().
945 // Firstly, make sure the simplest case to wait for data which never arrives.
946 ws
= Connect(url
, &result
, "");
948 ASSERT_EQ(PP_OK
, result
);
950 TestCompletionCallback
receive_callback(
951 instance_
->pp_instance(), callback_type());
952 result
= websocket_interface_
->ReceiveMessage(
954 receive_callback
.GetCallback().pp_completion_callback());
955 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
956 core_interface_
->ReleaseResource(ws
);
957 receive_callback
.WaitForResult(result
);
958 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
960 // Release the resource in the close completion callback.
961 ws
= Connect(url
, &result
, "");
963 ASSERT_EQ(PP_OK
, result
);
964 result
= websocket_interface_
->Close(
965 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
966 close_callback
.GetCallback().pp_completion_callback());
967 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
968 close_callback
.SetDelegate(&close_delegate
);
969 close_callback
.WaitForResult(result
);
970 CHECK_CALLBACK_BEHAVIOR(close_callback
);
971 ASSERT_EQ(PP_OK
, close_callback
.result());
973 // Release the resource in the aborting receive completion callback which is
974 // introduced by calling Close().
975 ws
= Connect(url
, &result
, "");
977 ASSERT_EQ(PP_OK
, result
);
978 result
= websocket_interface_
->ReceiveMessage(
980 receive_callback
.GetCallback().pp_completion_callback());
981 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
982 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
983 receive_callback
.SetDelegate(&receive_delegate
);
984 result
= websocket_interface_
->Close(
985 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
986 close_callback
.GetCallback().pp_completion_callback());
987 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
988 receive_callback
.WaitForResult(result
);
989 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
990 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
991 close_callback
.WaitForResult(result
);
992 CHECK_CALLBACK_BEHAVIOR(close_callback
);
993 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
995 // Test the behavior where receive process might be in-flight.
996 const char* text
= "yukarin";
997 PP_Var text_var
= CreateVarString(text
);
999 // Each trial sends 17 messages and receives just |trial| number of
1000 // message(s) before releasing the WebSocket. The WebSocket is released while
1001 // the next message is going to be received.
1002 for (int trial
= 1; trial
<= 16; trial
++) {
1003 ws
= Connect(url
, &result
, "");
1005 ASSERT_EQ(PP_OK
, result
);
1006 for (int i
= 0; i
<= 16; ++i
) {
1007 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1008 ASSERT_EQ(PP_OK
, result
);
1010 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1012 for (int i
= 0; i
< trial
; ++i
) {
1013 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1014 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1015 ASSERT_EQ(PP_OK
, callback
.result());
1016 ASSERT_TRUE(AreEqualWithString(var
, text
));
1019 result
= websocket_interface_
->ReceiveMessage(
1020 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1021 core_interface_
->ReleaseResource(ws
);
1022 if (result
!= PP_OK
) {
1023 callback
.WaitForResult(result
);
1024 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1027 // Same test, but the last receiving message is large message over 64KiB.
1028 for (int trial
= 1; trial
<= 16; trial
++) {
1029 ws
= Connect(url
, &result
, "");
1031 ASSERT_EQ(PP_OK
, result
);
1032 for (int i
= 0; i
<= 16; ++i
) {
1034 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1036 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1037 ASSERT_EQ(PP_OK
, result
);
1039 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1041 for (int i
= 0; i
< trial
; ++i
) {
1042 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1043 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1044 ASSERT_EQ(PP_OK
, callback
.result());
1045 ASSERT_TRUE(AreEqualWithString(var
, text
));
1048 result
= websocket_interface_
->ReceiveMessage(
1049 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1050 core_interface_
->ReleaseResource(ws
);
1051 if (result
!= PP_OK
) {
1052 callback
.WaitForResult(result
);
1053 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1057 ReleaseVar(large_var
);
1058 ReleaseVar(text_var
);
1063 std::string
TestWebSocket::TestCcInterfaces() {
1064 // C++ bindings is simple straightforward, then just verifies interfaces work
1065 // as a interface bridge fine.
1066 pp::WebSocket
ws(instance_
);
1068 // Check uninitialized properties access.
1069 ASSERT_EQ(0, ws
.GetBufferedAmount());
1070 ASSERT_EQ(0, ws
.GetCloseCode());
1071 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), ""));
1072 ASSERT_EQ(false, ws
.GetCloseWasClean());
1073 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), ""));
1074 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), ""));
1075 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1076 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), ""));
1078 // Check communication interfaces (connect, send, receive, and close).
1079 TestCompletionCallback
connect_callback(
1080 instance_
->pp_instance(), callback_type());
1081 connect_callback
.WaitForResult(ws
.Connect(
1082 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U, connect_callback
));
1083 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1084 ASSERT_EQ(PP_OK
, connect_callback
.result());
1086 std::string
text_message("hello C++");
1087 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1088 ASSERT_EQ(PP_OK
, result
);
1090 std::vector
<uint8_t> binary(256);
1091 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1093 result
= ws
.SendMessage(
1094 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1095 ASSERT_EQ(PP_OK
, result
);
1097 pp::Var text_receive_var
;
1098 TestCompletionCallback
text_receive_callback(
1099 instance_
->pp_instance(), callback_type());
1100 text_receive_callback
.WaitForResult(
1101 ws
.ReceiveMessage(&text_receive_var
, text_receive_callback
));
1102 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1104 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1106 pp::Var binary_receive_var
;
1107 TestCompletionCallback
binary_receive_callback(
1108 instance_
->pp_instance(), callback_type());
1109 binary_receive_callback
.WaitForResult(
1110 ws
.ReceiveMessage(&binary_receive_var
, binary_receive_callback
));
1111 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1112 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1114 TestCompletionCallback
close_callback(
1115 instance_
->pp_instance(), callback_type());
1116 std::string
reason("bye");
1117 close_callback
.WaitForResult(ws
.Close(
1118 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
), close_callback
));
1119 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1120 ASSERT_EQ(PP_OK
, close_callback
.result());
1122 // Check initialized properties access.
1123 ASSERT_EQ(0, ws
.GetBufferedAmount());
1124 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1126 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1127 ASSERT_EQ(true, ws
.GetCloseWasClean());
1128 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), ""));
1129 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1130 ASSERT_TRUE(AreEqualWithString(
1131 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1136 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1137 const pp::Var protocols
[] = { pp::Var() };
1139 TestWebSocketAPI
websocket(instance_
);
1140 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1141 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1142 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1144 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1145 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1146 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1148 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1149 TestWebSocketAPI
ws(instance_
);
1150 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1151 if (result
== PP_OK_COMPLETIONPENDING
) {
1153 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1154 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1155 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1156 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1158 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1159 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1166 std::string
TestWebSocket::TestUtilityProtocols() {
1167 const pp::Var bad_protocols
[] = {
1168 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1169 const pp::Var good_protocols
[] = {
1170 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1173 TestWebSocketAPI
websocket(instance_
);
1174 int32_t result
= websocket
.Connect(
1175 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1176 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1177 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1181 TestWebSocketAPI
websocket(instance_
);
1182 int32_t result
= websocket
.Connect(
1183 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1184 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1185 websocket
.WaitForConnected();
1186 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1187 // Protocol arguments are valid, but this test run without a WebSocket
1188 // server. As a result, OnError() and OnClose() are invoked because of
1189 // a connection establishment failure.
1190 ASSERT_EQ(2U, events
.size());
1191 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1192 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1193 ASSERT_FALSE(events
[1].was_clean
);
1199 std::string
TestWebSocket::TestUtilityGetURL() {
1200 const pp::Var protocols
[] = { pp::Var() };
1202 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1203 TestWebSocketAPI
websocket(instance_
);
1204 int32_t result
= websocket
.Connect(
1205 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1206 if (result
== PP_OK_COMPLETIONPENDING
) {
1207 websocket
.WaitForClosed();
1208 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1209 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1210 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1211 ASSERT_EQ(2U, events
.size());
1213 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1214 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1216 pp::Var url
= websocket
.GetURL();
1217 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1223 std::string
TestWebSocket::TestUtilityValidConnect() {
1224 const pp::Var protocols
[] = { pp::Var() };
1225 TestWebSocketAPI
websocket(instance_
);
1226 int32_t result
= websocket
.Connect(
1227 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1228 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1229 websocket
.WaitForConnected();
1230 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1231 ASSERT_EQ(1U, events
.size());
1232 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1233 ASSERT_TRUE(AreEqualWithString(websocket
.GetExtensions().pp_var(), ""));
1238 std::string
TestWebSocket::TestUtilityInvalidClose() {
1239 const pp::Var reason
= pp::Var(std::string("close for test"));
1241 // Close before connect.
1243 TestWebSocketAPI
websocket(instance_
);
1244 int32_t result
= websocket
.Close(
1245 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1246 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1247 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1250 // Close with bad arguments.
1252 TestWebSocketAPI
websocket(instance_
);
1253 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1255 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1256 websocket
.WaitForConnected();
1257 result
= websocket
.Close(1U, reason
);
1258 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1259 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1260 ASSERT_EQ(1U, events
.size());
1261 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1267 std::string
TestWebSocket::TestUtilityValidClose() {
1268 std::string
reason("close for test");
1269 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1273 TestWebSocketAPI
websocket(instance_
);
1274 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1275 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1276 websocket
.WaitForConnected();
1277 result
= websocket
.Close(
1278 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1279 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1280 websocket
.WaitForClosed();
1281 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1282 ASSERT_EQ(2U, events
.size());
1283 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1284 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1285 ASSERT_TRUE(events
[1].was_clean
);
1286 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1287 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1290 // Close in connecting.
1291 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1294 TestWebSocketAPI
websocket(instance_
);
1295 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1296 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1297 result
= websocket
.Close(
1298 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1299 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1300 websocket
.WaitForClosed();
1301 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1302 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1304 if (events
.size() == 3)
1305 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1306 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1307 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1308 ASSERT_FALSE(events
[index
].was_clean
);
1311 // Close in closing.
1312 // The first close will be done successfully, then the second one failed with
1313 // with PP_ERROR_INPROGRESS immediately.
1315 TestWebSocketAPI
websocket(instance_
);
1316 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1317 result
= websocket
.Close(
1318 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1319 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1320 result
= websocket
.Close(
1321 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1322 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1323 websocket
.WaitForClosed();
1324 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1325 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3)
1327 if (events
.size() == 3)
1328 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1329 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1330 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1331 ASSERT_FALSE(events
[index
].was_clean
);
1337 std::string
TestWebSocket::TestUtilityGetProtocol() {
1338 const std::string
protocol("x-chat");
1339 const pp::Var protocols
[] = { pp::Var(protocol
) };
1340 std::string
url(GetFullURL(kProtocolTestServerURL
));
1342 TestWebSocketAPI
websocket(instance_
);
1343 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1344 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1345 websocket
.WaitForReceived();
1346 ASSERT_TRUE(AreEqualWithString(
1347 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1348 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1349 // The server to which this test connect returns the decided protocol as a
1350 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1351 // after EVENT_OPEN event.
1352 ASSERT_EQ(2U, events
.size());
1353 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1354 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1355 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1360 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1361 const pp::Var protocols
[] = { pp::Var() };
1362 TestWebSocketAPI
websocket(instance_
);
1364 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1365 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1366 websocket
.WaitForConnected();
1368 // Send 'hello pepper'.
1369 std::string
message1("hello pepper");
1370 result
= websocket
.Send(pp::Var(std::string(message1
)));
1371 ASSERT_EQ(PP_OK
, result
);
1373 // Receive echoed 'hello pepper'.
1374 websocket
.WaitForReceived();
1376 // Send 'goodbye pepper'.
1377 std::string
message2("goodbye pepper");
1378 result
= websocket
.Send(pp::Var(std::string(message2
)));
1380 // Receive echoed 'goodbye pepper'.
1381 websocket
.WaitForReceived();
1383 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1384 ASSERT_EQ(3U, events
.size());
1385 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1386 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1387 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), message1
.c_str()));
1388 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1389 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1394 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1395 const pp::Var protocols
[] = { pp::Var() };
1396 TestWebSocketAPI
websocket(instance_
);
1398 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1399 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1400 websocket
.WaitForConnected();
1402 // Send binary message.
1404 std::vector
<uint8_t> binary(len
);
1405 for (uint32_t i
= 0; i
< len
; ++i
)
1407 pp::VarArrayBuffer
message(len
);
1408 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1409 std::copy(binary
.begin(), binary
.end(), var_data
);
1410 result
= websocket
.Send(message
);
1411 ASSERT_EQ(PP_OK
, result
);
1413 // Receive echoed binary message.
1414 websocket
.WaitForReceived();
1416 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1417 ASSERT_EQ(2U, events
.size());
1418 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1419 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1420 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1425 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1426 // Connect to test echo server.
1427 const pp::Var protocols
[] = { pp::Var() };
1428 TestWebSocketAPI
websocket(instance_
);
1430 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1431 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1432 websocket
.WaitForConnected();
1434 // Prepare a large message that is not aligned with the internal buffer
1436 std::string
message(8193, 'x');
1437 uint64_t buffered_amount
= 0;
1439 for (sent
= 0; sent
< 100; sent
++) {
1440 result
= websocket
.Send(pp::Var(message
));
1441 ASSERT_EQ(PP_OK
, result
);
1442 buffered_amount
= websocket
.GetBufferedAmount();
1443 // Buffered amount size 262144 is too big for the internal buffer size.
1444 if (buffered_amount
> 262144)
1448 // Close connection.
1449 std::string reason
= "close while busy";
1450 result
= websocket
.Close(
1451 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1452 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1453 websocket
.WaitForClosed();
1454 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1456 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1457 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1459 // After connection closure, all sending requests fail and just increase
1460 // the bufferedAmount property.
1461 result
= websocket
.Send(pp::Var(std::string("")));
1462 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1463 buffered_amount
= websocket
.GetBufferedAmount();
1464 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1465 base_buffered_amount
= buffered_amount
;
1467 result
= websocket
.Send(pp::Var(reason
));
1468 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1469 buffered_amount
= websocket
.GetBufferedAmount();
1470 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1471 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1473 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1474 ASSERT_EQ(events_on_closed
, events
.size());
1475 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1476 size_t last_event
= events_on_closed
- 1;
1477 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1478 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1479 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1481 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1482 ASSERT_TRUE(events
[last_event
].was_clean
);