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
);
227 RUN_TEST_WITH_REFERENCE_CHECK(ClosedFromServerWhileSending
, filter
);
229 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces
, filter
);
231 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect
, filter
);
232 RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols
, filter
);
233 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL
, filter
);
234 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect
, filter
);
235 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose
, filter
);
236 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose
, filter
);
237 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol
, filter
);
238 RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive
, filter
);
239 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive
, filter
);
240 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount
, filter
);
243 std::string
TestWebSocket::GetFullURL(const char* url
) {
244 std::string rv
= "ws://";
245 // Some WebSocket tests don't start the server so there'll be no host and
247 if (instance_
->websocket_host().empty())
250 rv
+= instance_
->websocket_host();
251 if (instance_
->websocket_port() != -1) {
253 sprintf(buffer
, ":%d", instance_
->websocket_port());
254 rv
+= std::string(buffer
);
261 PP_Var
TestWebSocket::CreateVarString(const std::string
& string
) {
262 return var_interface_
->VarFromUtf8(string
.c_str(), string
.size());
265 PP_Var
TestWebSocket::CreateVarBinary(const std::vector
<uint8_t>& binary
) {
266 PP_Var var
= arraybuffer_interface_
->Create(binary
.size());
267 uint8_t* var_data
= static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
));
268 std::copy(binary
.begin(), binary
.end(), var_data
);
272 void TestWebSocket::ReleaseVar(const PP_Var
& var
) {
273 var_interface_
->Release(var
);
276 bool TestWebSocket::AreEqualWithString(const PP_Var
& var
,
277 const std::string
& string
) {
278 if (var
.type
!= PP_VARTYPE_STRING
)
280 uint32_t utf8_length
;
281 const char* utf8
= var_interface_
->VarToUtf8(var
, &utf8_length
);
282 if (utf8_length
!= string
.size())
284 if (string
.compare(utf8
))
289 bool TestWebSocket::AreEqualWithBinary(const PP_Var
& var
,
290 const std::vector
<uint8_t>& binary
) {
291 uint32_t buffer_size
= 0;
292 PP_Bool success
= arraybuffer_interface_
->ByteLength(var
, &buffer_size
);
293 if (!success
|| buffer_size
!= binary
.size())
295 if (!std::equal(binary
.begin(), binary
.end(),
296 static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
))))
301 PP_Resource
TestWebSocket::Connect(const std::string
& url
,
303 const std::string
& protocol
) {
304 PP_Var protocols
[] = { PP_MakeUndefined() };
305 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
308 PP_Var url_var
= CreateVarString(url
);
309 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
310 uint32_t protocol_count
= 0U;
311 if (protocol
.size()) {
312 protocols
[0] = CreateVarString(protocol
);
315 callback
.WaitForResult(websocket_interface_
->Connect(
316 ws
, url_var
, protocols
, protocol_count
,
317 callback
.GetCallback().pp_completion_callback()));
320 ReleaseVar(protocols
[0]);
321 *result
= callback
.result();
325 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws
,
326 const std::string
& message
) {
327 PP_Var message_var
= CreateVarString(message
);
328 websocket_interface_
->SendMessage(ws
, message_var
);
329 ReleaseVar(message_var
);
332 std::string
TestWebSocket::TestIsWebSocket() {
333 // Test that a NULL resource isn't a websocket.
334 pp::Resource null_resource
;
336 websocket_interface_
->IsWebSocket(null_resource
.pp_resource());
337 ASSERT_FALSE(result
);
339 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
342 result
= websocket_interface_
->IsWebSocket(ws
);
345 core_interface_
->ReleaseResource(ws
);
350 std::string
TestWebSocket::TestUninitializedPropertiesAccess() {
351 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
354 uint64_t bufferedAmount
= websocket_interface_
->GetBufferedAmount(ws
);
355 ASSERT_EQ(0U, bufferedAmount
);
357 uint16_t close_code
= websocket_interface_
->GetCloseCode(ws
);
358 ASSERT_EQ(0U, close_code
);
360 PP_Var close_reason
= websocket_interface_
->GetCloseReason(ws
);
361 ASSERT_TRUE(AreEqualWithString(close_reason
, std::string()));
362 ReleaseVar(close_reason
);
364 PP_Bool close_was_clean
= websocket_interface_
->GetCloseWasClean(ws
);
365 ASSERT_EQ(PP_FALSE
, close_was_clean
);
367 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
368 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
369 ReleaseVar(extensions
);
371 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
372 ASSERT_TRUE(AreEqualWithString(protocol
, std::string()));
373 ReleaseVar(protocol
);
375 PP_WebSocketReadyState ready_state
=
376 websocket_interface_
->GetReadyState(ws
);
377 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ready_state
);
379 PP_Var url
= websocket_interface_
->GetURL(ws
);
380 ASSERT_TRUE(AreEqualWithString(url
, std::string()));
383 core_interface_
->ReleaseResource(ws
);
388 std::string
TestWebSocket::TestInvalidConnect() {
389 PP_Var protocols
[] = { PP_MakeUndefined() };
391 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
394 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
395 callback
.WaitForResult(websocket_interface_
->Connect(
396 ws
, PP_MakeUndefined(), protocols
, 1U,
397 callback
.GetCallback().pp_completion_callback()));
398 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
400 callback
.WaitForResult(websocket_interface_
->Connect(
401 ws
, PP_MakeUndefined(), protocols
, 1U,
402 callback
.GetCallback().pp_completion_callback()));
403 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback
.result());
405 core_interface_
->ReleaseResource(ws
);
407 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
409 ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
411 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
413 core_interface_
->ReleaseResource(ws
);
419 std::string
TestWebSocket::TestProtocols() {
420 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
421 PP_Var bad_protocols
[] = {
422 CreateVarString("x-test"),
423 CreateVarString("x-test")
425 PP_Var good_protocols
[] = {
426 CreateVarString("x-test"),
427 CreateVarString("x-yatest")
430 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
432 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
433 callback
.WaitForResult(websocket_interface_
->Connect(
434 ws
, url
, bad_protocols
, 2U,
435 callback
.GetCallback().pp_completion_callback()));
436 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
437 core_interface_
->ReleaseResource(ws
);
439 ws
= websocket_interface_
->Create(instance_
->pp_instance());
441 int32_t result
= websocket_interface_
->Connect(
442 ws
, url
, good_protocols
, 2U, PP_BlockUntilComplete());
443 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, result
);
444 core_interface_
->ReleaseResource(ws
);
447 for (int i
= 0; i
< 2; ++i
) {
448 ReleaseVar(bad_protocols
[i
]);
449 ReleaseVar(good_protocols
[i
]);
451 core_interface_
->ReleaseResource(ws
);
456 std::string
TestWebSocket::TestGetURL() {
457 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
459 PP_Resource ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
461 PP_Var url
= websocket_interface_
->GetURL(ws
);
462 ASSERT_TRUE(AreEqualWithString(url
, kInvalidURLs
[i
]));
463 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
466 core_interface_
->ReleaseResource(ws
);
472 std::string
TestWebSocket::TestValidConnect() {
474 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
476 ASSERT_EQ(PP_OK
, result
);
477 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
478 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
479 core_interface_
->ReleaseResource(ws
);
480 ReleaseVar(extensions
);
485 std::string
TestWebSocket::TestInvalidClose() {
486 PP_Var reason
= CreateVarString("close for test");
487 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
488 TestCompletionCallback
async_callback(instance_
->pp_instance(), PP_REQUIRED
);
490 // Close before connect.
491 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
492 callback
.WaitForResult(websocket_interface_
->Close(
493 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
494 callback
.GetCallback().pp_completion_callback()));
495 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
496 core_interface_
->ReleaseResource(ws
);
498 // Close with bad arguments.
500 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
502 ASSERT_EQ(PP_OK
, result
);
503 callback
.WaitForResult(websocket_interface_
->Close(
504 ws
, 1U, reason
, callback
.GetCallback().pp_completion_callback()));
505 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
506 core_interface_
->ReleaseResource(ws
);
508 // Close with PP_VARTYPE_NULL.
509 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
511 ASSERT_EQ(PP_OK
, result
);
512 callback
.WaitForResult(websocket_interface_
->Close(
513 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
514 callback
.GetCallback().pp_completion_callback()));
515 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
516 core_interface_
->ReleaseResource(ws
);
518 // Close with PP_VARTYPE_NULL and ongoing receive message.
519 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
521 ASSERT_EQ(PP_OK
, result
);
522 PP_Var receive_message_var
;
523 result
= websocket_interface_
->ReceiveMessage(
524 ws
, &receive_message_var
,
525 async_callback
.GetCallback().pp_completion_callback());
526 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
527 callback
.WaitForResult(websocket_interface_
->Close(
528 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
529 callback
.GetCallback().pp_completion_callback()));
530 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
531 const char* send_message
= "hi";
532 PP_Var send_message_var
= CreateVarString(send_message
);
533 result
= websocket_interface_
->SendMessage(ws
, send_message_var
);
534 ReleaseVar(send_message_var
);
535 ASSERT_EQ(PP_OK
, result
);
536 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
537 ASSERT_EQ(PP_OK
, async_callback
.result());
538 ASSERT_TRUE(AreEqualWithString(receive_message_var
, send_message
));
539 ReleaseVar(receive_message_var
);
540 core_interface_
->ReleaseResource(ws
);
543 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
545 ASSERT_EQ(PP_OK
, result
);
546 result
= websocket_interface_
->Close(
547 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
548 async_callback
.GetCallback().pp_completion_callback());
549 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
550 // Call another Close() before previous one is in progress.
551 result
= websocket_interface_
->Close(
552 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
553 callback
.GetCallback().pp_completion_callback());
554 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
555 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
556 ASSERT_EQ(PP_OK
, async_callback
.result());
557 // Call another Close() after previous one is completed.
558 // This Close() must do nothing and reports no error.
559 callback
.WaitForResult(websocket_interface_
->Close(
560 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
561 callback
.GetCallback().pp_completion_callback()));
562 ASSERT_EQ(PP_OK
, callback
.result());
563 core_interface_
->ReleaseResource(ws
);
570 // TODO(tyoshino): Consider splitting this test into smaller ones.
571 // http://crbug.com/397035
572 std::string
TestWebSocket::TestValidClose() {
573 PP_Var reason
= CreateVarString("close for test");
574 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
575 TestCompletionCallback
another_callback(
576 instance_
->pp_instance(), callback_type());
580 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
582 ASSERT_EQ(PP_OK
, result
);
583 callback
.WaitForResult(websocket_interface_
->Close(
584 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
585 callback
.GetCallback().pp_completion_callback()));
586 CHECK_CALLBACK_BEHAVIOR(callback
);
587 ASSERT_EQ(PP_OK
, callback
.result());
588 core_interface_
->ReleaseResource(ws
);
590 // Close without code and reason.
591 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
593 ASSERT_EQ(PP_OK
, result
);
594 callback
.WaitForResult(websocket_interface_
->Close(
595 ws
, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED
, reason
,
596 callback
.GetCallback().pp_completion_callback()));
597 CHECK_CALLBACK_BEHAVIOR(callback
);
598 ASSERT_EQ(PP_OK
, callback
.result());
599 core_interface_
->ReleaseResource(ws
);
601 // Close with PP_VARTYPE_UNDEFINED.
602 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
604 ASSERT_EQ(PP_OK
, result
);
605 callback
.WaitForResult(websocket_interface_
->Close(
606 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
607 callback
.GetCallback().pp_completion_callback()));
608 CHECK_CALLBACK_BEHAVIOR(callback
);
609 ASSERT_EQ(PP_OK
, callback
.result());
610 core_interface_
->ReleaseResource(ws
);
612 // Close in CONNECTING state.
613 // The ongoing Connect() fails with PP_ERROR_ABORTED, then the Close()
614 // completes successfully.
615 ws
= websocket_interface_
->Create(instance_
->pp_instance());
616 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
617 PP_Var protocols
[] = { PP_MakeUndefined() };
618 result
= websocket_interface_
->Connect(
619 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
620 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
621 result
= websocket_interface_
->Close(
622 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
623 another_callback
.GetCallback().pp_completion_callback());
624 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
625 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
626 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
627 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
628 ASSERT_EQ(PP_OK
, another_callback
.result());
629 core_interface_
->ReleaseResource(ws
);
632 // Close while already closing.
633 // The first Close will succeed, and the second one will synchronously fail
634 // with PP_ERROR_INPROGRESS.
635 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
637 ASSERT_EQ(PP_OK
, result
);
638 result
= websocket_interface_
->Close(
639 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
640 callback
.GetCallback().pp_completion_callback());
641 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
642 result
= websocket_interface_
->Close(
643 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
644 another_callback
.GetCallback().pp_completion_callback());
645 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
646 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
647 ASSERT_EQ(PP_OK
, callback
.result());
648 core_interface_
->ReleaseResource(ws
);
650 // Close with ongoing ReceiveMessage.
651 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
653 ASSERT_EQ(PP_OK
, result
);
654 PP_Var receive_message_var
;
655 result
= websocket_interface_
->ReceiveMessage(
656 ws
, &receive_message_var
,
657 callback
.GetCallback().pp_completion_callback());
658 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
659 result
= websocket_interface_
->Close(
660 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
661 another_callback
.GetCallback().pp_completion_callback());
662 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
663 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
664 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
665 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
666 ASSERT_EQ(PP_OK
, another_callback
.result());
667 core_interface_
->ReleaseResource(ws
);
669 // Close with PP_VARTYPE_UNDEFINED for reason and ongoing ReceiveMessage.
670 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
672 ASSERT_EQ(PP_OK
, result
);
673 result
= websocket_interface_
->ReceiveMessage(
674 ws
, &receive_message_var
,
675 callback
.GetCallback().pp_completion_callback());
676 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
677 result
= websocket_interface_
->Close(
678 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
679 another_callback
.GetCallback().pp_completion_callback());
680 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
681 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
682 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
683 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
684 ASSERT_EQ(PP_OK
, another_callback
.result());
685 core_interface_
->ReleaseResource(ws
);
687 // Server initiated closing handshake.
689 GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, std::string());
691 ASSERT_EQ(PP_OK
, result
);
692 // Text messsage "1000 bye" requests the server to initiate closing handshake
693 // with code being 1000 and reason being "bye".
694 PP_Var close_request_var
= CreateVarString("1000 bye");
695 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
696 ReleaseVar(close_request_var
);
697 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
698 ws
, &receive_message_var
,
699 callback
.GetCallback().pp_completion_callback()));
700 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
701 core_interface_
->ReleaseResource(ws
);
708 std::string
TestWebSocket::TestGetProtocol() {
709 const char* expected_protocols
[] = {
714 for (int i
= 0; expected_protocols
[i
]; ++i
) {
715 std::string
url(GetFullURL(kProtocolTestServerURL
));
716 url
+= expected_protocols
[i
];
718 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
720 ASSERT_EQ(PP_OK
, result
);
722 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
723 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
725 ReleaseVar(protocol
);
726 core_interface_
->ReleaseResource(ws
);
732 std::string
TestWebSocket::TestTextSendReceive() {
733 // Connect to test echo server.
734 int32_t connect_result
;
736 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
738 ASSERT_EQ(PP_OK
, connect_result
);
740 // Send 'hello pepper' text message.
741 const char* message
= "hello pepper";
742 PP_Var message_var
= CreateVarString(message
);
743 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
744 ReleaseVar(message_var
);
745 ASSERT_EQ(PP_OK
, result
);
747 // Receive echoed 'hello pepper'.
748 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
749 PP_Var received_message
;
750 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
751 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
752 ASSERT_EQ(PP_OK
, callback
.result());
753 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
754 ReleaseVar(received_message
);
755 core_interface_
->ReleaseResource(ws
);
760 // Run as a BACKGROUND test.
761 std::string
TestWebSocket::TestTextSendReceiveTwice() {
762 // Connect to test echo server.
763 int32_t connect_result
;
765 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
767 ASSERT_EQ(PP_OK
, connect_result
);
768 pp::MessageLoop message_loop
= pp::MessageLoop::GetCurrent();
769 pp::CompletionCallbackFactory
<TestWebSocket
> factory(this);
771 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
772 ws
, std::string("hello")));
773 // When the server receives 'Goodbye', it closes the session.
774 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
775 ws
, std::string("Goodbye")));
776 message_loop
.PostQuit(false);
779 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
780 PP_Var received_message
;
781 int32_t result
= websocket_interface_
->ReceiveMessage(
782 ws
, &received_message
, callback
.GetCallback().pp_completion_callback());
783 ASSERT_EQ(PP_OK
, result
);
784 // Since we don't run the message loop, the callback will stay
785 // "pending and scheduled to run" state.
787 // Waiting for the connection close which will be done by the server.
789 PP_WebSocketReadyState ready_state
=
790 websocket_interface_
->GetReadyState(ws
);
791 if (ready_state
!= PP_WEBSOCKETREADYSTATE_CONNECTING
&&
792 ready_state
!= PP_WEBSOCKETREADYSTATE_OPEN
) {
795 PlatformSleep(100); // 100ms
798 // Cleanup the message loop
799 message_loop
.PostQuit(false);
802 ASSERT_EQ(PP_OK
, callback
.result());
803 ASSERT_TRUE(AreEqualWithString(received_message
, "hello"));
804 ReleaseVar(received_message
);
805 core_interface_
->ReleaseResource(ws
);
809 std::string
TestWebSocket::TestBinarySendReceive() {
810 // Connect to test echo server.
811 int32_t connect_result
;
813 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
815 ASSERT_EQ(PP_OK
, connect_result
);
817 // Send binary message.
818 std::vector
<uint8_t> binary(256);
819 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
821 PP_Var message_var
= CreateVarBinary(binary
);
822 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
823 ReleaseVar(message_var
);
824 ASSERT_EQ(PP_OK
, result
);
826 // Receive echoed binary.
827 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
828 PP_Var received_message
;
829 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
830 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
831 ASSERT_EQ(PP_OK
, callback
.result());
832 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
833 ReleaseVar(received_message
);
834 core_interface_
->ReleaseResource(ws
);
839 std::string
TestWebSocket::TestStressedSendReceive() {
840 // Connect to test echo server.
841 int32_t connect_result
;
843 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
845 ASSERT_EQ(PP_OK
, connect_result
);
847 // Prepare PP_Var objects to send.
848 const char* text
= "hello pepper";
849 PP_Var text_var
= CreateVarString(text
);
850 std::vector
<uint8_t> binary(256);
851 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
853 PP_Var binary_var
= CreateVarBinary(binary
);
854 // Prepare very large binary data over 64KiB. Object serializer in
855 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
856 // to SRPC. In case received data over 64KiB exists, a specific code handles
857 // this large data via asynchronous callback from main thread. This data
858 // intends to test the code.
859 std::vector
<uint8_t> large_binary(65 * 1024);
860 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
861 large_binary
[i
] = i
& 0xff;
862 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
864 // Send many messages.
866 for (int i
= 0; i
< 256; ++i
) {
867 result
= websocket_interface_
->SendMessage(ws
, text_var
);
868 ASSERT_EQ(PP_OK
, result
);
869 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
870 ASSERT_EQ(PP_OK
, result
);
872 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
873 ASSERT_EQ(PP_OK
, result
);
874 ReleaseVar(text_var
);
875 ReleaseVar(binary_var
);
876 ReleaseVar(large_binary_var
);
878 // Receive echoed data.
879 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
880 for (int i
= 0; i
<= 512; ++i
) {
881 PP_Var received_message
;
882 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
883 ws
, &received_message
,
884 callback
.GetCallback().pp_completion_callback()));
885 ASSERT_EQ(PP_OK
, callback
.result());
887 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
889 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
891 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
893 ReleaseVar(received_message
);
895 core_interface_
->ReleaseResource(ws
);
900 std::string
TestWebSocket::TestBufferedAmount() {
901 // Connect to test echo server.
902 int32_t connect_result
;
904 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
906 ASSERT_EQ(PP_OK
, connect_result
);
908 // Prepare a large message that is not aligned with the internal buffer
910 std::string
message(8193, 'x');
911 PP_Var message_var
= CreateVarString(message
);
913 uint64_t buffered_amount
= 0;
915 for (int i
= 0; i
< 100; i
++) {
916 result
= websocket_interface_
->SendMessage(ws
, message_var
);
917 ASSERT_EQ(PP_OK
, result
);
918 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
919 // Buffered amount size 262144 is too big for the internal buffer size.
920 if (buffered_amount
> 262144)
925 std::string reason_str
= "close while busy";
926 PP_Var reason
= CreateVarString(reason_str
.c_str());
927 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
928 result
= websocket_interface_
->Close(
929 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
930 callback
.GetCallback().pp_completion_callback());
931 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
932 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
933 websocket_interface_
->GetReadyState(ws
));
935 callback
.WaitForResult(result
);
936 ASSERT_EQ(PP_OK
, callback
.result());
937 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
938 websocket_interface_
->GetReadyState(ws
));
940 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
942 // After connection closure, all sending requests fail and just increase
943 // the bufferedAmount property.
944 PP_Var empty_string
= CreateVarString(std::string());
945 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
946 ASSERT_EQ(PP_ERROR_FAILED
, result
);
947 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
948 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
949 base_buffered_amount
= buffered_amount
;
951 result
= websocket_interface_
->SendMessage(ws
, reason
);
952 ASSERT_EQ(PP_ERROR_FAILED
, result
);
953 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
954 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
955 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
957 ReleaseVar(message_var
);
959 ReleaseVar(empty_string
);
960 core_interface_
->ReleaseResource(ws
);
965 // Test abort behaviors where a WebSocket PP_Resource is released while each
966 // function is in-flight on the WebSocket PP_Resource.
967 std::string
TestWebSocket::TestAbortCallsWithCallback() {
968 // Following tests make sure the behavior for functions which require a
969 // callback. The callback must get a PP_ERROR_ABORTED.
971 // Test the behavior for Connect().
972 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
974 std::string url
= GetFullURL(kEchoServerURL
);
975 PP_Var url_var
= CreateVarString(url
);
976 TestCompletionCallback
connect_callback(
977 instance_
->pp_instance(), callback_type());
978 int32_t result
= websocket_interface_
->Connect(
979 ws
, url_var
, NULL
, 0,
980 connect_callback
.GetCallback().pp_completion_callback());
981 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
982 core_interface_
->ReleaseResource(ws
);
983 connect_callback
.WaitForResult(result
);
984 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
986 // Test the behavior for Close().
987 ws
= Connect(url
, &result
, std::string());
989 ASSERT_EQ(PP_OK
, result
);
990 PP_Var reason_var
= CreateVarString("abort");
991 TestCompletionCallback
close_callback(
992 instance_
->pp_instance(), callback_type());
993 result
= websocket_interface_
->Close(
994 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
995 close_callback
.GetCallback().pp_completion_callback());
996 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
997 core_interface_
->ReleaseResource(ws
);
998 close_callback
.WaitForResult(result
);
999 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1000 ReleaseVar(reason_var
);
1002 // Test the behavior for ReceiveMessage().
1003 // Make sure the simplest case to wait for data which never arrives, here.
1004 ws
= Connect(url
, &result
, std::string());
1006 ASSERT_EQ(PP_OK
, result
);
1008 TestCompletionCallback
receive_callback(
1009 instance_
->pp_instance(), callback_type());
1010 result
= websocket_interface_
->ReceiveMessage(
1012 receive_callback
.GetCallback().pp_completion_callback());
1013 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1014 core_interface_
->ReleaseResource(ws
);
1015 receive_callback
.WaitForResult(result
);
1016 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1018 // Release the resource in the aborting receive completion callback which is
1019 // introduced by calling Close().
1020 ws
= Connect(url
, &result
, std::string());
1022 ASSERT_EQ(PP_OK
, result
);
1023 result
= websocket_interface_
->ReceiveMessage(
1025 receive_callback
.GetCallback().pp_completion_callback());
1026 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1027 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
1028 receive_callback
.SetDelegate(&receive_delegate
);
1029 result
= websocket_interface_
->Close(
1030 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1031 close_callback
.GetCallback().pp_completion_callback());
1032 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1033 receive_callback
.WaitForResult(result
);
1034 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
1035 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1036 close_callback
.WaitForResult(result
);
1037 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1038 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1040 ReleaseVar(url_var
);
1045 std::string
TestWebSocket::TestAbortSendMessageCall() {
1046 // Test the behavior for SendMessage().
1047 // This function doesn't require a callback, but operation will be done
1048 // asynchronously in WebKit and browser process.
1049 std::vector
<uint8_t> large_binary(65 * 1024);
1050 PP_Var large_var
= CreateVarBinary(large_binary
);
1053 std::string url
= GetFullURL(kEchoServerURL
);
1054 PP_Resource ws
= Connect(url
, &result
, std::string());
1056 ASSERT_EQ(PP_OK
, result
);
1057 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1058 ASSERT_EQ(PP_OK
, result
);
1059 core_interface_
->ReleaseResource(ws
);
1060 ReleaseVar(large_var
);
1065 std::string
TestWebSocket::TestAbortCloseCall() {
1066 // Release the resource in the close completion callback.
1068 std::string url
= GetFullURL(kEchoServerURL
);
1069 PP_Resource ws
= Connect(url
, &result
, std::string());
1071 ASSERT_EQ(PP_OK
, result
);
1072 TestCompletionCallback
close_callback(
1073 instance_
->pp_instance(), callback_type());
1074 result
= websocket_interface_
->Close(
1075 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1076 close_callback
.GetCallback().pp_completion_callback());
1077 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
1078 close_callback
.SetDelegate(&close_delegate
);
1079 close_callback
.WaitForResult(result
);
1080 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1081 ASSERT_EQ(PP_OK
, close_callback
.result());
1086 std::string
TestWebSocket::TestAbortReceiveMessageCall() {
1087 // Test the behavior where receive process might be in-flight.
1088 std::vector
<uint8_t> large_binary(65 * 1024);
1089 PP_Var large_var
= CreateVarBinary(large_binary
);
1090 const char* text
= "yukarin";
1091 PP_Var text_var
= CreateVarString(text
);
1093 std::string url
= GetFullURL(kEchoServerURL
);
1097 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1098 // number of message(s) before releasing the WebSocket. The WebSocket is
1099 // released while the next message is going to be received.
1100 const int trial_count
= 8;
1101 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1102 ws
= Connect(url
, &result
, std::string());
1104 ASSERT_EQ(PP_OK
, result
);
1105 for (int i
= 0; i
<= trial_count
; ++i
) {
1106 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1107 ASSERT_EQ(PP_OK
, result
);
1109 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1111 for (int i
= 0; i
< trial
; ++i
) {
1112 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1113 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1114 ASSERT_EQ(PP_OK
, callback
.result());
1115 ASSERT_TRUE(AreEqualWithString(var
, text
));
1118 result
= websocket_interface_
->ReceiveMessage(
1119 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1120 core_interface_
->ReleaseResource(ws
);
1121 if (result
!= PP_OK
) {
1122 callback
.WaitForResult(result
);
1123 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1126 // Same test, but the last receiving message is large message over 64KiB.
1127 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1128 ws
= Connect(url
, &result
, std::string());
1130 ASSERT_EQ(PP_OK
, result
);
1131 for (int i
= 0; i
<= trial_count
; ++i
) {
1133 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1135 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1136 ASSERT_EQ(PP_OK
, result
);
1138 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1140 for (int i
= 0; i
< trial
; ++i
) {
1141 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1142 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1143 ASSERT_EQ(PP_OK
, callback
.result());
1144 ASSERT_TRUE(AreEqualWithString(var
, text
));
1147 result
= websocket_interface_
->ReceiveMessage(
1148 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1149 core_interface_
->ReleaseResource(ws
);
1150 if (result
!= PP_OK
) {
1151 callback
.WaitForResult(result
);
1152 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1156 ReleaseVar(large_var
);
1157 ReleaseVar(text_var
);
1162 std::string
TestWebSocket::TestClosedFromServerWhileSending() {
1163 // Connect to test echo server.
1164 const pp::Var protocols
[] = { pp::Var() };
1165 TestWebSocketAPI
websocket(instance_
);
1167 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1168 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1169 websocket
.WaitForConnected();
1171 result
= websocket
.Send(pp::Var("hello"));
1172 ASSERT_EQ(PP_OK
, result
);
1173 result
= websocket
.Send(pp::Var("Goodbye"));
1174 // We send many messages so that PepperWebSocketHost::SendText is called
1175 // after PepperWebSocketHost::didClose is called.
1176 // Note: We must not wait for CLOSED event here because
1177 // WebSocketResource::SendMessage doesn't call PepperWebSocketHost::SendText
1178 // when its internal state is CLOSING or CLOSED. We want to test if the
1179 // pepper WebSocket works well when WebSocketResource is OPEN and
1180 // PepperWebSocketHost is CLOSED.
1181 for (size_t i
= 0; i
< 10000; ++i
) {
1182 result
= websocket
.Send(pp::Var(""));
1183 ASSERT_EQ(PP_OK
, result
);
1189 std::string
TestWebSocket::TestCcInterfaces() {
1190 // C++ bindings is simple straightforward, then just verifies interfaces work
1191 // as a interface bridge fine.
1192 pp::WebSocket
ws(instance_
);
1194 // Check uninitialized properties access.
1195 ASSERT_EQ(0, ws
.GetBufferedAmount());
1196 ASSERT_EQ(0, ws
.GetCloseCode());
1197 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), std::string()));
1198 ASSERT_FALSE(ws
.GetCloseWasClean());
1199 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), std::string()));
1200 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1201 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1202 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), std::string()));
1204 // Check communication interfaces (connect, send, receive, and close).
1205 TestCompletionCallback
connect_callback(
1206 instance_
->pp_instance(), callback_type());
1207 connect_callback
.WaitForResult(ws
.Connect(
1208 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U,
1209 connect_callback
.GetCallback()));
1210 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1211 ASSERT_EQ(PP_OK
, connect_callback
.result());
1213 std::string
text_message("hello C++");
1214 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1215 ASSERT_EQ(PP_OK
, result
);
1217 std::vector
<uint8_t> binary(256);
1218 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1220 result
= ws
.SendMessage(
1221 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1222 ASSERT_EQ(PP_OK
, result
);
1224 pp::Var text_receive_var
;
1225 TestCompletionCallback
text_receive_callback(
1226 instance_
->pp_instance(), callback_type());
1227 text_receive_callback
.WaitForResult(
1228 ws
.ReceiveMessage(&text_receive_var
,
1229 text_receive_callback
.GetCallback()));
1230 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1232 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1234 pp::Var binary_receive_var
;
1235 TestCompletionCallback
binary_receive_callback(
1236 instance_
->pp_instance(), callback_type());
1237 binary_receive_callback
.WaitForResult(
1238 ws
.ReceiveMessage(&binary_receive_var
,
1239 binary_receive_callback
.GetCallback()));
1240 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1241 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1243 TestCompletionCallback
close_callback(
1244 instance_
->pp_instance(), callback_type());
1245 std::string
reason("bye");
1246 close_callback
.WaitForResult(ws
.Close(
1247 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
),
1248 close_callback
.GetCallback()));
1249 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1250 ASSERT_EQ(PP_OK
, close_callback
.result());
1252 // Check initialized properties access.
1253 ASSERT_EQ(0, ws
.GetBufferedAmount());
1254 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1256 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1257 ASSERT_EQ(true, ws
.GetCloseWasClean());
1258 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1259 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1260 ASSERT_TRUE(AreEqualWithString(
1261 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1266 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1267 const pp::Var protocols
[] = { pp::Var() };
1269 TestWebSocketAPI
websocket(instance_
);
1270 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1271 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1272 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1274 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1275 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1276 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1278 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1279 TestWebSocketAPI
ws(instance_
);
1280 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1281 if (result
== PP_OK_COMPLETIONPENDING
) {
1283 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1284 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1285 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1286 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1288 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1289 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1296 std::string
TestWebSocket::TestUtilityProtocols() {
1297 const pp::Var bad_protocols
[] = {
1298 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1299 const pp::Var good_protocols
[] = {
1300 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1303 TestWebSocketAPI
websocket(instance_
);
1304 int32_t result
= websocket
.Connect(
1305 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1306 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1307 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1311 TestWebSocketAPI
websocket(instance_
);
1312 int32_t result
= websocket
.Connect(
1313 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1314 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1315 websocket
.WaitForConnected();
1316 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1317 // Protocol arguments are valid, but this test run without a WebSocket
1318 // server. As a result, OnError() and OnClose() are invoked because of
1319 // a connection establishment failure.
1320 ASSERT_EQ(2U, events
.size());
1321 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1322 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1323 ASSERT_FALSE(events
[1].was_clean
);
1329 std::string
TestWebSocket::TestUtilityGetURL() {
1330 const pp::Var protocols
[] = { pp::Var() };
1332 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1333 TestWebSocketAPI
websocket(instance_
);
1334 int32_t result
= websocket
.Connect(
1335 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1336 if (result
== PP_OK_COMPLETIONPENDING
) {
1337 websocket
.WaitForClosed();
1338 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1339 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1340 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1341 ASSERT_EQ(2U, events
.size());
1343 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1344 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1346 pp::Var url
= websocket
.GetURL();
1347 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1353 std::string
TestWebSocket::TestUtilityValidConnect() {
1354 const pp::Var protocols
[] = { pp::Var() };
1355 TestWebSocketAPI
websocket(instance_
);
1356 int32_t result
= websocket
.Connect(
1357 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1358 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1359 websocket
.WaitForConnected();
1360 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1361 ASSERT_EQ(1U, events
.size());
1362 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1364 AreEqualWithString(websocket
.GetExtensions().pp_var(), std::string()));
1369 std::string
TestWebSocket::TestUtilityInvalidClose() {
1370 const pp::Var reason
= pp::Var(std::string("close for test"));
1372 // Close before connect.
1374 TestWebSocketAPI
websocket(instance_
);
1375 int32_t result
= websocket
.Close(
1376 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1377 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1378 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1381 // Close with bad arguments.
1383 TestWebSocketAPI
websocket(instance_
);
1384 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1386 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1387 websocket
.WaitForConnected();
1388 result
= websocket
.Close(1U, reason
);
1389 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1390 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1391 ASSERT_EQ(1U, events
.size());
1392 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1398 std::string
TestWebSocket::TestUtilityValidClose() {
1399 std::string
reason("close for test");
1400 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1404 TestWebSocketAPI
websocket(instance_
);
1405 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1406 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1407 websocket
.WaitForConnected();
1408 result
= websocket
.Close(
1409 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1410 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1411 websocket
.WaitForClosed();
1412 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1413 ASSERT_EQ(2U, events
.size());
1414 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1415 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1416 ASSERT_TRUE(events
[1].was_clean
);
1417 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1418 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1421 // Close in connecting.
1422 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1425 TestWebSocketAPI
websocket(instance_
);
1426 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1427 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1428 result
= websocket
.Close(
1429 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1430 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1431 websocket
.WaitForClosed();
1432 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1433 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1435 if (events
.size() == 3)
1436 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1437 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1438 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1439 ASSERT_FALSE(events
[index
].was_clean
);
1442 // Close in closing.
1443 // The first close will be done successfully, then the second one failed with
1444 // with PP_ERROR_INPROGRESS immediately.
1446 TestWebSocketAPI
websocket(instance_
);
1447 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1448 result
= websocket
.Close(
1449 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1450 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1451 result
= websocket
.Close(
1452 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1453 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1454 websocket
.WaitForClosed();
1455 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1456 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1458 if (events
.size() == 3)
1459 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1460 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1461 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1462 ASSERT_FALSE(events
[index
].was_clean
);
1468 std::string
TestWebSocket::TestUtilityGetProtocol() {
1469 const std::string
protocol("x-chat");
1470 const pp::Var protocols
[] = { pp::Var(protocol
) };
1471 std::string
url(GetFullURL(kProtocolTestServerURL
));
1473 TestWebSocketAPI
websocket(instance_
);
1474 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1475 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1476 websocket
.WaitForReceived();
1477 ASSERT_TRUE(AreEqualWithString(
1478 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1479 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1480 // The server to which this test connect returns the decided protocol as a
1481 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1482 // after EVENT_OPEN event.
1483 ASSERT_EQ(2U, events
.size());
1484 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1485 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1486 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1491 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1492 const pp::Var protocols
[] = { pp::Var() };
1493 TestWebSocketAPI
websocket(instance_
);
1495 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1496 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1497 websocket
.WaitForConnected();
1499 // Send 'hello pepper'.
1500 std::string
message1("hello pepper");
1501 result
= websocket
.Send(pp::Var(std::string(message1
)));
1502 ASSERT_EQ(PP_OK
, result
);
1504 // Receive echoed 'hello pepper'.
1505 websocket
.WaitForReceived();
1507 // Send 'goodbye pepper'.
1508 std::string
message2("goodbye pepper");
1509 result
= websocket
.Send(pp::Var(std::string(message2
)));
1511 // Receive echoed 'goodbye pepper'.
1512 websocket
.WaitForReceived();
1514 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1515 ASSERT_EQ(3U, events
.size());
1516 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1517 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1518 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), message1
.c_str()));
1519 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1520 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1525 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1526 const pp::Var protocols
[] = { pp::Var() };
1527 TestWebSocketAPI
websocket(instance_
);
1529 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1530 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1531 websocket
.WaitForConnected();
1533 // Send binary message.
1535 std::vector
<uint8_t> binary(len
);
1536 for (uint32_t i
= 0; i
< len
; ++i
)
1538 pp::VarArrayBuffer
message(len
);
1539 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1540 std::copy(binary
.begin(), binary
.end(), var_data
);
1541 result
= websocket
.Send(message
);
1542 ASSERT_EQ(PP_OK
, result
);
1544 // Receive echoed binary message.
1545 websocket
.WaitForReceived();
1547 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1548 ASSERT_EQ(2U, events
.size());
1549 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1550 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1551 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1556 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1557 // Connect to test echo server.
1558 const pp::Var protocols
[] = { pp::Var() };
1559 TestWebSocketAPI
websocket(instance_
);
1561 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1562 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1563 websocket
.WaitForConnected();
1565 // Prepare a large message that is not aligned with the internal buffer
1567 std::string
message(8193, 'x');
1568 uint64_t buffered_amount
= 0;
1570 for (sent
= 0; sent
< 100; sent
++) {
1571 result
= websocket
.Send(pp::Var(message
));
1572 ASSERT_EQ(PP_OK
, result
);
1573 buffered_amount
= websocket
.GetBufferedAmount();
1574 // Buffered amount size 262144 is too big for the internal buffer size.
1575 if (buffered_amount
> 262144)
1579 // Close connection.
1580 std::string reason
= "close while busy";
1581 result
= websocket
.Close(
1582 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1583 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1584 websocket
.WaitForClosed();
1585 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1587 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1588 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1590 // After connection closure, all sending requests fail and just increase
1591 // the bufferedAmount property.
1592 result
= websocket
.Send(pp::Var(std::string()));
1593 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1594 buffered_amount
= websocket
.GetBufferedAmount();
1595 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1596 base_buffered_amount
= buffered_amount
;
1598 result
= websocket
.Send(pp::Var(reason
));
1599 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1600 buffered_amount
= websocket
.GetBufferedAmount();
1601 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1602 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1604 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1605 ASSERT_EQ(events_on_closed
, events
.size());
1606 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1607 size_t last_event
= events_on_closed
- 1;
1608 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1609 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1610 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1612 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1613 ASSERT_TRUE(events
[last_event
].was_clean
);