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/pp_bool.h"
16 #include "ppapi/c/pp_completion_callback.h"
17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/c/pp_instance.h"
19 #include "ppapi/c/pp_resource.h"
20 #include "ppapi/c/pp_var.h"
21 #include "ppapi/c/ppb_core.h"
22 #include "ppapi/c/ppb_var.h"
23 #include "ppapi/c/ppb_var_array_buffer.h"
24 #include "ppapi/c/ppb_websocket.h"
25 #include "ppapi/c/private/ppb_testing_private.h"
26 #include "ppapi/cpp/instance.h"
27 #include "ppapi/cpp/module.h"
28 #include "ppapi/cpp/var_array_buffer.h"
29 #include "ppapi/cpp/websocket.h"
30 #include "ppapi/tests/test_utils.h"
31 #include "ppapi/tests/testing_instance.h"
32 #include "ppapi/utility/websocket/websocket_api.h"
34 // net::SpawnedTestServer serves WebSocket service for testing.
35 // Following URLs are handled by pywebsocket handlers in
36 // net/data/websocket/*_wsh.py.
37 const char kEchoServerURL
[] = "echo-with-no-extension";
38 const char kCloseServerURL
[] = "close";
39 const char kCloseWithCodeAndReasonServerURL
[] = "close-code-and-reason";
40 const char kProtocolTestServerURL
[] = "protocol-test?protocol=";
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 kMessageFrameOverhead
= 6;
54 struct WebSocketEvent
{
62 WebSocketEvent(EventType type
,
68 close_code(close_code
),
77 class ReleaseResourceDelegate
: public TestCompletionCallback::Delegate
{
79 explicit ReleaseResourceDelegate(const PPB_Core
* core_interface
,
81 : core_interface_(core_interface
),
85 // TestCompletionCallback::Delegate implementation.
86 virtual void OnCallback(void* user_data
, int32_t result
) {
88 core_interface_
->ReleaseResource(resource_
);
92 const PPB_Core
* core_interface_
;
93 PP_Resource resource_
;
96 class TestWebSocketAPI
: public pp::WebSocketAPI
{
98 explicit TestWebSocketAPI(pp::Instance
* instance
)
99 : pp::WebSocketAPI(instance
),
103 wait_for_connected_(false),
104 wait_for_received_(false),
105 wait_for_closed_(false),
106 instance_(instance
->pp_instance()) {
109 virtual void WebSocketDidOpen() {
111 WebSocketEvent(WebSocketEvent::EVENT_OPEN
, true, 0U, pp::Var()));
113 if (wait_for_connected_
) {
114 GetTestingInterface()->QuitMessageLoop(instance_
);
115 wait_for_connected_
= false;
119 virtual void WebSocketDidClose(
120 bool was_clean
, uint16_t code
, const pp::Var
& reason
) {
122 WebSocketEvent(WebSocketEvent::EVENT_CLOSE
, was_clean
, code
, reason
));
125 if (wait_for_connected_
|| wait_for_closed_
) {
126 GetTestingInterface()->QuitMessageLoop(instance_
);
127 wait_for_connected_
= false;
128 wait_for_closed_
= false;
132 virtual void HandleWebSocketMessage(const pp::Var
&message
) {
134 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE
, true, 0U, message
));
136 if (wait_for_received_
) {
137 GetTestingInterface()->QuitMessageLoop(instance_
);
138 wait_for_received_
= false;
143 virtual void HandleWebSocketError() {
145 WebSocketEvent(WebSocketEvent::EVENT_ERROR
, true, 0U, pp::Var()));
148 void WaitForConnected() {
150 wait_for_connected_
= true;
151 GetTestingInterface()->RunMessageLoop(instance_
);
155 void WaitForReceived() {
157 wait_for_received_
= true;
158 GetTestingInterface()->RunMessageLoop(instance_
);
162 void WaitForClosed() {
164 wait_for_closed_
= true;
165 GetTestingInterface()->RunMessageLoop(instance_
);
169 const std::vector
<WebSocketEvent
>& GetSeenEvents() const {
174 std::vector
<WebSocketEvent
> events_
;
178 bool wait_for_connected_
;
179 bool wait_for_received_
;
180 bool wait_for_closed_
;
181 PP_Instance instance_
;
186 REGISTER_TEST_CASE(WebSocket
);
188 bool TestWebSocket::Init() {
189 websocket_interface_
= static_cast<const PPB_WebSocket
*>(
190 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE
));
191 var_interface_
= static_cast<const PPB_Var
*>(
192 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
193 arraybuffer_interface_
= static_cast<const PPB_VarArrayBuffer
*>(
194 pp::Module::Get()->GetBrowserInterface(
195 PPB_VAR_ARRAY_BUFFER_INTERFACE
));
196 core_interface_
= static_cast<const PPB_Core
*>(
197 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
198 if (!websocket_interface_
|| !var_interface_
|| !arraybuffer_interface_
||
202 return CheckTestingInterface();
205 void TestWebSocket::RunTests(const std::string
& filter
) {
206 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket
, filter
);
207 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess
, filter
);
208 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect
, filter
);
209 RUN_TEST_WITH_REFERENCE_CHECK(Protocols
, filter
);
210 RUN_TEST_WITH_REFERENCE_CHECK(GetURL
, filter
);
211 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect
, filter
);
212 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose
, filter
);
213 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose
, filter
);
214 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol
, filter
);
215 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive
, filter
);
216 RUN_TEST_BACKGROUND(TestWebSocket
, TextSendReceiveTwice
, filter
);
217 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive
, filter
);
218 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive
, filter
);
219 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount
, filter
);
220 // PP_Resource for WebSocket may be released later because of an internal
221 // reference for asynchronous IPC handling. So, suppress reference check on
222 // the following AbortCallsWithCallback test.
223 RUN_TEST(AbortCallsWithCallback
, filter
);
224 RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall
, filter
);
225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall
, filter
);
226 RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall
, filter
);
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://";
244 // Some WebSocket tests don't start the server so there'll be no host and
246 if (instance_
->websocket_host().empty())
249 rv
+= instance_
->websocket_host();
250 if (instance_
->websocket_port() != -1) {
252 sprintf(buffer
, ":%d", instance_
->websocket_port());
253 rv
+= std::string(buffer
);
260 PP_Var
TestWebSocket::CreateVarString(const std::string
& string
) {
261 return var_interface_
->VarFromUtf8(string
.c_str(), string
.size());
264 PP_Var
TestWebSocket::CreateVarBinary(const std::vector
<uint8_t>& binary
) {
265 PP_Var var
= arraybuffer_interface_
->Create(binary
.size());
266 uint8_t* var_data
= static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
));
267 std::copy(binary
.begin(), binary
.end(), var_data
);
271 void TestWebSocket::ReleaseVar(const PP_Var
& var
) {
272 var_interface_
->Release(var
);
275 bool TestWebSocket::AreEqualWithString(const PP_Var
& var
,
276 const std::string
& string
) {
277 if (var
.type
!= PP_VARTYPE_STRING
)
279 uint32_t utf8_length
;
280 const char* utf8
= var_interface_
->VarToUtf8(var
, &utf8_length
);
281 if (utf8_length
!= string
.size())
283 if (string
.compare(utf8
))
288 bool TestWebSocket::AreEqualWithBinary(const PP_Var
& var
,
289 const std::vector
<uint8_t>& binary
) {
290 uint32_t buffer_size
= 0;
291 PP_Bool success
= arraybuffer_interface_
->ByteLength(var
, &buffer_size
);
292 if (!success
|| buffer_size
!= binary
.size())
294 if (!std::equal(binary
.begin(), binary
.end(),
295 static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
))))
300 PP_Resource
TestWebSocket::Connect(const std::string
& url
,
302 const std::string
& protocol
) {
303 PP_Var protocols
[] = { PP_MakeUndefined() };
304 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
307 PP_Var url_var
= CreateVarString(url
);
308 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
309 uint32_t protocol_count
= 0U;
310 if (protocol
.size()) {
311 protocols
[0] = CreateVarString(protocol
);
314 callback
.WaitForResult(websocket_interface_
->Connect(
315 ws
, url_var
, protocols
, protocol_count
,
316 callback
.GetCallback().pp_completion_callback()));
319 ReleaseVar(protocols
[0]);
320 *result
= callback
.result();
324 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws
,
325 const std::string
& message
) {
326 PP_Var message_var
= CreateVarString(message
);
327 websocket_interface_
->SendMessage(ws
, message_var
);
328 ReleaseVar(message_var
);
331 std::string
TestWebSocket::TestIsWebSocket() {
332 // Test that a NULL resource isn't a websocket.
333 pp::Resource null_resource
;
335 websocket_interface_
->IsWebSocket(null_resource
.pp_resource());
336 ASSERT_FALSE(result
);
338 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
341 result
= websocket_interface_
->IsWebSocket(ws
);
344 core_interface_
->ReleaseResource(ws
);
349 std::string
TestWebSocket::TestUninitializedPropertiesAccess() {
350 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
353 uint64_t bufferedAmount
= websocket_interface_
->GetBufferedAmount(ws
);
354 ASSERT_EQ(0U, bufferedAmount
);
356 uint16_t close_code
= websocket_interface_
->GetCloseCode(ws
);
357 ASSERT_EQ(0U, close_code
);
359 PP_Var close_reason
= websocket_interface_
->GetCloseReason(ws
);
360 ASSERT_TRUE(AreEqualWithString(close_reason
, std::string()));
361 ReleaseVar(close_reason
);
363 PP_Bool close_was_clean
= websocket_interface_
->GetCloseWasClean(ws
);
364 ASSERT_EQ(PP_FALSE
, close_was_clean
);
366 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
367 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
368 ReleaseVar(extensions
);
370 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
371 ASSERT_TRUE(AreEqualWithString(protocol
, std::string()));
372 ReleaseVar(protocol
);
374 PP_WebSocketReadyState ready_state
=
375 websocket_interface_
->GetReadyState(ws
);
376 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ready_state
);
378 PP_Var url
= websocket_interface_
->GetURL(ws
);
379 ASSERT_TRUE(AreEqualWithString(url
, std::string()));
382 core_interface_
->ReleaseResource(ws
);
387 std::string
TestWebSocket::TestInvalidConnect() {
388 PP_Var protocols
[] = { PP_MakeUndefined() };
390 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
393 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
394 callback
.WaitForResult(websocket_interface_
->Connect(
395 ws
, PP_MakeUndefined(), protocols
, 1U,
396 callback
.GetCallback().pp_completion_callback()));
397 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
399 callback
.WaitForResult(websocket_interface_
->Connect(
400 ws
, PP_MakeUndefined(), protocols
, 1U,
401 callback
.GetCallback().pp_completion_callback()));
402 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback
.result());
404 core_interface_
->ReleaseResource(ws
);
406 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
408 ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
410 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
412 core_interface_
->ReleaseResource(ws
);
418 std::string
TestWebSocket::TestProtocols() {
419 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
420 PP_Var bad_protocols
[] = {
421 CreateVarString("x-test"),
422 CreateVarString("x-test")
424 PP_Var good_protocols
[] = {
425 CreateVarString("x-test"),
426 CreateVarString("x-yatest")
429 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
431 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
432 callback
.WaitForResult(websocket_interface_
->Connect(
433 ws
, url
, bad_protocols
, 2U,
434 callback
.GetCallback().pp_completion_callback()));
435 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
436 core_interface_
->ReleaseResource(ws
);
438 ws
= websocket_interface_
->Create(instance_
->pp_instance());
440 int32_t result
= websocket_interface_
->Connect(
441 ws
, url
, good_protocols
, 2U, PP_BlockUntilComplete());
442 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, result
);
443 core_interface_
->ReleaseResource(ws
);
446 for (int i
= 0; i
< 2; ++i
) {
447 ReleaseVar(bad_protocols
[i
]);
448 ReleaseVar(good_protocols
[i
]);
450 core_interface_
->ReleaseResource(ws
);
455 std::string
TestWebSocket::TestGetURL() {
456 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
458 PP_Resource ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
460 PP_Var url
= websocket_interface_
->GetURL(ws
);
461 ASSERT_TRUE(AreEqualWithString(url
, kInvalidURLs
[i
]));
462 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
465 core_interface_
->ReleaseResource(ws
);
471 std::string
TestWebSocket::TestValidConnect() {
473 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
475 ASSERT_EQ(PP_OK
, result
);
476 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
477 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
478 core_interface_
->ReleaseResource(ws
);
479 ReleaseVar(extensions
);
484 std::string
TestWebSocket::TestInvalidClose() {
485 PP_Var reason
= CreateVarString("close for test");
486 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
487 TestCompletionCallback
async_callback(instance_
->pp_instance(), PP_REQUIRED
);
489 // Close before connect.
490 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
491 callback
.WaitForResult(websocket_interface_
->Close(
492 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
493 callback
.GetCallback().pp_completion_callback()));
494 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
495 core_interface_
->ReleaseResource(ws
);
497 // Close with bad arguments.
499 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
501 ASSERT_EQ(PP_OK
, result
);
502 callback
.WaitForResult(websocket_interface_
->Close(
503 ws
, 1U, reason
, callback
.GetCallback().pp_completion_callback()));
504 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
505 core_interface_
->ReleaseResource(ws
);
507 // Close with PP_VARTYPE_NULL.
508 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
510 ASSERT_EQ(PP_OK
, result
);
511 callback
.WaitForResult(websocket_interface_
->Close(
512 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
513 callback
.GetCallback().pp_completion_callback()));
514 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
515 core_interface_
->ReleaseResource(ws
);
517 // Close with PP_VARTYPE_NULL and ongoing receive message.
518 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
520 ASSERT_EQ(PP_OK
, result
);
521 PP_Var receive_message_var
;
522 result
= websocket_interface_
->ReceiveMessage(
523 ws
, &receive_message_var
,
524 async_callback
.GetCallback().pp_completion_callback());
525 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
526 callback
.WaitForResult(websocket_interface_
->Close(
527 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
528 callback
.GetCallback().pp_completion_callback()));
529 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
530 const char* send_message
= "hi";
531 PP_Var send_message_var
= CreateVarString(send_message
);
532 result
= websocket_interface_
->SendMessage(ws
, send_message_var
);
533 ReleaseVar(send_message_var
);
534 ASSERT_EQ(PP_OK
, result
);
535 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
536 ASSERT_EQ(PP_OK
, async_callback
.result());
537 ASSERT_TRUE(AreEqualWithString(receive_message_var
, send_message
));
538 ReleaseVar(receive_message_var
);
539 core_interface_
->ReleaseResource(ws
);
542 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
544 ASSERT_EQ(PP_OK
, result
);
545 result
= websocket_interface_
->Close(
546 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
547 async_callback
.GetCallback().pp_completion_callback());
548 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
549 // Call another Close() before previous one is in progress.
550 result
= websocket_interface_
->Close(
551 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
552 callback
.GetCallback().pp_completion_callback());
553 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
554 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
555 ASSERT_EQ(PP_OK
, async_callback
.result());
556 // Call another Close() after previous one is completed.
557 // This Close() must do nothing and reports no error.
558 callback
.WaitForResult(websocket_interface_
->Close(
559 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
560 callback
.GetCallback().pp_completion_callback()));
561 ASSERT_EQ(PP_OK
, callback
.result());
562 core_interface_
->ReleaseResource(ws
);
569 std::string
TestWebSocket::TestValidClose() {
570 PP_Var reason
= CreateVarString("close for test");
571 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
572 PP_Var protocols
[] = { PP_MakeUndefined() };
573 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
574 TestCompletionCallback
another_callback(
575 instance_
->pp_instance(), callback_type());
579 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
581 ASSERT_EQ(PP_OK
, result
);
582 callback
.WaitForResult(websocket_interface_
->Close(
583 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
584 callback
.GetCallback().pp_completion_callback()));
585 CHECK_CALLBACK_BEHAVIOR(callback
);
586 ASSERT_EQ(PP_OK
, callback
.result());
587 core_interface_
->ReleaseResource(ws
);
589 // Close without code and reason.
590 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
592 ASSERT_EQ(PP_OK
, result
);
593 callback
.WaitForResult(websocket_interface_
->Close(
594 ws
, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED
, reason
,
595 callback
.GetCallback().pp_completion_callback()));
596 ASSERT_EQ(PP_OK
, callback
.result());
597 core_interface_
->ReleaseResource(ws
);
599 // Close with PP_VARTYPE_UNDEFINED.
600 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
602 ASSERT_EQ(PP_OK
, result
);
603 callback
.WaitForResult(websocket_interface_
->Close(
604 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
605 callback
.GetCallback().pp_completion_callback()));
606 CHECK_CALLBACK_BEHAVIOR(callback
);
607 ASSERT_EQ(PP_OK
, callback
.result());
608 core_interface_
->ReleaseResource(ws
);
610 // Close in connecting.
611 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
613 ws
= websocket_interface_
->Create(instance_
->pp_instance());
614 result
= websocket_interface_
->Connect(
615 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
616 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
617 result
= websocket_interface_
->Close(
618 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
619 another_callback
.GetCallback().pp_completion_callback());
620 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
621 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
622 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
623 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
624 ASSERT_EQ(PP_OK
, another_callback
.result());
625 core_interface_
->ReleaseResource(ws
);
628 // The first close will be done successfully, then the second one failed with
629 // with PP_ERROR_INPROGRESS immediately.
630 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
632 ASSERT_EQ(PP_OK
, result
);
633 result
= websocket_interface_
->Close(
634 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
635 callback
.GetCallback().pp_completion_callback());
636 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
637 result
= websocket_interface_
->Close(
638 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
639 another_callback
.GetCallback().pp_completion_callback());
640 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
641 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
642 ASSERT_EQ(PP_OK
, callback
.result());
643 core_interface_
->ReleaseResource(ws
);
645 // Close with ongoing receive message.
646 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
648 ASSERT_EQ(PP_OK
, result
);
649 PP_Var receive_message_var
;
650 result
= websocket_interface_
->ReceiveMessage(
651 ws
, &receive_message_var
,
652 callback
.GetCallback().pp_completion_callback());
653 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
654 result
= websocket_interface_
->Close(
655 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
656 another_callback
.GetCallback().pp_completion_callback());
657 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
658 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
659 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
660 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
661 ASSERT_EQ(PP_OK
, another_callback
.result());
662 core_interface_
->ReleaseResource(ws
);
664 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
665 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
667 ASSERT_EQ(PP_OK
, result
);
668 result
= websocket_interface_
->ReceiveMessage(
669 ws
, &receive_message_var
,
670 callback
.GetCallback().pp_completion_callback());
671 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
672 result
= websocket_interface_
->Close(
673 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
674 another_callback
.GetCallback().pp_completion_callback());
675 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
676 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
677 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
678 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
679 ASSERT_EQ(PP_OK
, another_callback
.result());
680 core_interface_
->ReleaseResource(ws
);
682 // Server initiated closing handshake.
684 GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, std::string());
686 ASSERT_EQ(PP_OK
, result
);
687 // Text messsage "1000 bye" requests the server to initiate closing handshake
688 // with code being 1000 and reason being "bye".
689 PP_Var close_request_var
= CreateVarString("1000 bye");
690 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
691 ReleaseVar(close_request_var
);
692 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
693 ws
, &receive_message_var
,
694 callback
.GetCallback().pp_completion_callback()));
695 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
696 core_interface_
->ReleaseResource(ws
);
704 std::string
TestWebSocket::TestGetProtocol() {
705 const char* expected_protocols
[] = {
710 for (int i
= 0; expected_protocols
[i
]; ++i
) {
711 std::string
url(GetFullURL(kProtocolTestServerURL
));
712 url
+= expected_protocols
[i
];
714 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
716 ASSERT_EQ(PP_OK
, result
);
718 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
719 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
721 ReleaseVar(protocol
);
722 core_interface_
->ReleaseResource(ws
);
728 std::string
TestWebSocket::TestTextSendReceive() {
729 // Connect to test echo server.
730 int32_t connect_result
;
732 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
734 ASSERT_EQ(PP_OK
, connect_result
);
736 // Send 'hello pepper' text message.
737 const char* message
= "hello pepper";
738 PP_Var message_var
= CreateVarString(message
);
739 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
740 ReleaseVar(message_var
);
741 ASSERT_EQ(PP_OK
, result
);
743 // Receive echoed 'hello pepper'.
744 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
745 PP_Var received_message
;
746 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
747 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
748 ASSERT_EQ(PP_OK
, callback
.result());
749 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
750 ReleaseVar(received_message
);
751 core_interface_
->ReleaseResource(ws
);
756 // Run as a BACKGROUND test.
757 std::string
TestWebSocket::TestTextSendReceiveTwice() {
758 // Connect to test echo server.
759 int32_t connect_result
;
761 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
763 ASSERT_EQ(PP_OK
, connect_result
);
764 pp::MessageLoop message_loop
= pp::MessageLoop::GetCurrent();
765 pp::CompletionCallbackFactory
<TestWebSocket
> factory(this);
767 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
768 ws
, std::string("hello")));
769 // When the server receives 'Goodbye', it closes the session.
770 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
771 ws
, std::string("Goodbye")));
772 message_loop
.PostQuit(false);
775 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
776 PP_Var received_message
;
777 int32_t result
= websocket_interface_
->ReceiveMessage(
778 ws
, &received_message
, callback
.GetCallback().pp_completion_callback());
779 ASSERT_EQ(PP_OK
, result
);
780 // Since we don't run the message loop, the callback will stay
781 // "pending and scheduled to run" state.
783 // Waiting for the connection close which will be done by the server.
785 PP_WebSocketReadyState ready_state
=
786 websocket_interface_
->GetReadyState(ws
);
787 if (ready_state
!= PP_WEBSOCKETREADYSTATE_CONNECTING
&&
788 ready_state
!= PP_WEBSOCKETREADYSTATE_OPEN
) {
791 PlatformSleep(100); // 100ms
794 // Cleanup the message loop
795 message_loop
.PostQuit(false);
798 ASSERT_EQ(PP_OK
, callback
.result());
799 ASSERT_TRUE(AreEqualWithString(received_message
, "hello"));
800 ReleaseVar(received_message
);
801 core_interface_
->ReleaseResource(ws
);
805 std::string
TestWebSocket::TestBinarySendReceive() {
806 // Connect to test echo server.
807 int32_t connect_result
;
809 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
811 ASSERT_EQ(PP_OK
, connect_result
);
813 // Send binary message.
814 std::vector
<uint8_t> binary(256);
815 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
817 PP_Var message_var
= CreateVarBinary(binary
);
818 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
819 ReleaseVar(message_var
);
820 ASSERT_EQ(PP_OK
, result
);
822 // Receive echoed binary.
823 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
824 PP_Var received_message
;
825 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
826 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
827 ASSERT_EQ(PP_OK
, callback
.result());
828 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
829 ReleaseVar(received_message
);
830 core_interface_
->ReleaseResource(ws
);
835 std::string
TestWebSocket::TestStressedSendReceive() {
836 // Connect to test echo server.
837 int32_t connect_result
;
839 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
841 ASSERT_EQ(PP_OK
, connect_result
);
843 // Prepare PP_Var objects to send.
844 const char* text
= "hello pepper";
845 PP_Var text_var
= CreateVarString(text
);
846 std::vector
<uint8_t> binary(256);
847 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
849 PP_Var binary_var
= CreateVarBinary(binary
);
850 // Prepare very large binary data over 64KiB. Object serializer in
851 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
852 // to SRPC. In case received data over 64KiB exists, a specific code handles
853 // this large data via asynchronous callback from main thread. This data
854 // intends to test the code.
855 std::vector
<uint8_t> large_binary(65 * 1024);
856 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
857 large_binary
[i
] = i
& 0xff;
858 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
860 // Send many messages.
862 for (int i
= 0; i
< 256; ++i
) {
863 result
= websocket_interface_
->SendMessage(ws
, text_var
);
864 ASSERT_EQ(PP_OK
, result
);
865 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
866 ASSERT_EQ(PP_OK
, result
);
868 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
869 ASSERT_EQ(PP_OK
, result
);
870 ReleaseVar(text_var
);
871 ReleaseVar(binary_var
);
872 ReleaseVar(large_binary_var
);
874 // Receive echoed data.
875 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
876 for (int i
= 0; i
<= 512; ++i
) {
877 PP_Var received_message
;
878 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
879 ws
, &received_message
,
880 callback
.GetCallback().pp_completion_callback()));
881 ASSERT_EQ(PP_OK
, callback
.result());
883 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
885 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
887 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
889 ReleaseVar(received_message
);
891 core_interface_
->ReleaseResource(ws
);
896 std::string
TestWebSocket::TestBufferedAmount() {
897 // Connect to test echo server.
898 int32_t connect_result
;
900 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
902 ASSERT_EQ(PP_OK
, connect_result
);
904 // Prepare a large message that is not aligned with the internal buffer
906 std::string
message(8193, 'x');
907 PP_Var message_var
= CreateVarString(message
);
909 uint64_t buffered_amount
= 0;
911 for (int i
= 0; i
< 100; i
++) {
912 result
= websocket_interface_
->SendMessage(ws
, message_var
);
913 ASSERT_EQ(PP_OK
, result
);
914 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
915 // Buffered amount size 262144 is too big for the internal buffer size.
916 if (buffered_amount
> 262144)
921 std::string reason_str
= "close while busy";
922 PP_Var reason
= CreateVarString(reason_str
.c_str());
923 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
924 result
= websocket_interface_
->Close(
925 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
926 callback
.GetCallback().pp_completion_callback());
927 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
928 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
929 websocket_interface_
->GetReadyState(ws
));
931 callback
.WaitForResult(result
);
932 ASSERT_EQ(PP_OK
, callback
.result());
933 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
934 websocket_interface_
->GetReadyState(ws
));
936 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
938 // After connection closure, all sending requests fail and just increase
939 // the bufferedAmount property.
940 PP_Var empty_string
= CreateVarString(std::string());
941 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
942 ASSERT_EQ(PP_ERROR_FAILED
, result
);
943 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
944 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
945 base_buffered_amount
= buffered_amount
;
947 result
= websocket_interface_
->SendMessage(ws
, reason
);
948 ASSERT_EQ(PP_ERROR_FAILED
, result
);
949 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
950 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
951 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
953 ReleaseVar(message_var
);
955 ReleaseVar(empty_string
);
956 core_interface_
->ReleaseResource(ws
);
961 // Test abort behaviors where a WebSocket PP_Resource is released while each
962 // function is in-flight on the WebSocket PP_Resource.
963 std::string
TestWebSocket::TestAbortCallsWithCallback() {
964 // Following tests make sure the behavior for functions which require a
965 // callback. The callback must get a PP_ERROR_ABORTED.
967 // Test the behavior for Connect().
968 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
970 std::string url
= GetFullURL(kEchoServerURL
);
971 PP_Var url_var
= CreateVarString(url
);
972 TestCompletionCallback
connect_callback(
973 instance_
->pp_instance(), callback_type());
974 int32_t result
= websocket_interface_
->Connect(
975 ws
, url_var
, NULL
, 0,
976 connect_callback
.GetCallback().pp_completion_callback());
977 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
978 core_interface_
->ReleaseResource(ws
);
979 connect_callback
.WaitForResult(result
);
980 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
982 // Test the behavior for Close().
983 ws
= Connect(url
, &result
, std::string());
985 ASSERT_EQ(PP_OK
, result
);
986 PP_Var reason_var
= CreateVarString("abort");
987 TestCompletionCallback
close_callback(
988 instance_
->pp_instance(), callback_type());
989 result
= websocket_interface_
->Close(
990 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
991 close_callback
.GetCallback().pp_completion_callback());
992 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
993 core_interface_
->ReleaseResource(ws
);
994 close_callback
.WaitForResult(result
);
995 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
996 ReleaseVar(reason_var
);
998 // Test the behavior for ReceiveMessage().
999 // Make sure the simplest case to wait for data which never arrives, here.
1000 ws
= Connect(url
, &result
, std::string());
1002 ASSERT_EQ(PP_OK
, result
);
1004 TestCompletionCallback
receive_callback(
1005 instance_
->pp_instance(), callback_type());
1006 result
= websocket_interface_
->ReceiveMessage(
1008 receive_callback
.GetCallback().pp_completion_callback());
1009 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1010 core_interface_
->ReleaseResource(ws
);
1011 receive_callback
.WaitForResult(result
);
1012 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1014 // Release the resource in the aborting receive completion callback which is
1015 // introduced by calling Close().
1016 ws
= Connect(url
, &result
, std::string());
1018 ASSERT_EQ(PP_OK
, result
);
1019 result
= websocket_interface_
->ReceiveMessage(
1021 receive_callback
.GetCallback().pp_completion_callback());
1022 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1023 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
1024 receive_callback
.SetDelegate(&receive_delegate
);
1025 result
= websocket_interface_
->Close(
1026 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1027 close_callback
.GetCallback().pp_completion_callback());
1028 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1029 receive_callback
.WaitForResult(result
);
1030 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
1031 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1032 close_callback
.WaitForResult(result
);
1033 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1034 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1036 ReleaseVar(url_var
);
1041 std::string
TestWebSocket::TestAbortSendMessageCall() {
1042 // Test the behavior for SendMessage().
1043 // This function doesn't require a callback, but operation will be done
1044 // asynchronously in WebKit and browser process.
1045 std::vector
<uint8_t> large_binary(65 * 1024);
1046 PP_Var large_var
= CreateVarBinary(large_binary
);
1049 std::string url
= GetFullURL(kEchoServerURL
);
1050 PP_Resource ws
= Connect(url
, &result
, std::string());
1052 ASSERT_EQ(PP_OK
, result
);
1053 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1054 ASSERT_EQ(PP_OK
, result
);
1055 core_interface_
->ReleaseResource(ws
);
1056 ReleaseVar(large_var
);
1061 std::string
TestWebSocket::TestAbortCloseCall() {
1062 // Release the resource in the close completion callback.
1064 std::string url
= GetFullURL(kEchoServerURL
);
1065 PP_Resource ws
= Connect(url
, &result
, std::string());
1067 ASSERT_EQ(PP_OK
, result
);
1068 TestCompletionCallback
close_callback(
1069 instance_
->pp_instance(), callback_type());
1070 result
= websocket_interface_
->Close(
1071 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1072 close_callback
.GetCallback().pp_completion_callback());
1073 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
1074 close_callback
.SetDelegate(&close_delegate
);
1075 close_callback
.WaitForResult(result
);
1076 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1077 ASSERT_EQ(PP_OK
, close_callback
.result());
1082 std::string
TestWebSocket::TestAbortReceiveMessageCall() {
1083 // Test the behavior where receive process might be in-flight.
1084 std::vector
<uint8_t> large_binary(65 * 1024);
1085 PP_Var large_var
= CreateVarBinary(large_binary
);
1086 const char* text
= "yukarin";
1087 PP_Var text_var
= CreateVarString(text
);
1089 std::string url
= GetFullURL(kEchoServerURL
);
1093 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1094 // number of message(s) before releasing the WebSocket. The WebSocket is
1095 // released while the next message is going to be received.
1096 const int trial_count
= 8;
1097 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1098 ws
= Connect(url
, &result
, std::string());
1100 ASSERT_EQ(PP_OK
, result
);
1101 for (int i
= 0; i
<= trial_count
; ++i
) {
1102 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1103 ASSERT_EQ(PP_OK
, result
);
1105 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1107 for (int i
= 0; i
< trial
; ++i
) {
1108 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1109 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1110 ASSERT_EQ(PP_OK
, callback
.result());
1111 ASSERT_TRUE(AreEqualWithString(var
, text
));
1114 result
= websocket_interface_
->ReceiveMessage(
1115 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1116 core_interface_
->ReleaseResource(ws
);
1117 if (result
!= PP_OK
) {
1118 callback
.WaitForResult(result
);
1119 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1122 // Same test, but the last receiving message is large message over 64KiB.
1123 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1124 ws
= Connect(url
, &result
, std::string());
1126 ASSERT_EQ(PP_OK
, result
);
1127 for (int i
= 0; i
<= trial_count
; ++i
) {
1129 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1131 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1132 ASSERT_EQ(PP_OK
, result
);
1134 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1136 for (int i
= 0; i
< trial
; ++i
) {
1137 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1138 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1139 ASSERT_EQ(PP_OK
, callback
.result());
1140 ASSERT_TRUE(AreEqualWithString(var
, text
));
1143 result
= websocket_interface_
->ReceiveMessage(
1144 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1145 core_interface_
->ReleaseResource(ws
);
1146 if (result
!= PP_OK
) {
1147 callback
.WaitForResult(result
);
1148 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1152 ReleaseVar(large_var
);
1153 ReleaseVar(text_var
);
1158 std::string
TestWebSocket::TestCcInterfaces() {
1159 // C++ bindings is simple straightforward, then just verifies interfaces work
1160 // as a interface bridge fine.
1161 pp::WebSocket
ws(instance_
);
1163 // Check uninitialized properties access.
1164 ASSERT_EQ(0, ws
.GetBufferedAmount());
1165 ASSERT_EQ(0, ws
.GetCloseCode());
1166 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), std::string()));
1167 ASSERT_FALSE(ws
.GetCloseWasClean());
1168 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), std::string()));
1169 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1170 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1171 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), std::string()));
1173 // Check communication interfaces (connect, send, receive, and close).
1174 TestCompletionCallback
connect_callback(
1175 instance_
->pp_instance(), callback_type());
1176 connect_callback
.WaitForResult(ws
.Connect(
1177 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U,
1178 connect_callback
.GetCallback()));
1179 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1180 ASSERT_EQ(PP_OK
, connect_callback
.result());
1182 std::string
text_message("hello C++");
1183 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1184 ASSERT_EQ(PP_OK
, result
);
1186 std::vector
<uint8_t> binary(256);
1187 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1189 result
= ws
.SendMessage(
1190 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1191 ASSERT_EQ(PP_OK
, result
);
1193 pp::Var text_receive_var
;
1194 TestCompletionCallback
text_receive_callback(
1195 instance_
->pp_instance(), callback_type());
1196 text_receive_callback
.WaitForResult(
1197 ws
.ReceiveMessage(&text_receive_var
,
1198 text_receive_callback
.GetCallback()));
1199 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1201 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1203 pp::Var binary_receive_var
;
1204 TestCompletionCallback
binary_receive_callback(
1205 instance_
->pp_instance(), callback_type());
1206 binary_receive_callback
.WaitForResult(
1207 ws
.ReceiveMessage(&binary_receive_var
,
1208 binary_receive_callback
.GetCallback()));
1209 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1210 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1212 TestCompletionCallback
close_callback(
1213 instance_
->pp_instance(), callback_type());
1214 std::string
reason("bye");
1215 close_callback
.WaitForResult(ws
.Close(
1216 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
),
1217 close_callback
.GetCallback()));
1218 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1219 ASSERT_EQ(PP_OK
, close_callback
.result());
1221 // Check initialized properties access.
1222 ASSERT_EQ(0, ws
.GetBufferedAmount());
1223 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1225 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1226 ASSERT_EQ(true, ws
.GetCloseWasClean());
1227 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1228 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1229 ASSERT_TRUE(AreEqualWithString(
1230 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1235 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1236 const pp::Var protocols
[] = { pp::Var() };
1238 TestWebSocketAPI
websocket(instance_
);
1239 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1240 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1241 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1243 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1244 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1245 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1247 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1248 TestWebSocketAPI
ws(instance_
);
1249 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1250 if (result
== PP_OK_COMPLETIONPENDING
) {
1252 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1253 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1254 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1255 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1257 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1258 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1265 std::string
TestWebSocket::TestUtilityProtocols() {
1266 const pp::Var bad_protocols
[] = {
1267 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1268 const pp::Var good_protocols
[] = {
1269 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1272 TestWebSocketAPI
websocket(instance_
);
1273 int32_t result
= websocket
.Connect(
1274 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1275 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1276 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1280 TestWebSocketAPI
websocket(instance_
);
1281 int32_t result
= websocket
.Connect(
1282 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1283 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1284 websocket
.WaitForConnected();
1285 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1286 // Protocol arguments are valid, but this test run without a WebSocket
1287 // server. As a result, OnError() and OnClose() are invoked because of
1288 // a connection establishment failure.
1289 ASSERT_EQ(2U, events
.size());
1290 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1291 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1292 ASSERT_FALSE(events
[1].was_clean
);
1298 std::string
TestWebSocket::TestUtilityGetURL() {
1299 const pp::Var protocols
[] = { pp::Var() };
1301 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1302 TestWebSocketAPI
websocket(instance_
);
1303 int32_t result
= websocket
.Connect(
1304 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1305 if (result
== PP_OK_COMPLETIONPENDING
) {
1306 websocket
.WaitForClosed();
1307 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1308 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1309 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1310 ASSERT_EQ(2U, events
.size());
1312 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1313 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1315 pp::Var url
= websocket
.GetURL();
1316 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1322 std::string
TestWebSocket::TestUtilityValidConnect() {
1323 const pp::Var protocols
[] = { pp::Var() };
1324 TestWebSocketAPI
websocket(instance_
);
1325 int32_t result
= websocket
.Connect(
1326 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1327 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1328 websocket
.WaitForConnected();
1329 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1330 ASSERT_EQ(1U, events
.size());
1331 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1333 AreEqualWithString(websocket
.GetExtensions().pp_var(), std::string()));
1338 std::string
TestWebSocket::TestUtilityInvalidClose() {
1339 const pp::Var reason
= pp::Var(std::string("close for test"));
1341 // Close before connect.
1343 TestWebSocketAPI
websocket(instance_
);
1344 int32_t result
= websocket
.Close(
1345 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1346 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1347 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1350 // Close with bad arguments.
1352 TestWebSocketAPI
websocket(instance_
);
1353 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1355 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1356 websocket
.WaitForConnected();
1357 result
= websocket
.Close(1U, reason
);
1358 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1359 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1360 ASSERT_EQ(1U, events
.size());
1361 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1367 std::string
TestWebSocket::TestUtilityValidClose() {
1368 std::string
reason("close for test");
1369 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1373 TestWebSocketAPI
websocket(instance_
);
1374 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1375 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1376 websocket
.WaitForConnected();
1377 result
= websocket
.Close(
1378 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1379 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1380 websocket
.WaitForClosed();
1381 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1382 ASSERT_EQ(2U, events
.size());
1383 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1384 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1385 ASSERT_TRUE(events
[1].was_clean
);
1386 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1387 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1390 // Close in connecting.
1391 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1394 TestWebSocketAPI
websocket(instance_
);
1395 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1396 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1397 result
= websocket
.Close(
1398 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1399 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1400 websocket
.WaitForClosed();
1401 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1402 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1404 if (events
.size() == 3)
1405 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1406 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1407 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1408 ASSERT_FALSE(events
[index
].was_clean
);
1411 // Close in closing.
1412 // The first close will be done successfully, then the second one failed with
1413 // with PP_ERROR_INPROGRESS immediately.
1415 TestWebSocketAPI
websocket(instance_
);
1416 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1417 result
= websocket
.Close(
1418 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1419 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1420 result
= websocket
.Close(
1421 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1422 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1423 websocket
.WaitForClosed();
1424 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1425 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1427 if (events
.size() == 3)
1428 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1429 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1430 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1431 ASSERT_FALSE(events
[index
].was_clean
);
1437 std::string
TestWebSocket::TestUtilityGetProtocol() {
1438 const std::string
protocol("x-chat");
1439 const pp::Var protocols
[] = { pp::Var(protocol
) };
1440 std::string
url(GetFullURL(kProtocolTestServerURL
));
1442 TestWebSocketAPI
websocket(instance_
);
1443 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1444 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1445 websocket
.WaitForReceived();
1446 ASSERT_TRUE(AreEqualWithString(
1447 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1448 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1449 // The server to which this test connect returns the decided protocol as a
1450 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1451 // after EVENT_OPEN event.
1452 ASSERT_EQ(2U, events
.size());
1453 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1454 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1455 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1460 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1461 const pp::Var protocols
[] = { pp::Var() };
1462 TestWebSocketAPI
websocket(instance_
);
1464 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1465 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1466 websocket
.WaitForConnected();
1468 // Send 'hello pepper'.
1469 std::string
message1("hello pepper");
1470 result
= websocket
.Send(pp::Var(std::string(message1
)));
1471 ASSERT_EQ(PP_OK
, result
);
1473 // Receive echoed 'hello pepper'.
1474 websocket
.WaitForReceived();
1476 // Send 'goodbye pepper'.
1477 std::string
message2("goodbye pepper");
1478 result
= websocket
.Send(pp::Var(std::string(message2
)));
1480 // Receive echoed 'goodbye pepper'.
1481 websocket
.WaitForReceived();
1483 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1484 ASSERT_EQ(3U, events
.size());
1485 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1486 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1487 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), message1
.c_str()));
1488 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1489 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1494 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1495 const pp::Var protocols
[] = { pp::Var() };
1496 TestWebSocketAPI
websocket(instance_
);
1498 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1499 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1500 websocket
.WaitForConnected();
1502 // Send binary message.
1504 std::vector
<uint8_t> binary(len
);
1505 for (uint32_t i
= 0; i
< len
; ++i
)
1507 pp::VarArrayBuffer
message(len
);
1508 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1509 std::copy(binary
.begin(), binary
.end(), var_data
);
1510 result
= websocket
.Send(message
);
1511 ASSERT_EQ(PP_OK
, result
);
1513 // Receive echoed binary message.
1514 websocket
.WaitForReceived();
1516 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1517 ASSERT_EQ(2U, events
.size());
1518 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1519 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1520 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1525 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1526 // Connect to test echo server.
1527 const pp::Var protocols
[] = { pp::Var() };
1528 TestWebSocketAPI
websocket(instance_
);
1530 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1531 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1532 websocket
.WaitForConnected();
1534 // Prepare a large message that is not aligned with the internal buffer
1536 std::string
message(8193, 'x');
1537 uint64_t buffered_amount
= 0;
1539 for (sent
= 0; sent
< 100; sent
++) {
1540 result
= websocket
.Send(pp::Var(message
));
1541 ASSERT_EQ(PP_OK
, result
);
1542 buffered_amount
= websocket
.GetBufferedAmount();
1543 // Buffered amount size 262144 is too big for the internal buffer size.
1544 if (buffered_amount
> 262144)
1548 // Close connection.
1549 std::string reason
= "close while busy";
1550 result
= websocket
.Close(
1551 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1552 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1553 websocket
.WaitForClosed();
1554 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1556 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1557 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1559 // After connection closure, all sending requests fail and just increase
1560 // the bufferedAmount property.
1561 result
= websocket
.Send(pp::Var(std::string()));
1562 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1563 buffered_amount
= websocket
.GetBufferedAmount();
1564 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1565 base_buffered_amount
= buffered_amount
;
1567 result
= websocket
.Send(pp::Var(reason
));
1568 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1569 buffered_amount
= websocket
.GetBufferedAmount();
1570 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1571 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1573 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1574 ASSERT_EQ(events_on_closed
, events
.size());
1575 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1576 size_t last_event
= events_on_closed
- 1;
1577 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1578 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1579 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1581 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1582 ASSERT_TRUE(events
[last_event
].was_clean
);