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 // net::TestServer serves WebSocket service for testing.
35 // Following URLs are handled by pywebsocket handlers in
36 // net/data/websocket/*_wsh.py.
37 const char kEchoServerURL
[] = "echo-with-no-extension";
38 const char kCloseServerURL
[] = "close";
39 const char kCloseWithCodeAndReasonServerURL
[] = "close-code-and-reason";
40 const char kProtocolTestServerURL
[] = "protocol-test?protocol=";
42 const char* const kInvalidURLs
[] = {
43 "http://www.google.com/invalid_scheme",
44 "ws://www.google.com/invalid#fragment",
45 "ws://www.google.com:65535/invalid_port",
49 // Internal packet sizes.
50 const uint64_t kCloseFrameSize
= 6;
51 const uint64_t kMessageFrameOverhead
= 6;
55 struct WebSocketEvent
{
63 WebSocketEvent(EventType type
,
69 close_code(close_code
),
78 class ReleaseResourceDelegate
: public TestCompletionCallback::Delegate
{
80 explicit ReleaseResourceDelegate(const PPB_Core
* core_interface
,
82 : core_interface_(core_interface
),
86 // TestCompletionCallback::Delegate implementation.
87 virtual void OnCallback(void* user_data
, int32_t result
) {
89 core_interface_
->ReleaseResource(resource_
);
93 const PPB_Core
* core_interface_
;
94 PP_Resource resource_
;
97 class TestWebSocketAPI
: public pp::WebSocketAPI
{
99 explicit TestWebSocketAPI(pp::Instance
* instance
)
100 : pp::WebSocketAPI(instance
),
104 wait_for_connected_(false),
105 wait_for_received_(false),
106 wait_for_closed_(false),
107 instance_(instance
->pp_instance()) {
110 virtual void WebSocketDidOpen() {
112 WebSocketEvent(WebSocketEvent::EVENT_OPEN
, true, 0U, pp::Var()));
114 if (wait_for_connected_
) {
115 GetTestingInterface()->QuitMessageLoop(instance_
);
116 wait_for_connected_
= false;
120 virtual void WebSocketDidClose(
121 bool was_clean
, uint16_t code
, const pp::Var
& reason
) {
123 WebSocketEvent(WebSocketEvent::EVENT_CLOSE
, was_clean
, code
, reason
));
126 if (wait_for_connected_
|| wait_for_closed_
) {
127 GetTestingInterface()->QuitMessageLoop(instance_
);
128 wait_for_connected_
= false;
129 wait_for_closed_
= false;
133 virtual void HandleWebSocketMessage(const pp::Var
&message
) {
135 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE
, true, 0U, message
));
137 if (wait_for_received_
) {
138 GetTestingInterface()->QuitMessageLoop(instance_
);
139 wait_for_received_
= false;
144 virtual void HandleWebSocketError() {
146 WebSocketEvent(WebSocketEvent::EVENT_ERROR
, true, 0U, pp::Var()));
149 void WaitForConnected() {
151 wait_for_connected_
= true;
152 GetTestingInterface()->RunMessageLoop(instance_
);
156 void WaitForReceived() {
158 wait_for_received_
= true;
159 GetTestingInterface()->RunMessageLoop(instance_
);
163 void WaitForClosed() {
165 wait_for_closed_
= true;
166 GetTestingInterface()->RunMessageLoop(instance_
);
170 const std::vector
<WebSocketEvent
>& GetSeenEvents() const {
175 std::vector
<WebSocketEvent
> events_
;
179 bool wait_for_connected_
;
180 bool wait_for_received_
;
181 bool wait_for_closed_
;
182 PP_Instance instance_
;
187 REGISTER_TEST_CASE(WebSocket
);
189 bool TestWebSocket::Init() {
190 websocket_interface_
= static_cast<const PPB_WebSocket
*>(
191 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE
));
192 var_interface_
= static_cast<const PPB_Var
*>(
193 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
194 arraybuffer_interface_
= static_cast<const PPB_VarArrayBuffer
*>(
195 pp::Module::Get()->GetBrowserInterface(
196 PPB_VAR_ARRAY_BUFFER_INTERFACE
));
197 core_interface_
= static_cast<const PPB_Core
*>(
198 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
199 if (!websocket_interface_
|| !var_interface_
|| !arraybuffer_interface_
||
203 return CheckTestingInterface();
206 void TestWebSocket::RunTests(const std::string
& filter
) {
207 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket
, filter
);
208 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess
, filter
);
209 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect
, filter
);
210 RUN_TEST_WITH_REFERENCE_CHECK(Protocols
, filter
);
211 RUN_TEST_WITH_REFERENCE_CHECK(GetURL
, filter
);
212 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect
, filter
);
213 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose
, filter
);
214 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose
, filter
);
215 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol
, filter
);
216 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive
, filter
);
217 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive
, filter
);
218 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive
, filter
);
219 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount
, filter
);
220 // PP_Resource for WebSocket may be released later because of an internal
221 // reference for asynchronous IPC handling. So, suppress reference check on
222 // the following AbortCallsWithCallback test.
223 RUN_TEST(AbortCallsWithCallback
, filter
);
224 RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall
, filter
);
225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall
, filter
);
226 RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall
, filter
);
228 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces
, filter
);
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
);
242 std::string
TestWebSocket::GetFullURL(const char* url
) {
243 std::string rv
= "ws://localhost";
244 // Some WebSocket tests don't start the server so there'll be no port.
245 if (instance_
->websocket_port() != -1) {
247 sprintf(buffer
, ":%d", instance_
->websocket_port());
248 rv
+= std::string(buffer
);
255 PP_Var
TestWebSocket::CreateVarString(const std::string
& string
) {
256 return var_interface_
->VarFromUtf8(string
.c_str(), string
.size());
259 PP_Var
TestWebSocket::CreateVarBinary(const std::vector
<uint8_t>& binary
) {
260 PP_Var var
= arraybuffer_interface_
->Create(binary
.size());
261 uint8_t* var_data
= static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
));
262 std::copy(binary
.begin(), binary
.end(), var_data
);
266 void TestWebSocket::ReleaseVar(const PP_Var
& var
) {
267 var_interface_
->Release(var
);
270 bool TestWebSocket::AreEqualWithString(const PP_Var
& var
,
271 const std::string
& string
) {
272 if (var
.type
!= PP_VARTYPE_STRING
)
274 uint32_t utf8_length
;
275 const char* utf8
= var_interface_
->VarToUtf8(var
, &utf8_length
);
276 if (utf8_length
!= string
.size())
278 if (string
.compare(utf8
))
283 bool TestWebSocket::AreEqualWithBinary(const PP_Var
& var
,
284 const std::vector
<uint8_t>& binary
) {
285 uint32_t buffer_size
= 0;
286 PP_Bool success
= arraybuffer_interface_
->ByteLength(var
, &buffer_size
);
287 if (!success
|| buffer_size
!= binary
.size())
289 if (!std::equal(binary
.begin(), binary
.end(),
290 static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
))))
295 PP_Resource
TestWebSocket::Connect(const std::string
& url
,
297 const std::string
& protocol
) {
298 PP_Var protocols
[] = { PP_MakeUndefined() };
299 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
302 PP_Var url_var
= CreateVarString(url
);
303 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
304 uint32_t protocol_count
= 0U;
305 if (protocol
.size()) {
306 protocols
[0] = CreateVarString(protocol
);
309 callback
.WaitForResult(websocket_interface_
->Connect(
310 ws
, url_var
, protocols
, protocol_count
,
311 callback
.GetCallback().pp_completion_callback()));
314 ReleaseVar(protocols
[0]);
315 *result
= callback
.result();
319 std::string
TestWebSocket::TestIsWebSocket() {
320 // Test that a NULL resource isn't a websocket.
321 pp::Resource null_resource
;
323 websocket_interface_
->IsWebSocket(null_resource
.pp_resource());
324 ASSERT_FALSE(result
);
326 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
329 result
= websocket_interface_
->IsWebSocket(ws
);
332 core_interface_
->ReleaseResource(ws
);
337 std::string
TestWebSocket::TestUninitializedPropertiesAccess() {
338 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
341 uint64_t bufferedAmount
= websocket_interface_
->GetBufferedAmount(ws
);
342 ASSERT_EQ(0U, bufferedAmount
);
344 uint16_t close_code
= websocket_interface_
->GetCloseCode(ws
);
345 ASSERT_EQ(0U, close_code
);
347 PP_Var close_reason
= websocket_interface_
->GetCloseReason(ws
);
348 ASSERT_TRUE(AreEqualWithString(close_reason
, ""));
349 ReleaseVar(close_reason
);
351 PP_Bool close_was_clean
= websocket_interface_
->GetCloseWasClean(ws
);
352 ASSERT_EQ(PP_FALSE
, close_was_clean
);
354 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
355 ASSERT_TRUE(AreEqualWithString(extensions
, ""));
356 ReleaseVar(extensions
);
358 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
359 ASSERT_TRUE(AreEqualWithString(protocol
, ""));
360 ReleaseVar(protocol
);
362 PP_WebSocketReadyState ready_state
=
363 websocket_interface_
->GetReadyState(ws
);
364 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ready_state
);
366 PP_Var url
= websocket_interface_
->GetURL(ws
);
367 ASSERT_TRUE(AreEqualWithString(url
, ""));
370 core_interface_
->ReleaseResource(ws
);
375 std::string
TestWebSocket::TestInvalidConnect() {
376 PP_Var protocols
[] = { PP_MakeUndefined() };
378 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
381 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
382 callback
.WaitForResult(websocket_interface_
->Connect(
383 ws
, PP_MakeUndefined(), protocols
, 1U,
384 callback
.GetCallback().pp_completion_callback()));
385 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
387 callback
.WaitForResult(websocket_interface_
->Connect(
388 ws
, PP_MakeUndefined(), protocols
, 1U,
389 callback
.GetCallback().pp_completion_callback()));
390 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback
.result());
392 core_interface_
->ReleaseResource(ws
);
394 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
396 ws
= Connect(kInvalidURLs
[i
], &result
, "");
398 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
400 core_interface_
->ReleaseResource(ws
);
406 std::string
TestWebSocket::TestProtocols() {
407 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
408 PP_Var bad_protocols
[] = {
409 CreateVarString("x-test"),
410 CreateVarString("x-test")
412 PP_Var good_protocols
[] = {
413 CreateVarString("x-test"),
414 CreateVarString("x-yatest")
417 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
419 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
420 callback
.WaitForResult(websocket_interface_
->Connect(
421 ws
, url
, bad_protocols
, 2U,
422 callback
.GetCallback().pp_completion_callback()));
423 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
424 core_interface_
->ReleaseResource(ws
);
426 ws
= websocket_interface_
->Create(instance_
->pp_instance());
428 int32_t result
= websocket_interface_
->Connect(
429 ws
, url
, good_protocols
, 2U, PP_BlockUntilComplete());
430 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, result
);
431 core_interface_
->ReleaseResource(ws
);
434 for (int i
= 0; i
< 2; ++i
) {
435 ReleaseVar(bad_protocols
[i
]);
436 ReleaseVar(good_protocols
[i
]);
438 core_interface_
->ReleaseResource(ws
);
443 std::string
TestWebSocket::TestGetURL() {
444 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
446 PP_Resource ws
= Connect(kInvalidURLs
[i
], &result
, "");
448 PP_Var url
= websocket_interface_
->GetURL(ws
);
449 ASSERT_TRUE(AreEqualWithString(url
, kInvalidURLs
[i
]));
450 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
453 core_interface_
->ReleaseResource(ws
);
459 std::string
TestWebSocket::TestValidConnect() {
461 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
463 ASSERT_EQ(PP_OK
, result
);
464 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
465 ASSERT_TRUE(AreEqualWithString(extensions
, ""));
466 core_interface_
->ReleaseResource(ws
);
471 std::string
TestWebSocket::TestInvalidClose() {
472 PP_Var reason
= CreateVarString("close for test");
473 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
474 TestCompletionCallback
async_callback(instance_
->pp_instance(), PP_REQUIRED
);
476 // Close before connect.
477 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
478 callback
.WaitForResult(websocket_interface_
->Close(
479 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
480 callback
.GetCallback().pp_completion_callback()));
481 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
482 core_interface_
->ReleaseResource(ws
);
484 // Close with bad arguments.
486 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
488 ASSERT_EQ(PP_OK
, result
);
489 callback
.WaitForResult(websocket_interface_
->Close(
490 ws
, 1U, reason
, callback
.GetCallback().pp_completion_callback()));
491 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
492 core_interface_
->ReleaseResource(ws
);
494 // Close with PP_VARTYPE_NULL.
495 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
497 ASSERT_EQ(PP_OK
, result
);
498 callback
.WaitForResult(websocket_interface_
->Close(
499 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
500 callback
.GetCallback().pp_completion_callback()));
501 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
502 core_interface_
->ReleaseResource(ws
);
504 // Close with PP_VARTYPE_NULL and ongoing receive message.
505 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
507 ASSERT_EQ(PP_OK
, result
);
508 PP_Var receive_message_var
;
509 result
= websocket_interface_
->ReceiveMessage(
510 ws
, &receive_message_var
,
511 async_callback
.GetCallback().pp_completion_callback());
512 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, 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 const char* send_message
= "hi";
518 PP_Var send_message_var
= CreateVarString(send_message
);
519 result
= websocket_interface_
->SendMessage(ws
, send_message_var
);
520 ReleaseVar(send_message_var
);
521 ASSERT_EQ(PP_OK
, result
);
522 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
523 ASSERT_EQ(PP_OK
, async_callback
.result());
524 ASSERT_TRUE(AreEqualWithString(receive_message_var
, send_message
));
525 ReleaseVar(receive_message_var
);
526 core_interface_
->ReleaseResource(ws
);
529 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
531 ASSERT_EQ(PP_OK
, result
);
532 result
= websocket_interface_
->Close(
533 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
534 async_callback
.GetCallback().pp_completion_callback());
535 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
536 // Call another Close() before previous one is in progress.
537 result
= websocket_interface_
->Close(
538 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
539 callback
.GetCallback().pp_completion_callback());
540 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
541 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
542 ASSERT_EQ(PP_OK
, async_callback
.result());
543 // Call another Close() after previous one is completed.
544 // This Close() must do nothing and reports no error.
545 callback
.WaitForResult(websocket_interface_
->Close(
546 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
547 callback
.GetCallback().pp_completion_callback()));
548 ASSERT_EQ(PP_OK
, callback
.result());
549 core_interface_
->ReleaseResource(ws
);
556 std::string
TestWebSocket::TestValidClose() {
557 PP_Var reason
= CreateVarString("close for test");
558 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
559 PP_Var protocols
[] = { PP_MakeUndefined() };
560 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
561 TestCompletionCallback
another_callback(
562 instance_
->pp_instance(), callback_type());
566 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
568 ASSERT_EQ(PP_OK
, result
);
569 callback
.WaitForResult(websocket_interface_
->Close(
570 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
571 callback
.GetCallback().pp_completion_callback()));
572 CHECK_CALLBACK_BEHAVIOR(callback
);
573 ASSERT_EQ(PP_OK
, callback
.result());
574 core_interface_
->ReleaseResource(ws
);
576 // Close without code and reason.
577 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
579 ASSERT_EQ(PP_OK
, result
);
580 callback
.WaitForResult(websocket_interface_
->Close(
581 ws
, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED
, reason
,
582 callback
.GetCallback().pp_completion_callback()));
583 ASSERT_EQ(PP_OK
, callback
.result());
584 core_interface_
->ReleaseResource(ws
);
586 // Close with PP_VARTYPE_UNDEFINED.
587 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
589 ASSERT_EQ(PP_OK
, result
);
590 callback
.WaitForResult(websocket_interface_
->Close(
591 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
592 callback
.GetCallback().pp_completion_callback()));
593 CHECK_CALLBACK_BEHAVIOR(callback
);
594 ASSERT_EQ(PP_OK
, callback
.result());
595 core_interface_
->ReleaseResource(ws
);
597 // Close in connecting.
598 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
600 ws
= websocket_interface_
->Create(instance_
->pp_instance());
601 result
= websocket_interface_
->Connect(
602 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
603 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
604 result
= websocket_interface_
->Close(
605 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
606 another_callback
.GetCallback().pp_completion_callback());
607 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
608 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
609 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
610 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
611 ASSERT_EQ(PP_OK
, another_callback
.result());
612 core_interface_
->ReleaseResource(ws
);
615 // The first close will be done successfully, then the second one failed with
616 // with PP_ERROR_INPROGRESS immediately.
617 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
619 ASSERT_EQ(PP_OK
, result
);
620 result
= websocket_interface_
->Close(
621 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
622 callback
.GetCallback().pp_completion_callback());
623 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
624 result
= websocket_interface_
->Close(
625 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
626 another_callback
.GetCallback().pp_completion_callback());
627 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
628 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
629 ASSERT_EQ(PP_OK
, callback
.result());
630 core_interface_
->ReleaseResource(ws
);
632 // Close with ongoing receive message.
633 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
635 ASSERT_EQ(PP_OK
, result
);
636 PP_Var receive_message_var
;
637 result
= websocket_interface_
->ReceiveMessage(
638 ws
, &receive_message_var
,
639 callback
.GetCallback().pp_completion_callback());
640 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
641 result
= websocket_interface_
->Close(
642 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
643 another_callback
.GetCallback().pp_completion_callback());
644 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
645 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
646 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
647 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
648 ASSERT_EQ(PP_OK
, another_callback
.result());
649 core_interface_
->ReleaseResource(ws
);
651 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
652 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, "");
654 ASSERT_EQ(PP_OK
, result
);
655 result
= websocket_interface_
->ReceiveMessage(
656 ws
, &receive_message_var
,
657 callback
.GetCallback().pp_completion_callback());
658 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
659 result
= websocket_interface_
->Close(
660 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
661 another_callback
.GetCallback().pp_completion_callback());
662 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
663 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
664 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
665 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
666 ASSERT_EQ(PP_OK
, another_callback
.result());
667 core_interface_
->ReleaseResource(ws
);
669 // Server initiated closing handshake.
670 ws
= Connect(GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, "");
672 ASSERT_EQ(PP_OK
, result
);
673 // Text messsage "1000 bye" requests the server to initiate closing handshake
674 // with code being 1000 and reason being "bye".
675 PP_Var close_request_var
= CreateVarString("1000 bye");
676 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
677 ReleaseVar(close_request_var
);
678 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
679 ws
, &receive_message_var
,
680 callback
.GetCallback().pp_completion_callback()));
681 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
682 core_interface_
->ReleaseResource(ws
);
690 std::string
TestWebSocket::TestGetProtocol() {
691 const char* expected_protocols
[] = {
696 for (int i
= 0; expected_protocols
[i
]; ++i
) {
697 std::string
url(GetFullURL(kProtocolTestServerURL
));
698 url
+= expected_protocols
[i
];
700 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
702 ASSERT_EQ(PP_OK
, result
);
704 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
705 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
707 ReleaseVar(protocol
);
708 core_interface_
->ReleaseResource(ws
);
714 std::string
TestWebSocket::TestTextSendReceive() {
715 // Connect to test echo server.
716 int32_t connect_result
;
717 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
719 ASSERT_EQ(PP_OK
, connect_result
);
721 // Send 'hello pepper' text message.
722 const char* message
= "hello pepper";
723 PP_Var message_var
= CreateVarString(message
);
724 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
725 ReleaseVar(message_var
);
726 ASSERT_EQ(PP_OK
, result
);
728 // Receive echoed 'hello pepper'.
729 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
730 PP_Var received_message
;
731 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
732 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
733 ASSERT_EQ(PP_OK
, callback
.result());
734 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
735 ReleaseVar(received_message
);
736 core_interface_
->ReleaseResource(ws
);
741 std::string
TestWebSocket::TestBinarySendReceive() {
742 // Connect to test echo server.
743 int32_t connect_result
;
744 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
746 ASSERT_EQ(PP_OK
, connect_result
);
748 // Send binary message.
749 std::vector
<uint8_t> binary(256);
750 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
752 PP_Var message_var
= CreateVarBinary(binary
);
753 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
754 ReleaseVar(message_var
);
755 ASSERT_EQ(PP_OK
, result
);
757 // Receive echoed binary.
758 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
759 PP_Var received_message
;
760 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
761 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
762 ASSERT_EQ(PP_OK
, callback
.result());
763 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
764 ReleaseVar(received_message
);
765 core_interface_
->ReleaseResource(ws
);
770 std::string
TestWebSocket::TestStressedSendReceive() {
771 // Connect to test echo server.
772 int32_t connect_result
;
773 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
775 ASSERT_EQ(PP_OK
, connect_result
);
777 // Prepare PP_Var objects to send.
778 const char* text
= "hello pepper";
779 PP_Var text_var
= CreateVarString(text
);
780 std::vector
<uint8_t> binary(256);
781 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
783 PP_Var binary_var
= CreateVarBinary(binary
);
784 // Prepare very large binary data over 64KiB. Object serializer in
785 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
786 // to SRPC. In case received data over 64KiB exists, a specific code handles
787 // this large data via asynchronous callback from main thread. This data
788 // intends to test the code.
789 std::vector
<uint8_t> large_binary(65 * 1024);
790 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
791 large_binary
[i
] = i
& 0xff;
792 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
794 // Send many messages.
796 for (int i
= 0; i
< 256; ++i
) {
797 result
= websocket_interface_
->SendMessage(ws
, text_var
);
798 ASSERT_EQ(PP_OK
, result
);
799 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
800 ASSERT_EQ(PP_OK
, result
);
802 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
803 ASSERT_EQ(PP_OK
, result
);
804 ReleaseVar(text_var
);
805 ReleaseVar(binary_var
);
806 ReleaseVar(large_binary_var
);
808 // Receive echoed data.
809 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
810 for (int i
= 0; i
<= 512; ++i
) {
811 PP_Var received_message
;
812 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
813 ws
, &received_message
,
814 callback
.GetCallback().pp_completion_callback()));
815 ASSERT_EQ(PP_OK
, callback
.result());
817 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
819 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
821 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
823 ReleaseVar(received_message
);
825 core_interface_
->ReleaseResource(ws
);
830 std::string
TestWebSocket::TestBufferedAmount() {
831 // Connect to test echo server.
832 int32_t connect_result
;
833 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &connect_result
, "");
835 ASSERT_EQ(PP_OK
, connect_result
);
837 // Prepare a large message that is not aligned with the internal buffer
839 std::string
message(8193, 'x');
840 PP_Var message_var
= CreateVarString(message
);
842 uint64_t buffered_amount
= 0;
844 for (int i
= 0; i
< 100; i
++) {
845 result
= websocket_interface_
->SendMessage(ws
, message_var
);
846 ASSERT_EQ(PP_OK
, result
);
847 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
848 // Buffered amount size 262144 is too big for the internal buffer size.
849 if (buffered_amount
> 262144)
854 std::string reason_str
= "close while busy";
855 PP_Var reason
= CreateVarString(reason_str
.c_str());
856 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
857 result
= websocket_interface_
->Close(
858 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
859 callback
.GetCallback().pp_completion_callback());
860 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
861 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
862 websocket_interface_
->GetReadyState(ws
));
864 callback
.WaitForResult(result
);
865 ASSERT_EQ(PP_OK
, callback
.result());
866 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
867 websocket_interface_
->GetReadyState(ws
));
869 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
871 // After connection closure, all sending requests fail and just increase
872 // the bufferedAmount property.
873 PP_Var empty_string
= CreateVarString("");
874 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
875 ASSERT_EQ(PP_ERROR_FAILED
, result
);
876 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
877 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
878 base_buffered_amount
= buffered_amount
;
880 result
= websocket_interface_
->SendMessage(ws
, reason
);
881 ASSERT_EQ(PP_ERROR_FAILED
, result
);
882 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
883 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
884 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
886 ReleaseVar(message_var
);
888 ReleaseVar(empty_string
);
889 core_interface_
->ReleaseResource(ws
);
894 // Test abort behaviors where a WebSocket PP_Resource is released while each
895 // function is in-flight on the WebSocket PP_Resource.
896 std::string
TestWebSocket::TestAbortCallsWithCallback() {
897 // Following tests make sure the behavior for functions which require a
898 // callback. The callback must get a PP_ERROR_ABORTED.
900 // Test the behavior for Connect().
901 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
903 std::string url
= GetFullURL(kEchoServerURL
);
904 PP_Var url_var
= CreateVarString(url
);
905 TestCompletionCallback
connect_callback(
906 instance_
->pp_instance(), callback_type());
907 int32_t result
= websocket_interface_
->Connect(
908 ws
, url_var
, NULL
, 0,
909 connect_callback
.GetCallback().pp_completion_callback());
910 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
911 core_interface_
->ReleaseResource(ws
);
912 connect_callback
.WaitForResult(result
);
913 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
915 // Test the behavior for Close().
916 ws
= Connect(url
, &result
, "");
918 ASSERT_EQ(PP_OK
, result
);
919 PP_Var reason_var
= CreateVarString("abort");
920 TestCompletionCallback
close_callback(
921 instance_
->pp_instance(), callback_type());
922 result
= websocket_interface_
->Close(
923 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
924 close_callback
.GetCallback().pp_completion_callback());
925 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
926 core_interface_
->ReleaseResource(ws
);
927 close_callback
.WaitForResult(result
);
928 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
929 ReleaseVar(reason_var
);
931 // Test the behavior for ReceiveMessage().
932 // Make sure the simplest case to wait for data which never arrives, here.
933 ws
= Connect(url
, &result
, "");
935 ASSERT_EQ(PP_OK
, result
);
937 TestCompletionCallback
receive_callback(
938 instance_
->pp_instance(), callback_type());
939 result
= websocket_interface_
->ReceiveMessage(
941 receive_callback
.GetCallback().pp_completion_callback());
942 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
943 core_interface_
->ReleaseResource(ws
);
944 receive_callback
.WaitForResult(result
);
945 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
947 // Release the resource in the aborting receive completion callback which is
948 // introduced by calling Close().
949 ws
= Connect(url
, &result
, "");
951 ASSERT_EQ(PP_OK
, result
);
952 result
= websocket_interface_
->ReceiveMessage(
954 receive_callback
.GetCallback().pp_completion_callback());
955 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
956 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
957 receive_callback
.SetDelegate(&receive_delegate
);
958 result
= websocket_interface_
->Close(
959 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
960 close_callback
.GetCallback().pp_completion_callback());
961 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
962 receive_callback
.WaitForResult(result
);
963 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
964 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
965 close_callback
.WaitForResult(result
);
966 CHECK_CALLBACK_BEHAVIOR(close_callback
);
967 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
974 std::string
TestWebSocket::TestAbortSendMessageCall() {
975 // Test the behavior for SendMessage().
976 // This function doesn't require a callback, but operation will be done
977 // asynchronously in WebKit and browser process.
978 std::vector
<uint8_t> large_binary(65 * 1024);
979 PP_Var large_var
= CreateVarBinary(large_binary
);
982 std::string url
= GetFullURL(kEchoServerURL
);
983 PP_Resource ws
= Connect(url
, &result
, "");
985 ASSERT_EQ(PP_OK
, result
);
986 result
= websocket_interface_
->SendMessage(ws
, large_var
);
987 ASSERT_EQ(PP_OK
, result
);
988 core_interface_
->ReleaseResource(ws
);
989 ReleaseVar(large_var
);
994 std::string
TestWebSocket::TestAbortCloseCall() {
995 // Release the resource in the close completion callback.
997 std::string url
= GetFullURL(kEchoServerURL
);
998 PP_Resource ws
= Connect(url
, &result
, "");
1000 ASSERT_EQ(PP_OK
, result
);
1001 TestCompletionCallback
close_callback(
1002 instance_
->pp_instance(), callback_type());
1003 result
= websocket_interface_
->Close(
1004 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1005 close_callback
.GetCallback().pp_completion_callback());
1006 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
1007 close_callback
.SetDelegate(&close_delegate
);
1008 close_callback
.WaitForResult(result
);
1009 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1010 ASSERT_EQ(PP_OK
, close_callback
.result());
1015 std::string
TestWebSocket::TestAbortReceiveMessageCall() {
1016 // Test the behavior where receive process might be in-flight.
1017 std::vector
<uint8_t> large_binary(65 * 1024);
1018 PP_Var large_var
= CreateVarBinary(large_binary
);
1019 const char* text
= "yukarin";
1020 PP_Var text_var
= CreateVarString(text
);
1022 std::string url
= GetFullURL(kEchoServerURL
);
1026 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1027 // number of message(s) before releasing the WebSocket. The WebSocket is
1028 // released while the next message is going to be received.
1029 const int trial_count
= 8;
1030 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1031 ws
= Connect(url
, &result
, "");
1033 ASSERT_EQ(PP_OK
, result
);
1034 for (int i
= 0; i
<= trial_count
; ++i
) {
1035 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1036 ASSERT_EQ(PP_OK
, result
);
1038 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1040 for (int i
= 0; i
< trial
; ++i
) {
1041 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1042 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1043 ASSERT_EQ(PP_OK
, callback
.result());
1044 ASSERT_TRUE(AreEqualWithString(var
, text
));
1047 result
= websocket_interface_
->ReceiveMessage(
1048 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1049 core_interface_
->ReleaseResource(ws
);
1050 if (result
!= PP_OK
) {
1051 callback
.WaitForResult(result
);
1052 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1055 // Same test, but the last receiving message is large message over 64KiB.
1056 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1057 ws
= Connect(url
, &result
, "");
1059 ASSERT_EQ(PP_OK
, result
);
1060 for (int i
= 0; i
<= trial_count
; ++i
) {
1062 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1064 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1065 ASSERT_EQ(PP_OK
, result
);
1067 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1069 for (int i
= 0; i
< trial
; ++i
) {
1070 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1071 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1072 ASSERT_EQ(PP_OK
, callback
.result());
1073 ASSERT_TRUE(AreEqualWithString(var
, text
));
1076 result
= websocket_interface_
->ReceiveMessage(
1077 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1078 core_interface_
->ReleaseResource(ws
);
1079 if (result
!= PP_OK
) {
1080 callback
.WaitForResult(result
);
1081 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1085 ReleaseVar(large_var
);
1086 ReleaseVar(text_var
);
1091 std::string
TestWebSocket::TestCcInterfaces() {
1092 // C++ bindings is simple straightforward, then just verifies interfaces work
1093 // as a interface bridge fine.
1094 pp::WebSocket
ws(instance_
);
1096 // Check uninitialized properties access.
1097 ASSERT_EQ(0, ws
.GetBufferedAmount());
1098 ASSERT_EQ(0, ws
.GetCloseCode());
1099 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), ""));
1100 ASSERT_EQ(false, ws
.GetCloseWasClean());
1101 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), ""));
1102 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), ""));
1103 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1104 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), ""));
1106 // Check communication interfaces (connect, send, receive, and close).
1107 TestCompletionCallback
connect_callback(
1108 instance_
->pp_instance(), callback_type());
1109 connect_callback
.WaitForResult(ws
.Connect(
1110 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U, connect_callback
));
1111 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1112 ASSERT_EQ(PP_OK
, connect_callback
.result());
1114 std::string
text_message("hello C++");
1115 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1116 ASSERT_EQ(PP_OK
, result
);
1118 std::vector
<uint8_t> binary(256);
1119 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1121 result
= ws
.SendMessage(
1122 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1123 ASSERT_EQ(PP_OK
, result
);
1125 pp::Var text_receive_var
;
1126 TestCompletionCallback
text_receive_callback(
1127 instance_
->pp_instance(), callback_type());
1128 text_receive_callback
.WaitForResult(
1129 ws
.ReceiveMessage(&text_receive_var
, text_receive_callback
));
1130 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1132 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1134 pp::Var binary_receive_var
;
1135 TestCompletionCallback
binary_receive_callback(
1136 instance_
->pp_instance(), callback_type());
1137 binary_receive_callback
.WaitForResult(
1138 ws
.ReceiveMessage(&binary_receive_var
, binary_receive_callback
));
1139 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1140 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1142 TestCompletionCallback
close_callback(
1143 instance_
->pp_instance(), callback_type());
1144 std::string
reason("bye");
1145 close_callback
.WaitForResult(ws
.Close(
1146 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
), close_callback
));
1147 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1148 ASSERT_EQ(PP_OK
, close_callback
.result());
1150 // Check initialized properties access.
1151 ASSERT_EQ(0, ws
.GetBufferedAmount());
1152 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1154 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1155 ASSERT_EQ(true, ws
.GetCloseWasClean());
1156 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), ""));
1157 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1158 ASSERT_TRUE(AreEqualWithString(
1159 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1164 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1165 const pp::Var protocols
[] = { pp::Var() };
1167 TestWebSocketAPI
websocket(instance_
);
1168 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1169 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1170 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1172 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1173 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1174 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1176 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1177 TestWebSocketAPI
ws(instance_
);
1178 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1179 if (result
== PP_OK_COMPLETIONPENDING
) {
1181 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1182 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1183 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1184 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1186 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1187 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1194 std::string
TestWebSocket::TestUtilityProtocols() {
1195 const pp::Var bad_protocols
[] = {
1196 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1197 const pp::Var good_protocols
[] = {
1198 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1201 TestWebSocketAPI
websocket(instance_
);
1202 int32_t result
= websocket
.Connect(
1203 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1204 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1205 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1209 TestWebSocketAPI
websocket(instance_
);
1210 int32_t result
= websocket
.Connect(
1211 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1212 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1213 websocket
.WaitForConnected();
1214 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1215 // Protocol arguments are valid, but this test run without a WebSocket
1216 // server. As a result, OnError() and OnClose() are invoked because of
1217 // a connection establishment failure.
1218 ASSERT_EQ(2U, events
.size());
1219 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1220 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1221 ASSERT_FALSE(events
[1].was_clean
);
1227 std::string
TestWebSocket::TestUtilityGetURL() {
1228 const pp::Var protocols
[] = { pp::Var() };
1230 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1231 TestWebSocketAPI
websocket(instance_
);
1232 int32_t result
= websocket
.Connect(
1233 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1234 if (result
== PP_OK_COMPLETIONPENDING
) {
1235 websocket
.WaitForClosed();
1236 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1237 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1238 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1239 ASSERT_EQ(2U, events
.size());
1241 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1242 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1244 pp::Var url
= websocket
.GetURL();
1245 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1251 std::string
TestWebSocket::TestUtilityValidConnect() {
1252 const pp::Var protocols
[] = { pp::Var() };
1253 TestWebSocketAPI
websocket(instance_
);
1254 int32_t result
= websocket
.Connect(
1255 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1256 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1257 websocket
.WaitForConnected();
1258 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1259 ASSERT_EQ(1U, events
.size());
1260 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1261 ASSERT_TRUE(AreEqualWithString(websocket
.GetExtensions().pp_var(), ""));
1266 std::string
TestWebSocket::TestUtilityInvalidClose() {
1267 const pp::Var reason
= pp::Var(std::string("close for test"));
1269 // Close before connect.
1271 TestWebSocketAPI
websocket(instance_
);
1272 int32_t result
= websocket
.Close(
1273 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1274 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1275 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1278 // Close with bad arguments.
1280 TestWebSocketAPI
websocket(instance_
);
1281 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1283 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1284 websocket
.WaitForConnected();
1285 result
= websocket
.Close(1U, reason
);
1286 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1287 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1288 ASSERT_EQ(1U, events
.size());
1289 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1295 std::string
TestWebSocket::TestUtilityValidClose() {
1296 std::string
reason("close for test");
1297 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1301 TestWebSocketAPI
websocket(instance_
);
1302 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1303 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1304 websocket
.WaitForConnected();
1305 result
= websocket
.Close(
1306 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1307 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1308 websocket
.WaitForClosed();
1309 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1310 ASSERT_EQ(2U, events
.size());
1311 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1312 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1313 ASSERT_TRUE(events
[1].was_clean
);
1314 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1315 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1318 // Close in connecting.
1319 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1322 TestWebSocketAPI
websocket(instance_
);
1323 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1324 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1325 result
= websocket
.Close(
1326 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1327 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1328 websocket
.WaitForClosed();
1329 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1330 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1332 if (events
.size() == 3)
1333 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1334 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1335 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1336 ASSERT_FALSE(events
[index
].was_clean
);
1339 // Close in closing.
1340 // The first close will be done successfully, then the second one failed with
1341 // with PP_ERROR_INPROGRESS immediately.
1343 TestWebSocketAPI
websocket(instance_
);
1344 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1345 result
= websocket
.Close(
1346 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1347 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1348 result
= websocket
.Close(
1349 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1350 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1351 websocket
.WaitForClosed();
1352 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1353 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3)
1355 if (events
.size() == 3)
1356 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1357 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1358 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1359 ASSERT_FALSE(events
[index
].was_clean
);
1365 std::string
TestWebSocket::TestUtilityGetProtocol() {
1366 const std::string
protocol("x-chat");
1367 const pp::Var protocols
[] = { pp::Var(protocol
) };
1368 std::string
url(GetFullURL(kProtocolTestServerURL
));
1370 TestWebSocketAPI
websocket(instance_
);
1371 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1372 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1373 websocket
.WaitForReceived();
1374 ASSERT_TRUE(AreEqualWithString(
1375 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1376 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1377 // The server to which this test connect returns the decided protocol as a
1378 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1379 // after EVENT_OPEN event.
1380 ASSERT_EQ(2U, events
.size());
1381 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1382 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1383 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1388 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1389 const pp::Var protocols
[] = { pp::Var() };
1390 TestWebSocketAPI
websocket(instance_
);
1392 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1393 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1394 websocket
.WaitForConnected();
1396 // Send 'hello pepper'.
1397 std::string
message1("hello pepper");
1398 result
= websocket
.Send(pp::Var(std::string(message1
)));
1399 ASSERT_EQ(PP_OK
, result
);
1401 // Receive echoed 'hello pepper'.
1402 websocket
.WaitForReceived();
1404 // Send 'goodbye pepper'.
1405 std::string
message2("goodbye pepper");
1406 result
= websocket
.Send(pp::Var(std::string(message2
)));
1408 // Receive echoed 'goodbye pepper'.
1409 websocket
.WaitForReceived();
1411 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1412 ASSERT_EQ(3U, events
.size());
1413 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1414 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1415 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), message1
.c_str()));
1416 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1417 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1422 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1423 const pp::Var protocols
[] = { pp::Var() };
1424 TestWebSocketAPI
websocket(instance_
);
1426 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1427 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1428 websocket
.WaitForConnected();
1430 // Send binary message.
1432 std::vector
<uint8_t> binary(len
);
1433 for (uint32_t i
= 0; i
< len
; ++i
)
1435 pp::VarArrayBuffer
message(len
);
1436 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1437 std::copy(binary
.begin(), binary
.end(), var_data
);
1438 result
= websocket
.Send(message
);
1439 ASSERT_EQ(PP_OK
, result
);
1441 // Receive echoed binary message.
1442 websocket
.WaitForReceived();
1444 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1445 ASSERT_EQ(2U, events
.size());
1446 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1447 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1448 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1453 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1454 // Connect to test echo server.
1455 const pp::Var protocols
[] = { pp::Var() };
1456 TestWebSocketAPI
websocket(instance_
);
1458 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1459 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1460 websocket
.WaitForConnected();
1462 // Prepare a large message that is not aligned with the internal buffer
1464 std::string
message(8193, 'x');
1465 uint64_t buffered_amount
= 0;
1467 for (sent
= 0; sent
< 100; sent
++) {
1468 result
= websocket
.Send(pp::Var(message
));
1469 ASSERT_EQ(PP_OK
, result
);
1470 buffered_amount
= websocket
.GetBufferedAmount();
1471 // Buffered amount size 262144 is too big for the internal buffer size.
1472 if (buffered_amount
> 262144)
1476 // Close connection.
1477 std::string reason
= "close while busy";
1478 result
= websocket
.Close(
1479 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1480 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1481 websocket
.WaitForClosed();
1482 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1484 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1485 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1487 // After connection closure, all sending requests fail and just increase
1488 // the bufferedAmount property.
1489 result
= websocket
.Send(pp::Var(std::string("")));
1490 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1491 buffered_amount
= websocket
.GetBufferedAmount();
1492 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1493 base_buffered_amount
= buffered_amount
;
1495 result
= websocket
.Send(pp::Var(reason
));
1496 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1497 buffered_amount
= websocket
.GetBufferedAmount();
1498 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1499 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1501 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1502 ASSERT_EQ(events_on_closed
, events
.size());
1503 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1504 size_t last_event
= events_on_closed
- 1;
1505 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1506 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1507 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1509 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1510 ASSERT_TRUE(events
[last_event
].was_clean
);