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(),
263 static_cast<uint32_t>(string
.size()));
266 PP_Var
TestWebSocket::CreateVarBinary(const std::vector
<uint8_t>& binary
) {
268 arraybuffer_interface_
->Create(static_cast<uint32_t>(binary
.size()));
269 uint8_t* var_data
= static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
));
270 std::copy(binary
.begin(), binary
.end(), var_data
);
274 void TestWebSocket::ReleaseVar(const PP_Var
& var
) {
275 var_interface_
->Release(var
);
278 bool TestWebSocket::AreEqualWithString(const PP_Var
& var
,
279 const std::string
& string
) {
280 if (var
.type
!= PP_VARTYPE_STRING
)
282 uint32_t utf8_length
;
283 const char* utf8
= var_interface_
->VarToUtf8(var
, &utf8_length
);
284 if (utf8_length
!= string
.size())
286 if (string
.compare(utf8
))
291 bool TestWebSocket::AreEqualWithBinary(const PP_Var
& var
,
292 const std::vector
<uint8_t>& binary
) {
293 uint32_t buffer_size
= 0;
294 PP_Bool success
= arraybuffer_interface_
->ByteLength(var
, &buffer_size
);
295 if (!success
|| buffer_size
!= binary
.size())
297 if (!std::equal(binary
.begin(), binary
.end(),
298 static_cast<uint8_t*>(arraybuffer_interface_
->Map(var
))))
303 PP_Resource
TestWebSocket::Connect(const std::string
& url
,
305 const std::string
& protocol
) {
306 PP_Var protocols
[] = { PP_MakeUndefined() };
307 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
310 PP_Var url_var
= CreateVarString(url
);
311 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
312 uint32_t protocol_count
= 0U;
313 if (protocol
.size()) {
314 protocols
[0] = CreateVarString(protocol
);
317 callback
.WaitForResult(websocket_interface_
->Connect(
318 ws
, url_var
, protocols
, protocol_count
,
319 callback
.GetCallback().pp_completion_callback()));
322 ReleaseVar(protocols
[0]);
323 *result
= callback
.result();
327 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws
,
328 const std::string
& message
) {
329 PP_Var message_var
= CreateVarString(message
);
330 websocket_interface_
->SendMessage(ws
, message_var
);
331 ReleaseVar(message_var
);
334 std::string
TestWebSocket::TestIsWebSocket() {
335 // Test that a NULL resource isn't a websocket.
336 pp::Resource null_resource
;
338 websocket_interface_
->IsWebSocket(null_resource
.pp_resource());
339 ASSERT_FALSE(result
);
341 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
344 result
= websocket_interface_
->IsWebSocket(ws
);
347 core_interface_
->ReleaseResource(ws
);
352 std::string
TestWebSocket::TestUninitializedPropertiesAccess() {
353 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
356 uint64_t bufferedAmount
= websocket_interface_
->GetBufferedAmount(ws
);
357 ASSERT_EQ(0U, bufferedAmount
);
359 uint16_t close_code
= websocket_interface_
->GetCloseCode(ws
);
360 ASSERT_EQ(0U, close_code
);
362 PP_Var close_reason
= websocket_interface_
->GetCloseReason(ws
);
363 ASSERT_TRUE(AreEqualWithString(close_reason
, std::string()));
364 ReleaseVar(close_reason
);
366 PP_Bool close_was_clean
= websocket_interface_
->GetCloseWasClean(ws
);
367 ASSERT_EQ(PP_FALSE
, close_was_clean
);
369 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
370 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
371 ReleaseVar(extensions
);
373 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
374 ASSERT_TRUE(AreEqualWithString(protocol
, std::string()));
375 ReleaseVar(protocol
);
377 PP_WebSocketReadyState ready_state
=
378 websocket_interface_
->GetReadyState(ws
);
379 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ready_state
);
381 PP_Var url
= websocket_interface_
->GetURL(ws
);
382 ASSERT_TRUE(AreEqualWithString(url
, std::string()));
385 core_interface_
->ReleaseResource(ws
);
390 std::string
TestWebSocket::TestInvalidConnect() {
391 PP_Var protocols
[] = { PP_MakeUndefined() };
393 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
396 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
397 callback
.WaitForResult(websocket_interface_
->Connect(
398 ws
, PP_MakeUndefined(), protocols
, 1U,
399 callback
.GetCallback().pp_completion_callback()));
400 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
402 callback
.WaitForResult(websocket_interface_
->Connect(
403 ws
, PP_MakeUndefined(), protocols
, 1U,
404 callback
.GetCallback().pp_completion_callback()));
405 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback
.result());
407 core_interface_
->ReleaseResource(ws
);
409 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
411 ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
413 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
415 core_interface_
->ReleaseResource(ws
);
421 std::string
TestWebSocket::TestProtocols() {
422 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
423 PP_Var bad_protocols
[] = {
424 CreateVarString("x-test"),
425 CreateVarString("x-test")
427 PP_Var good_protocols
[] = {
428 CreateVarString("x-test"),
429 CreateVarString("x-yatest")
432 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
434 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
435 callback
.WaitForResult(websocket_interface_
->Connect(
436 ws
, url
, bad_protocols
, 2U,
437 callback
.GetCallback().pp_completion_callback()));
438 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
439 core_interface_
->ReleaseResource(ws
);
441 ws
= websocket_interface_
->Create(instance_
->pp_instance());
443 int32_t result
= websocket_interface_
->Connect(
444 ws
, url
, good_protocols
, 2U, PP_BlockUntilComplete());
445 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, result
);
446 core_interface_
->ReleaseResource(ws
);
449 for (int i
= 0; i
< 2; ++i
) {
450 ReleaseVar(bad_protocols
[i
]);
451 ReleaseVar(good_protocols
[i
]);
453 core_interface_
->ReleaseResource(ws
);
458 std::string
TestWebSocket::TestGetURL() {
459 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
461 PP_Resource ws
= Connect(kInvalidURLs
[i
], &result
, std::string());
463 PP_Var url
= websocket_interface_
->GetURL(ws
);
464 ASSERT_TRUE(AreEqualWithString(url
, kInvalidURLs
[i
]));
465 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
468 core_interface_
->ReleaseResource(ws
);
474 std::string
TestWebSocket::TestValidConnect() {
476 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
478 ASSERT_EQ(PP_OK
, result
);
479 PP_Var extensions
= websocket_interface_
->GetExtensions(ws
);
480 ASSERT_TRUE(AreEqualWithString(extensions
, std::string()));
481 core_interface_
->ReleaseResource(ws
);
482 ReleaseVar(extensions
);
487 std::string
TestWebSocket::TestInvalidClose() {
488 PP_Var reason
= CreateVarString("close for test");
489 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
490 TestCompletionCallback
async_callback(instance_
->pp_instance(), PP_REQUIRED
);
492 // Close before connect.
493 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
494 callback
.WaitForResult(websocket_interface_
->Close(
495 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
496 callback
.GetCallback().pp_completion_callback()));
497 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
498 core_interface_
->ReleaseResource(ws
);
500 // Close with bad arguments.
502 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
504 ASSERT_EQ(PP_OK
, result
);
505 callback
.WaitForResult(websocket_interface_
->Close(
506 ws
, 1U, reason
, callback
.GetCallback().pp_completion_callback()));
507 ASSERT_EQ(PP_ERROR_NOACCESS
, callback
.result());
508 core_interface_
->ReleaseResource(ws
);
510 // Close with PP_VARTYPE_NULL.
511 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
513 ASSERT_EQ(PP_OK
, result
);
514 callback
.WaitForResult(websocket_interface_
->Close(
515 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
516 callback
.GetCallback().pp_completion_callback()));
517 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
518 core_interface_
->ReleaseResource(ws
);
520 // Close with PP_VARTYPE_NULL and ongoing receive message.
521 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
523 ASSERT_EQ(PP_OK
, result
);
524 PP_Var receive_message_var
;
525 result
= websocket_interface_
->ReceiveMessage(
526 ws
, &receive_message_var
,
527 async_callback
.GetCallback().pp_completion_callback());
528 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
529 callback
.WaitForResult(websocket_interface_
->Close(
530 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeNull(),
531 callback
.GetCallback().pp_completion_callback()));
532 ASSERT_EQ(PP_ERROR_BADARGUMENT
, callback
.result());
533 const char* send_message
= "hi";
534 PP_Var send_message_var
= CreateVarString(send_message
);
535 result
= websocket_interface_
->SendMessage(ws
, send_message_var
);
536 ReleaseVar(send_message_var
);
537 ASSERT_EQ(PP_OK
, result
);
538 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
539 ASSERT_EQ(PP_OK
, async_callback
.result());
540 ASSERT_TRUE(AreEqualWithString(receive_message_var
, send_message
));
541 ReleaseVar(receive_message_var
);
542 core_interface_
->ReleaseResource(ws
);
545 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
547 ASSERT_EQ(PP_OK
, result
);
548 result
= websocket_interface_
->Close(
549 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
550 async_callback
.GetCallback().pp_completion_callback());
551 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
552 // Call another Close() before previous one is in progress.
553 result
= websocket_interface_
->Close(
554 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
555 callback
.GetCallback().pp_completion_callback());
556 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
557 async_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
558 ASSERT_EQ(PP_OK
, async_callback
.result());
559 // Call another Close() after previous one is completed.
560 // This Close() must do nothing and reports no error.
561 callback
.WaitForResult(websocket_interface_
->Close(
562 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
563 callback
.GetCallback().pp_completion_callback()));
564 ASSERT_EQ(PP_OK
, callback
.result());
565 core_interface_
->ReleaseResource(ws
);
572 // TODO(tyoshino): Consider splitting this test into smaller ones.
573 // http://crbug.com/397035
574 std::string
TestWebSocket::TestValidClose() {
575 PP_Var reason
= CreateVarString("close for test");
576 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
577 TestCompletionCallback
another_callback(
578 instance_
->pp_instance(), callback_type());
582 PP_Resource ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
584 ASSERT_EQ(PP_OK
, result
);
585 callback
.WaitForResult(websocket_interface_
->Close(
586 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
587 callback
.GetCallback().pp_completion_callback()));
588 CHECK_CALLBACK_BEHAVIOR(callback
);
589 ASSERT_EQ(PP_OK
, callback
.result());
590 core_interface_
->ReleaseResource(ws
);
592 // Close without code and reason.
593 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
595 ASSERT_EQ(PP_OK
, result
);
596 callback
.WaitForResult(websocket_interface_
->Close(
597 ws
, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED
, reason
,
598 callback
.GetCallback().pp_completion_callback()));
599 CHECK_CALLBACK_BEHAVIOR(callback
);
600 ASSERT_EQ(PP_OK
, callback
.result());
601 core_interface_
->ReleaseResource(ws
);
603 // Close with PP_VARTYPE_UNDEFINED.
604 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
606 ASSERT_EQ(PP_OK
, result
);
607 callback
.WaitForResult(websocket_interface_
->Close(
608 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
609 callback
.GetCallback().pp_completion_callback()));
610 CHECK_CALLBACK_BEHAVIOR(callback
);
611 ASSERT_EQ(PP_OK
, callback
.result());
612 core_interface_
->ReleaseResource(ws
);
614 // Close in CONNECTING state.
615 // The ongoing Connect() fails with PP_ERROR_ABORTED, then the Close()
616 // completes successfully.
617 ws
= websocket_interface_
->Create(instance_
->pp_instance());
618 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
619 PP_Var protocols
[] = { PP_MakeUndefined() };
620 result
= websocket_interface_
->Connect(
621 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
622 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
623 result
= websocket_interface_
->Close(
624 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
625 another_callback
.GetCallback().pp_completion_callback());
626 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
627 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
628 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
629 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
630 ASSERT_EQ(PP_OK
, another_callback
.result());
631 core_interface_
->ReleaseResource(ws
);
634 // Close while already closing.
635 // The first Close will succeed, and the second one will synchronously fail
636 // with PP_ERROR_INPROGRESS.
637 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
639 ASSERT_EQ(PP_OK
, result
);
640 result
= websocket_interface_
->Close(
641 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
642 callback
.GetCallback().pp_completion_callback());
643 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
644 result
= websocket_interface_
->Close(
645 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
646 another_callback
.GetCallback().pp_completion_callback());
647 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
648 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
649 ASSERT_EQ(PP_OK
, callback
.result());
650 core_interface_
->ReleaseResource(ws
);
652 // Close with ongoing ReceiveMessage.
653 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
655 ASSERT_EQ(PP_OK
, result
);
656 PP_Var receive_message_var
;
657 result
= websocket_interface_
->ReceiveMessage(
658 ws
, &receive_message_var
,
659 callback
.GetCallback().pp_completion_callback());
660 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
661 result
= websocket_interface_
->Close(
662 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
663 another_callback
.GetCallback().pp_completion_callback());
664 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
665 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
666 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
667 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
668 ASSERT_EQ(PP_OK
, another_callback
.result());
669 core_interface_
->ReleaseResource(ws
);
671 // Close with PP_VARTYPE_UNDEFINED for reason and ongoing ReceiveMessage.
672 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
674 ASSERT_EQ(PP_OK
, result
);
675 result
= websocket_interface_
->ReceiveMessage(
676 ws
, &receive_message_var
,
677 callback
.GetCallback().pp_completion_callback());
678 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
679 result
= websocket_interface_
->Close(
680 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
681 another_callback
.GetCallback().pp_completion_callback());
682 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
683 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
684 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
685 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
686 ASSERT_EQ(PP_OK
, another_callback
.result());
687 core_interface_
->ReleaseResource(ws
);
689 // Server initiated closing handshake.
691 GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, std::string());
693 ASSERT_EQ(PP_OK
, result
);
694 // Text messsage "1000 bye" requests the server to initiate closing handshake
695 // with code being 1000 and reason being "bye".
696 PP_Var close_request_var
= CreateVarString("1000 bye");
697 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
698 ReleaseVar(close_request_var
);
699 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
700 ws
, &receive_message_var
,
701 callback
.GetCallback().pp_completion_callback()));
702 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
703 core_interface_
->ReleaseResource(ws
);
710 std::string
TestWebSocket::TestGetProtocol() {
711 const char* expected_protocols
[] = {
716 for (int i
= 0; expected_protocols
[i
]; ++i
) {
717 std::string
url(GetFullURL(kProtocolTestServerURL
));
718 url
+= expected_protocols
[i
];
720 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
722 ASSERT_EQ(PP_OK
, result
);
724 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
725 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
727 ReleaseVar(protocol
);
728 core_interface_
->ReleaseResource(ws
);
734 std::string
TestWebSocket::TestTextSendReceive() {
735 // Connect to test echo server.
736 int32_t connect_result
;
738 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
740 ASSERT_EQ(PP_OK
, connect_result
);
742 // Send 'hello pepper' text message.
743 const char* message
= "hello pepper";
744 PP_Var message_var
= CreateVarString(message
);
745 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
746 ReleaseVar(message_var
);
747 ASSERT_EQ(PP_OK
, result
);
749 // Receive echoed 'hello pepper'.
750 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
751 PP_Var received_message
;
752 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
753 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
754 ASSERT_EQ(PP_OK
, callback
.result());
755 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
756 ReleaseVar(received_message
);
757 core_interface_
->ReleaseResource(ws
);
762 // Run as a BACKGROUND test.
763 std::string
TestWebSocket::TestTextSendReceiveTwice() {
764 // Connect to test echo server.
765 int32_t connect_result
;
767 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
769 ASSERT_EQ(PP_OK
, connect_result
);
770 pp::MessageLoop message_loop
= pp::MessageLoop::GetCurrent();
771 pp::CompletionCallbackFactory
<TestWebSocket
> factory(this);
773 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
774 ws
, std::string("hello")));
775 // When the server receives 'Goodbye', it closes the session.
776 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
777 ws
, std::string("Goodbye")));
778 message_loop
.PostQuit(false);
781 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
782 PP_Var received_message
;
783 int32_t result
= websocket_interface_
->ReceiveMessage(
784 ws
, &received_message
, callback
.GetCallback().pp_completion_callback());
785 ASSERT_EQ(PP_OK
, result
);
786 // Since we don't run the message loop, the callback will stay
787 // "pending and scheduled to run" state.
789 // Waiting for the connection close which will be done by the server.
791 PP_WebSocketReadyState ready_state
=
792 websocket_interface_
->GetReadyState(ws
);
793 if (ready_state
!= PP_WEBSOCKETREADYSTATE_CONNECTING
&&
794 ready_state
!= PP_WEBSOCKETREADYSTATE_OPEN
) {
797 PlatformSleep(100); // 100ms
800 // Cleanup the message loop
801 message_loop
.PostQuit(false);
804 ASSERT_EQ(PP_OK
, callback
.result());
805 ASSERT_TRUE(AreEqualWithString(received_message
, "hello"));
806 ReleaseVar(received_message
);
807 core_interface_
->ReleaseResource(ws
);
811 std::string
TestWebSocket::TestBinarySendReceive() {
812 // Connect to test echo server.
813 int32_t connect_result
;
815 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
817 ASSERT_EQ(PP_OK
, connect_result
);
819 // Send binary message.
820 std::vector
<uint8_t> binary(256);
821 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
823 PP_Var message_var
= CreateVarBinary(binary
);
824 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
825 ReleaseVar(message_var
);
826 ASSERT_EQ(PP_OK
, result
);
828 // Receive echoed binary.
829 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
830 PP_Var received_message
;
831 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
832 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
833 ASSERT_EQ(PP_OK
, callback
.result());
834 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
835 ReleaseVar(received_message
);
836 core_interface_
->ReleaseResource(ws
);
841 std::string
TestWebSocket::TestStressedSendReceive() {
842 // Connect to test echo server.
843 int32_t connect_result
;
845 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
847 ASSERT_EQ(PP_OK
, connect_result
);
849 // Prepare PP_Var objects to send.
850 const char* text
= "hello pepper";
851 PP_Var text_var
= CreateVarString(text
);
852 std::vector
<uint8_t> binary(256);
853 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
855 PP_Var binary_var
= CreateVarBinary(binary
);
856 // Prepare very large binary data over 64KiB. Object serializer in
857 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
858 // to SRPC. In case received data over 64KiB exists, a specific code handles
859 // this large data via asynchronous callback from main thread. This data
860 // intends to test the code.
861 std::vector
<uint8_t> large_binary(65 * 1024);
862 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
863 large_binary
[i
] = i
& 0xff;
864 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
866 // Send many messages.
868 for (int i
= 0; i
< 256; ++i
) {
869 result
= websocket_interface_
->SendMessage(ws
, text_var
);
870 ASSERT_EQ(PP_OK
, result
);
871 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
872 ASSERT_EQ(PP_OK
, result
);
874 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
875 ASSERT_EQ(PP_OK
, result
);
876 ReleaseVar(text_var
);
877 ReleaseVar(binary_var
);
878 ReleaseVar(large_binary_var
);
880 // Receive echoed data.
881 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
882 for (int i
= 0; i
<= 512; ++i
) {
883 PP_Var received_message
;
884 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
885 ws
, &received_message
,
886 callback
.GetCallback().pp_completion_callback()));
887 ASSERT_EQ(PP_OK
, callback
.result());
889 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
891 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
893 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
895 ReleaseVar(received_message
);
897 core_interface_
->ReleaseResource(ws
);
902 std::string
TestWebSocket::TestBufferedAmount() {
903 // Connect to test echo server.
904 int32_t connect_result
;
906 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
908 ASSERT_EQ(PP_OK
, connect_result
);
910 // Prepare a large message that is not aligned with the internal buffer
912 std::string
message(8193, 'x');
913 PP_Var message_var
= CreateVarString(message
);
915 uint64_t buffered_amount
= 0;
917 for (int i
= 0; i
< 100; i
++) {
918 result
= websocket_interface_
->SendMessage(ws
, message_var
);
919 ASSERT_EQ(PP_OK
, result
);
920 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
921 // Buffered amount size 262144 is too big for the internal buffer size.
922 if (buffered_amount
> 262144)
927 std::string reason_str
= "close while busy";
928 PP_Var reason
= CreateVarString(reason_str
.c_str());
929 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
930 result
= websocket_interface_
->Close(
931 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
932 callback
.GetCallback().pp_completion_callback());
933 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
934 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
935 websocket_interface_
->GetReadyState(ws
));
937 callback
.WaitForResult(result
);
938 ASSERT_EQ(PP_OK
, callback
.result());
939 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
940 websocket_interface_
->GetReadyState(ws
));
942 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
944 // After connection closure, all sending requests fail and just increase
945 // the bufferedAmount property.
946 PP_Var empty_string
= CreateVarString(std::string());
947 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
948 ASSERT_EQ(PP_ERROR_FAILED
, result
);
949 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
950 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
951 base_buffered_amount
= buffered_amount
;
953 result
= websocket_interface_
->SendMessage(ws
, reason
);
954 ASSERT_EQ(PP_ERROR_FAILED
, result
);
955 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
956 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
957 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
959 ReleaseVar(message_var
);
961 ReleaseVar(empty_string
);
962 core_interface_
->ReleaseResource(ws
);
967 // Test abort behaviors where a WebSocket PP_Resource is released while each
968 // function is in-flight on the WebSocket PP_Resource.
969 std::string
TestWebSocket::TestAbortCallsWithCallback() {
970 // Following tests make sure the behavior for functions which require a
971 // callback. The callback must get a PP_ERROR_ABORTED.
973 // Test the behavior for Connect().
974 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
976 std::string url
= GetFullURL(kEchoServerURL
);
977 PP_Var url_var
= CreateVarString(url
);
978 TestCompletionCallback
connect_callback(
979 instance_
->pp_instance(), callback_type());
980 int32_t result
= websocket_interface_
->Connect(
981 ws
, url_var
, NULL
, 0,
982 connect_callback
.GetCallback().pp_completion_callback());
983 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
984 core_interface_
->ReleaseResource(ws
);
985 connect_callback
.WaitForResult(result
);
986 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
988 // Test the behavior for Close().
989 ws
= Connect(url
, &result
, std::string());
991 ASSERT_EQ(PP_OK
, result
);
992 PP_Var reason_var
= CreateVarString("abort");
993 TestCompletionCallback
close_callback(
994 instance_
->pp_instance(), callback_type());
995 result
= websocket_interface_
->Close(
996 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
997 close_callback
.GetCallback().pp_completion_callback());
998 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
999 core_interface_
->ReleaseResource(ws
);
1000 close_callback
.WaitForResult(result
);
1001 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1002 ReleaseVar(reason_var
);
1004 // Test the behavior for ReceiveMessage().
1005 // Make sure the simplest case to wait for data which never arrives, here.
1006 ws
= Connect(url
, &result
, std::string());
1008 ASSERT_EQ(PP_OK
, result
);
1010 TestCompletionCallback
receive_callback(
1011 instance_
->pp_instance(), callback_type());
1012 result
= websocket_interface_
->ReceiveMessage(
1014 receive_callback
.GetCallback().pp_completion_callback());
1015 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1016 core_interface_
->ReleaseResource(ws
);
1017 receive_callback
.WaitForResult(result
);
1018 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1020 // Release the resource in the aborting receive completion callback which is
1021 // introduced by calling Close().
1022 ws
= Connect(url
, &result
, std::string());
1024 ASSERT_EQ(PP_OK
, result
);
1025 result
= websocket_interface_
->ReceiveMessage(
1027 receive_callback
.GetCallback().pp_completion_callback());
1028 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1029 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
1030 receive_callback
.SetDelegate(&receive_delegate
);
1031 result
= websocket_interface_
->Close(
1032 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1033 close_callback
.GetCallback().pp_completion_callback());
1034 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1035 receive_callback
.WaitForResult(result
);
1036 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
1037 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1038 close_callback
.WaitForResult(result
);
1039 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1040 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1042 ReleaseVar(url_var
);
1047 std::string
TestWebSocket::TestAbortSendMessageCall() {
1048 // Test the behavior for SendMessage().
1049 // This function doesn't require a callback, but operation will be done
1050 // asynchronously in WebKit and browser process.
1051 std::vector
<uint8_t> large_binary(65 * 1024);
1052 PP_Var large_var
= CreateVarBinary(large_binary
);
1055 std::string url
= GetFullURL(kEchoServerURL
);
1056 PP_Resource ws
= Connect(url
, &result
, std::string());
1058 ASSERT_EQ(PP_OK
, result
);
1059 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1060 ASSERT_EQ(PP_OK
, result
);
1061 core_interface_
->ReleaseResource(ws
);
1062 ReleaseVar(large_var
);
1067 std::string
TestWebSocket::TestAbortCloseCall() {
1068 // Release the resource in the close completion callback.
1070 std::string url
= GetFullURL(kEchoServerURL
);
1071 PP_Resource ws
= Connect(url
, &result
, std::string());
1073 ASSERT_EQ(PP_OK
, result
);
1074 TestCompletionCallback
close_callback(
1075 instance_
->pp_instance(), callback_type());
1076 result
= websocket_interface_
->Close(
1077 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1078 close_callback
.GetCallback().pp_completion_callback());
1079 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
1080 close_callback
.SetDelegate(&close_delegate
);
1081 close_callback
.WaitForResult(result
);
1082 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1083 ASSERT_EQ(PP_OK
, close_callback
.result());
1088 std::string
TestWebSocket::TestAbortReceiveMessageCall() {
1089 // Test the behavior where receive process might be in-flight.
1090 std::vector
<uint8_t> large_binary(65 * 1024);
1091 PP_Var large_var
= CreateVarBinary(large_binary
);
1092 const char* text
= "yukarin";
1093 PP_Var text_var
= CreateVarString(text
);
1095 std::string url
= GetFullURL(kEchoServerURL
);
1099 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1100 // number of message(s) before releasing the WebSocket. The WebSocket is
1101 // released while the next message is going to be received.
1102 const int trial_count
= 8;
1103 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1104 ws
= Connect(url
, &result
, std::string());
1106 ASSERT_EQ(PP_OK
, result
);
1107 for (int i
= 0; i
<= trial_count
; ++i
) {
1108 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1109 ASSERT_EQ(PP_OK
, result
);
1111 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1113 for (int i
= 0; i
< trial
; ++i
) {
1114 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1115 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1116 ASSERT_EQ(PP_OK
, callback
.result());
1117 ASSERT_TRUE(AreEqualWithString(var
, text
));
1120 result
= websocket_interface_
->ReceiveMessage(
1121 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1122 core_interface_
->ReleaseResource(ws
);
1123 if (result
!= PP_OK
) {
1124 callback
.WaitForResult(result
);
1125 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1128 // Same test, but the last receiving message is large message over 64KiB.
1129 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1130 ws
= Connect(url
, &result
, std::string());
1132 ASSERT_EQ(PP_OK
, result
);
1133 for (int i
= 0; i
<= trial_count
; ++i
) {
1135 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1137 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1138 ASSERT_EQ(PP_OK
, result
);
1140 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1142 for (int i
= 0; i
< trial
; ++i
) {
1143 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1144 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1145 ASSERT_EQ(PP_OK
, callback
.result());
1146 ASSERT_TRUE(AreEqualWithString(var
, text
));
1149 result
= websocket_interface_
->ReceiveMessage(
1150 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1151 core_interface_
->ReleaseResource(ws
);
1152 if (result
!= PP_OK
) {
1153 callback
.WaitForResult(result
);
1154 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1158 ReleaseVar(large_var
);
1159 ReleaseVar(text_var
);
1164 std::string
TestWebSocket::TestClosedFromServerWhileSending() {
1165 // Connect to test echo server.
1166 const pp::Var protocols
[] = { pp::Var() };
1167 TestWebSocketAPI
websocket(instance_
);
1169 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1170 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1171 websocket
.WaitForConnected();
1173 result
= websocket
.Send(pp::Var("hello"));
1174 ASSERT_EQ(PP_OK
, result
);
1175 result
= websocket
.Send(pp::Var("Goodbye"));
1176 // We send many messages so that PepperWebSocketHost::SendText is called
1177 // after PepperWebSocketHost::didClose is called.
1178 // Note: We must not wait for CLOSED event here because
1179 // WebSocketResource::SendMessage doesn't call PepperWebSocketHost::SendText
1180 // when its internal state is CLOSING or CLOSED. We want to test if the
1181 // pepper WebSocket works well when WebSocketResource is OPEN and
1182 // PepperWebSocketHost is CLOSED.
1183 for (size_t i
= 0; i
< 10000; ++i
) {
1184 result
= websocket
.Send(pp::Var(""));
1185 ASSERT_EQ(PP_OK
, result
);
1191 std::string
TestWebSocket::TestCcInterfaces() {
1192 // C++ bindings is simple straightforward, then just verifies interfaces work
1193 // as a interface bridge fine.
1194 pp::WebSocket
ws(instance_
);
1196 // Check uninitialized properties access.
1197 ASSERT_EQ(0, ws
.GetBufferedAmount());
1198 ASSERT_EQ(0, ws
.GetCloseCode());
1199 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), std::string()));
1200 ASSERT_FALSE(ws
.GetCloseWasClean());
1201 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), std::string()));
1202 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1203 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1204 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), std::string()));
1206 // Check communication interfaces (connect, send, receive, and close).
1207 TestCompletionCallback
connect_callback(
1208 instance_
->pp_instance(), callback_type());
1209 connect_callback
.WaitForResult(ws
.Connect(
1210 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U,
1211 connect_callback
.GetCallback()));
1212 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1213 ASSERT_EQ(PP_OK
, connect_callback
.result());
1215 std::string
text_message("hello C++");
1216 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1217 ASSERT_EQ(PP_OK
, result
);
1219 std::vector
<uint8_t> binary(256);
1220 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1222 result
= ws
.SendMessage(
1223 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1224 ASSERT_EQ(PP_OK
, result
);
1226 pp::Var text_receive_var
;
1227 TestCompletionCallback
text_receive_callback(
1228 instance_
->pp_instance(), callback_type());
1229 text_receive_callback
.WaitForResult(
1230 ws
.ReceiveMessage(&text_receive_var
,
1231 text_receive_callback
.GetCallback()));
1232 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1234 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1236 pp::Var binary_receive_var
;
1237 TestCompletionCallback
binary_receive_callback(
1238 instance_
->pp_instance(), callback_type());
1239 binary_receive_callback
.WaitForResult(
1240 ws
.ReceiveMessage(&binary_receive_var
,
1241 binary_receive_callback
.GetCallback()));
1242 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1243 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1245 TestCompletionCallback
close_callback(
1246 instance_
->pp_instance(), callback_type());
1247 std::string
reason("bye");
1248 close_callback
.WaitForResult(ws
.Close(
1249 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
),
1250 close_callback
.GetCallback()));
1251 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1252 ASSERT_EQ(PP_OK
, close_callback
.result());
1254 // Check initialized properties access.
1255 ASSERT_EQ(0, ws
.GetBufferedAmount());
1256 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1258 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1259 ASSERT_EQ(true, ws
.GetCloseWasClean());
1260 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1261 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1262 ASSERT_TRUE(AreEqualWithString(
1263 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1268 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1269 const pp::Var protocols
[] = { pp::Var() };
1271 TestWebSocketAPI
websocket(instance_
);
1272 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1273 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1274 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1276 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1277 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1278 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1280 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1281 TestWebSocketAPI
ws(instance_
);
1282 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1283 if (result
== PP_OK_COMPLETIONPENDING
) {
1285 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1286 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1287 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1288 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1290 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1291 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1298 std::string
TestWebSocket::TestUtilityProtocols() {
1299 const pp::Var bad_protocols
[] = {
1300 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1301 const pp::Var good_protocols
[] = {
1302 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1305 TestWebSocketAPI
websocket(instance_
);
1306 int32_t result
= websocket
.Connect(
1307 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1308 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1309 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1313 TestWebSocketAPI
websocket(instance_
);
1314 int32_t result
= websocket
.Connect(
1315 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1316 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1317 websocket
.WaitForConnected();
1318 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1319 // Protocol arguments are valid, but this test run without a WebSocket
1320 // server. As a result, OnError() and OnClose() are invoked because of
1321 // a connection establishment failure.
1322 ASSERT_EQ(2U, events
.size());
1323 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1324 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1325 ASSERT_FALSE(events
[1].was_clean
);
1331 std::string
TestWebSocket::TestUtilityGetURL() {
1332 const pp::Var protocols
[] = { pp::Var() };
1334 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1335 TestWebSocketAPI
websocket(instance_
);
1336 int32_t result
= websocket
.Connect(
1337 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1338 if (result
== PP_OK_COMPLETIONPENDING
) {
1339 websocket
.WaitForClosed();
1340 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1341 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1342 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1343 ASSERT_EQ(2U, events
.size());
1345 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1346 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1348 pp::Var url
= websocket
.GetURL();
1349 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1355 std::string
TestWebSocket::TestUtilityValidConnect() {
1356 const pp::Var protocols
[] = { pp::Var() };
1357 TestWebSocketAPI
websocket(instance_
);
1358 int32_t result
= websocket
.Connect(
1359 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1360 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1361 websocket
.WaitForConnected();
1362 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1363 ASSERT_EQ(1U, events
.size());
1364 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1366 AreEqualWithString(websocket
.GetExtensions().pp_var(), std::string()));
1371 std::string
TestWebSocket::TestUtilityInvalidClose() {
1372 const pp::Var reason
= pp::Var(std::string("close for test"));
1374 // Close before connect.
1376 TestWebSocketAPI
websocket(instance_
);
1377 int32_t result
= websocket
.Close(
1378 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1379 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1380 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1383 // Close with bad arguments.
1385 TestWebSocketAPI
websocket(instance_
);
1386 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1388 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1389 websocket
.WaitForConnected();
1390 result
= websocket
.Close(1U, reason
);
1391 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1392 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1393 ASSERT_EQ(1U, events
.size());
1394 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1400 std::string
TestWebSocket::TestUtilityValidClose() {
1401 std::string
reason("close for test");
1402 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1406 TestWebSocketAPI
websocket(instance_
);
1407 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1408 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1409 websocket
.WaitForConnected();
1410 result
= websocket
.Close(
1411 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1412 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1413 websocket
.WaitForClosed();
1414 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1415 ASSERT_EQ(2U, events
.size());
1416 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1417 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1418 ASSERT_TRUE(events
[1].was_clean
);
1419 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1420 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1423 // Close in connecting.
1424 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1427 TestWebSocketAPI
websocket(instance_
);
1428 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1429 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1430 result
= websocket
.Close(
1431 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1432 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1433 websocket
.WaitForClosed();
1434 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1435 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1437 if (events
.size() == 3)
1438 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1439 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1440 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1441 ASSERT_FALSE(events
[index
].was_clean
);
1444 // Close in closing.
1445 // The first close will be done successfully, then the second one failed with
1446 // with PP_ERROR_INPROGRESS immediately.
1448 TestWebSocketAPI
websocket(instance_
);
1449 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1450 result
= websocket
.Close(
1451 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1452 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1453 result
= websocket
.Close(
1454 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1455 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1456 websocket
.WaitForClosed();
1457 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1458 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1460 if (events
.size() == 3)
1461 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1462 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1463 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1464 ASSERT_FALSE(events
[index
].was_clean
);
1470 std::string
TestWebSocket::TestUtilityGetProtocol() {
1471 const std::string
protocol("x-chat");
1472 const pp::Var protocols
[] = { pp::Var(protocol
) };
1473 std::string
url(GetFullURL(kProtocolTestServerURL
));
1475 TestWebSocketAPI
websocket(instance_
);
1476 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1477 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1478 websocket
.WaitForReceived();
1479 ASSERT_TRUE(AreEqualWithString(
1480 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1481 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1482 // The server to which this test connect returns the decided protocol as a
1483 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1484 // after EVENT_OPEN event.
1485 ASSERT_EQ(2U, events
.size());
1486 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1487 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1488 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1493 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1494 const pp::Var protocols
[] = { pp::Var() };
1495 TestWebSocketAPI
websocket(instance_
);
1497 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1498 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1499 websocket
.WaitForConnected();
1501 // Send 'hello pepper'.
1502 std::string
message1("hello pepper");
1503 result
= websocket
.Send(pp::Var(std::string(message1
)));
1504 ASSERT_EQ(PP_OK
, result
);
1506 // Receive echoed 'hello pepper'.
1507 websocket
.WaitForReceived();
1509 // Send 'goodbye pepper'.
1510 std::string
message2("goodbye pepper");
1511 result
= websocket
.Send(pp::Var(std::string(message2
)));
1513 // Receive echoed 'goodbye pepper'.
1514 websocket
.WaitForReceived();
1516 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1517 ASSERT_EQ(3U, 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(AreEqualWithString(events
[1].var
.pp_var(), message1
.c_str()));
1521 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1522 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1527 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1528 const pp::Var protocols
[] = { pp::Var() };
1529 TestWebSocketAPI
websocket(instance_
);
1531 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1532 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1533 websocket
.WaitForConnected();
1535 // Send binary message.
1537 std::vector
<uint8_t> binary(len
);
1538 for (uint32_t i
= 0; i
< len
; ++i
)
1540 pp::VarArrayBuffer
message(len
);
1541 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1542 std::copy(binary
.begin(), binary
.end(), var_data
);
1543 result
= websocket
.Send(message
);
1544 ASSERT_EQ(PP_OK
, result
);
1546 // Receive echoed binary message.
1547 websocket
.WaitForReceived();
1549 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1550 ASSERT_EQ(2U, events
.size());
1551 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1552 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1553 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1558 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1559 // Connect to test echo server.
1560 const pp::Var protocols
[] = { pp::Var() };
1561 TestWebSocketAPI
websocket(instance_
);
1563 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1564 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1565 websocket
.WaitForConnected();
1567 // Prepare a large message that is not aligned with the internal buffer
1569 std::string
message(8193, 'x');
1570 uint64_t buffered_amount
= 0;
1572 for (sent
= 0; sent
< 100; sent
++) {
1573 result
= websocket
.Send(pp::Var(message
));
1574 ASSERT_EQ(PP_OK
, result
);
1575 buffered_amount
= websocket
.GetBufferedAmount();
1576 // Buffered amount size 262144 is too big for the internal buffer size.
1577 if (buffered_amount
> 262144)
1581 // Close connection.
1582 std::string reason
= "close while busy";
1583 result
= websocket
.Close(
1584 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1585 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1586 websocket
.WaitForClosed();
1587 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1589 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1590 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1592 // After connection closure, all sending requests fail and just increase
1593 // the bufferedAmount property.
1594 result
= websocket
.Send(pp::Var(std::string()));
1595 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1596 buffered_amount
= websocket
.GetBufferedAmount();
1597 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1598 base_buffered_amount
= buffered_amount
;
1600 result
= websocket
.Send(pp::Var(reason
));
1601 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1602 buffered_amount
= websocket
.GetBufferedAmount();
1603 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1604 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1606 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1607 ASSERT_EQ(events_on_closed
, events
.size());
1608 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1609 size_t last_event
= events_on_closed
- 1;
1610 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1611 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1612 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1614 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1615 ASSERT_TRUE(events
[last_event
].was_clean
);