1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/tests/test_websocket.h"
15 #include "ppapi/c/dev/ppb_testing_dev.h"
16 #include "ppapi/c/pp_bool.h"
17 #include "ppapi/c/pp_completion_callback.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/c/pp_instance.h"
20 #include "ppapi/c/pp_resource.h"
21 #include "ppapi/c/pp_var.h"
22 #include "ppapi/c/ppb_core.h"
23 #include "ppapi/c/ppb_var.h"
24 #include "ppapi/c/ppb_var_array_buffer.h"
25 #include "ppapi/c/ppb_websocket.h"
26 #include "ppapi/cpp/instance.h"
27 #include "ppapi/cpp/module.h"
28 #include "ppapi/cpp/var_array_buffer.h"
29 #include "ppapi/cpp/websocket.h"
30 #include "ppapi/tests/test_utils.h"
31 #include "ppapi/tests/testing_instance.h"
32 #include "ppapi/utility/websocket/websocket_api.h"
34 // net::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 kCloseFrameSize
= 6;
51 const uint64_t kMessageFrameOverhead
= 6;
55 struct WebSocketEvent
{
63 WebSocketEvent(EventType type
,
69 close_code(close_code
),
78 class ReleaseResourceDelegate
: public TestCompletionCallback::Delegate
{
80 explicit ReleaseResourceDelegate(const PPB_Core
* core_interface
,
82 : core_interface_(core_interface
),
86 // TestCompletionCallback::Delegate implementation.
87 virtual void OnCallback(void* user_data
, int32_t result
) {
89 core_interface_
->ReleaseResource(resource_
);
93 const PPB_Core
* core_interface_
;
94 PP_Resource resource_
;
97 class TestWebSocketAPI
: public pp::WebSocketAPI
{
99 explicit TestWebSocketAPI(pp::Instance
* instance
)
100 : pp::WebSocketAPI(instance
),
104 wait_for_connected_(false),
105 wait_for_received_(false),
106 wait_for_closed_(false),
107 instance_(instance
->pp_instance()) {
110 virtual void WebSocketDidOpen() {
112 WebSocketEvent(WebSocketEvent::EVENT_OPEN
, true, 0U, pp::Var()));
114 if (wait_for_connected_
) {
115 GetTestingInterface()->QuitMessageLoop(instance_
);
116 wait_for_connected_
= false;
120 virtual void WebSocketDidClose(
121 bool was_clean
, uint16_t code
, const pp::Var
& reason
) {
123 WebSocketEvent(WebSocketEvent::EVENT_CLOSE
, was_clean
, code
, reason
));
126 if (wait_for_connected_
|| wait_for_closed_
) {
127 GetTestingInterface()->QuitMessageLoop(instance_
);
128 wait_for_connected_
= false;
129 wait_for_closed_
= false;
133 virtual void HandleWebSocketMessage(const pp::Var
&message
) {
135 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE
, true, 0U, message
));
137 if (wait_for_received_
) {
138 GetTestingInterface()->QuitMessageLoop(instance_
);
139 wait_for_received_
= false;
144 virtual void HandleWebSocketError() {
146 WebSocketEvent(WebSocketEvent::EVENT_ERROR
, true, 0U, pp::Var()));
149 void WaitForConnected() {
151 wait_for_connected_
= true;
152 GetTestingInterface()->RunMessageLoop(instance_
);
156 void WaitForReceived() {
158 wait_for_received_
= true;
159 GetTestingInterface()->RunMessageLoop(instance_
);
163 void WaitForClosed() {
165 wait_for_closed_
= true;
166 GetTestingInterface()->RunMessageLoop(instance_
);
170 const std::vector
<WebSocketEvent
>& GetSeenEvents() const {
175 std::vector
<WebSocketEvent
> events_
;
179 bool wait_for_connected_
;
180 bool wait_for_received_
;
181 bool wait_for_closed_
;
182 PP_Instance instance_
;
187 REGISTER_TEST_CASE(WebSocket
);
189 bool TestWebSocket::Init() {
190 websocket_interface_
= static_cast<const PPB_WebSocket
*>(
191 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE
));
192 var_interface_
= static_cast<const PPB_Var
*>(
193 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE
));
194 arraybuffer_interface_
= static_cast<const PPB_VarArrayBuffer
*>(
195 pp::Module::Get()->GetBrowserInterface(
196 PPB_VAR_ARRAY_BUFFER_INTERFACE
));
197 core_interface_
= static_cast<const PPB_Core
*>(
198 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
199 if (!websocket_interface_
|| !var_interface_
|| !arraybuffer_interface_
||
203 return CheckTestingInterface();
206 void TestWebSocket::RunTests(const std::string
& filter
) {
207 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket
, filter
);
208 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess
, filter
);
209 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect
, filter
);
210 RUN_TEST_WITH_REFERENCE_CHECK(Protocols
, filter
);
211 RUN_TEST_WITH_REFERENCE_CHECK(GetURL
, filter
);
212 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect
, filter
);
213 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose
, filter
);
214 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose
, filter
);
215 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol
, filter
);
216 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive
, filter
);
217 RUN_TEST_BACKGROUND(TestWebSocket
, TextSendReceiveTwice
, filter
);
218 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive
, filter
);
219 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive
, filter
);
220 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount
, filter
);
221 // PP_Resource for WebSocket may be released later because of an internal
222 // reference for asynchronous IPC handling. So, suppress reference check on
223 // the following AbortCallsWithCallback test.
224 RUN_TEST(AbortCallsWithCallback
, filter
);
225 RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall
, filter
);
226 RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall
, filter
);
227 RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall
, 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 std::string
TestWebSocket::TestValidClose() {
571 PP_Var reason
= CreateVarString("close for test");
572 PP_Var url
= CreateVarString(GetFullURL(kEchoServerURL
).c_str());
573 PP_Var protocols
[] = { PP_MakeUndefined() };
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 ASSERT_EQ(PP_OK
, callback
.result());
598 core_interface_
->ReleaseResource(ws
);
600 // Close with PP_VARTYPE_UNDEFINED.
601 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
603 ASSERT_EQ(PP_OK
, result
);
604 callback
.WaitForResult(websocket_interface_
->Close(
605 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
606 callback
.GetCallback().pp_completion_callback()));
607 CHECK_CALLBACK_BEHAVIOR(callback
);
608 ASSERT_EQ(PP_OK
, callback
.result());
609 core_interface_
->ReleaseResource(ws
);
611 // Close in connecting.
612 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
614 ws
= websocket_interface_
->Create(instance_
->pp_instance());
615 result
= websocket_interface_
->Connect(
616 ws
, url
, protocols
, 0U, callback
.GetCallback().pp_completion_callback());
617 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
618 result
= websocket_interface_
->Close(
619 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
620 another_callback
.GetCallback().pp_completion_callback());
621 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
622 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
623 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
624 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
625 ASSERT_EQ(PP_OK
, another_callback
.result());
626 core_interface_
->ReleaseResource(ws
);
629 // The first close will be done successfully, then the second one failed with
630 // with PP_ERROR_INPROGRESS immediately.
631 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
633 ASSERT_EQ(PP_OK
, result
);
634 result
= websocket_interface_
->Close(
635 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
636 callback
.GetCallback().pp_completion_callback());
637 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
638 result
= websocket_interface_
->Close(
639 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
640 another_callback
.GetCallback().pp_completion_callback());
641 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
642 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
643 ASSERT_EQ(PP_OK
, callback
.result());
644 core_interface_
->ReleaseResource(ws
);
646 // Close with ongoing receive message.
647 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
649 ASSERT_EQ(PP_OK
, result
);
650 PP_Var receive_message_var
;
651 result
= websocket_interface_
->ReceiveMessage(
652 ws
, &receive_message_var
,
653 callback
.GetCallback().pp_completion_callback());
654 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
655 result
= websocket_interface_
->Close(
656 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
657 another_callback
.GetCallback().pp_completion_callback());
658 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
659 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
660 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
661 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
662 ASSERT_EQ(PP_OK
, another_callback
.result());
663 core_interface_
->ReleaseResource(ws
);
665 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
666 ws
= Connect(GetFullURL(kEchoServerURL
), &result
, std::string());
668 ASSERT_EQ(PP_OK
, result
);
669 result
= websocket_interface_
->ReceiveMessage(
670 ws
, &receive_message_var
,
671 callback
.GetCallback().pp_completion_callback());
672 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
673 result
= websocket_interface_
->Close(
674 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
675 another_callback
.GetCallback().pp_completion_callback());
676 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
677 callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
678 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
679 another_callback
.WaitForResult(PP_OK_COMPLETIONPENDING
);
680 ASSERT_EQ(PP_OK
, another_callback
.result());
681 core_interface_
->ReleaseResource(ws
);
683 // Server initiated closing handshake.
685 GetFullURL(kCloseWithCodeAndReasonServerURL
), &result
, std::string());
687 ASSERT_EQ(PP_OK
, result
);
688 // Text messsage "1000 bye" requests the server to initiate closing handshake
689 // with code being 1000 and reason being "bye".
690 PP_Var close_request_var
= CreateVarString("1000 bye");
691 result
= websocket_interface_
->SendMessage(ws
, close_request_var
);
692 ReleaseVar(close_request_var
);
693 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
694 ws
, &receive_message_var
,
695 callback
.GetCallback().pp_completion_callback()));
696 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
697 core_interface_
->ReleaseResource(ws
);
705 std::string
TestWebSocket::TestGetProtocol() {
706 const char* expected_protocols
[] = {
711 for (int i
= 0; expected_protocols
[i
]; ++i
) {
712 std::string
url(GetFullURL(kProtocolTestServerURL
));
713 url
+= expected_protocols
[i
];
715 PP_Resource ws
= Connect(url
.c_str(), &result
, expected_protocols
[i
]);
717 ASSERT_EQ(PP_OK
, result
);
719 PP_Var protocol
= websocket_interface_
->GetProtocol(ws
);
720 ASSERT_TRUE(AreEqualWithString(protocol
, expected_protocols
[i
]));
722 ReleaseVar(protocol
);
723 core_interface_
->ReleaseResource(ws
);
729 std::string
TestWebSocket::TestTextSendReceive() {
730 // Connect to test echo server.
731 int32_t connect_result
;
733 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
735 ASSERT_EQ(PP_OK
, connect_result
);
737 // Send 'hello pepper' text message.
738 const char* message
= "hello pepper";
739 PP_Var message_var
= CreateVarString(message
);
740 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
741 ReleaseVar(message_var
);
742 ASSERT_EQ(PP_OK
, result
);
744 // Receive echoed 'hello pepper'.
745 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
746 PP_Var received_message
;
747 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
748 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
749 ASSERT_EQ(PP_OK
, callback
.result());
750 ASSERT_TRUE(AreEqualWithString(received_message
, message
));
751 ReleaseVar(received_message
);
752 core_interface_
->ReleaseResource(ws
);
757 // Run as a BACKGROUND test.
758 std::string
TestWebSocket::TestTextSendReceiveTwice() {
759 // Connect to test echo server.
760 int32_t connect_result
;
762 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
764 ASSERT_EQ(PP_OK
, connect_result
);
765 pp::MessageLoop message_loop
= pp::MessageLoop::GetCurrent();
766 pp::CompletionCallbackFactory
<TestWebSocket
> factory(this);
768 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
769 ws
, std::string("hello")));
770 // When the server receives 'Goodbye', it closes the session.
771 message_loop
.PostWork(factory
.NewCallback(&TestWebSocket::Send
,
772 ws
, std::string("Goodbye")));
773 message_loop
.PostQuit(false);
776 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
777 PP_Var received_message
;
778 int32_t result
= websocket_interface_
->ReceiveMessage(
779 ws
, &received_message
, callback
.GetCallback().pp_completion_callback());
780 ASSERT_EQ(PP_OK
, result
);
781 // Since we don't run the message loop, the callback will stay
782 // "pending and scheduled to run" state.
784 // Waiting for the connection close which will be done by the server.
786 PP_WebSocketReadyState ready_state
=
787 websocket_interface_
->GetReadyState(ws
);
788 if (ready_state
!= PP_WEBSOCKETREADYSTATE_CONNECTING
&&
789 ready_state
!= PP_WEBSOCKETREADYSTATE_OPEN
) {
792 PlatformSleep(100); // 100ms
795 // Cleanup the message loop
796 message_loop
.PostQuit(false);
799 ASSERT_EQ(PP_OK
, callback
.result());
800 ASSERT_TRUE(AreEqualWithString(received_message
, "hello"));
801 ReleaseVar(received_message
);
802 core_interface_
->ReleaseResource(ws
);
806 std::string
TestWebSocket::TestBinarySendReceive() {
807 // Connect to test echo server.
808 int32_t connect_result
;
810 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
812 ASSERT_EQ(PP_OK
, connect_result
);
814 // Send binary message.
815 std::vector
<uint8_t> binary(256);
816 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
818 PP_Var message_var
= CreateVarBinary(binary
);
819 int32_t result
= websocket_interface_
->SendMessage(ws
, message_var
);
820 ReleaseVar(message_var
);
821 ASSERT_EQ(PP_OK
, result
);
823 // Receive echoed binary.
824 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
825 PP_Var received_message
;
826 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
827 ws
, &received_message
, callback
.GetCallback().pp_completion_callback()));
828 ASSERT_EQ(PP_OK
, callback
.result());
829 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
830 ReleaseVar(received_message
);
831 core_interface_
->ReleaseResource(ws
);
836 std::string
TestWebSocket::TestStressedSendReceive() {
837 // Connect to test echo server.
838 int32_t connect_result
;
840 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
842 ASSERT_EQ(PP_OK
, connect_result
);
844 // Prepare PP_Var objects to send.
845 const char* text
= "hello pepper";
846 PP_Var text_var
= CreateVarString(text
);
847 std::vector
<uint8_t> binary(256);
848 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
850 PP_Var binary_var
= CreateVarBinary(binary
);
851 // Prepare very large binary data over 64KiB. Object serializer in
852 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
853 // to SRPC. In case received data over 64KiB exists, a specific code handles
854 // this large data via asynchronous callback from main thread. This data
855 // intends to test the code.
856 std::vector
<uint8_t> large_binary(65 * 1024);
857 for (uint32_t i
= 0; i
< large_binary
.size(); ++i
)
858 large_binary
[i
] = i
& 0xff;
859 PP_Var large_binary_var
= CreateVarBinary(large_binary
);
861 // Send many messages.
863 for (int i
= 0; i
< 256; ++i
) {
864 result
= websocket_interface_
->SendMessage(ws
, text_var
);
865 ASSERT_EQ(PP_OK
, result
);
866 result
= websocket_interface_
->SendMessage(ws
, binary_var
);
867 ASSERT_EQ(PP_OK
, result
);
869 result
= websocket_interface_
->SendMessage(ws
, large_binary_var
);
870 ASSERT_EQ(PP_OK
, result
);
871 ReleaseVar(text_var
);
872 ReleaseVar(binary_var
);
873 ReleaseVar(large_binary_var
);
875 // Receive echoed data.
876 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
877 for (int i
= 0; i
<= 512; ++i
) {
878 PP_Var received_message
;
879 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
880 ws
, &received_message
,
881 callback
.GetCallback().pp_completion_callback()));
882 ASSERT_EQ(PP_OK
, callback
.result());
884 ASSERT_TRUE(AreEqualWithBinary(received_message
, large_binary
));
886 ASSERT_TRUE(AreEqualWithBinary(received_message
, binary
));
888 ASSERT_TRUE(AreEqualWithString(received_message
, text
));
890 ReleaseVar(received_message
);
892 core_interface_
->ReleaseResource(ws
);
897 std::string
TestWebSocket::TestBufferedAmount() {
898 // Connect to test echo server.
899 int32_t connect_result
;
901 Connect(GetFullURL(kEchoServerURL
), &connect_result
, std::string());
903 ASSERT_EQ(PP_OK
, connect_result
);
905 // Prepare a large message that is not aligned with the internal buffer
907 std::string
message(8193, 'x');
908 PP_Var message_var
= CreateVarString(message
);
910 uint64_t buffered_amount
= 0;
912 for (int i
= 0; i
< 100; i
++) {
913 result
= websocket_interface_
->SendMessage(ws
, message_var
);
914 ASSERT_EQ(PP_OK
, result
);
915 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
916 // Buffered amount size 262144 is too big for the internal buffer size.
917 if (buffered_amount
> 262144)
922 std::string reason_str
= "close while busy";
923 PP_Var reason
= CreateVarString(reason_str
.c_str());
924 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
925 result
= websocket_interface_
->Close(
926 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
,
927 callback
.GetCallback().pp_completion_callback());
928 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
929 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
,
930 websocket_interface_
->GetReadyState(ws
));
932 callback
.WaitForResult(result
);
933 ASSERT_EQ(PP_OK
, callback
.result());
934 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
,
935 websocket_interface_
->GetReadyState(ws
));
937 uint64_t base_buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
939 // After connection closure, all sending requests fail and just increase
940 // the bufferedAmount property.
941 PP_Var empty_string
= CreateVarString(std::string());
942 result
= websocket_interface_
->SendMessage(ws
, empty_string
);
943 ASSERT_EQ(PP_ERROR_FAILED
, result
);
944 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
945 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
946 base_buffered_amount
= buffered_amount
;
948 result
= websocket_interface_
->SendMessage(ws
, reason
);
949 ASSERT_EQ(PP_ERROR_FAILED
, result
);
950 buffered_amount
= websocket_interface_
->GetBufferedAmount(ws
);
951 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason_str
.length();
952 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
954 ReleaseVar(message_var
);
956 ReleaseVar(empty_string
);
957 core_interface_
->ReleaseResource(ws
);
962 // Test abort behaviors where a WebSocket PP_Resource is released while each
963 // function is in-flight on the WebSocket PP_Resource.
964 std::string
TestWebSocket::TestAbortCallsWithCallback() {
965 // Following tests make sure the behavior for functions which require a
966 // callback. The callback must get a PP_ERROR_ABORTED.
968 // Test the behavior for Connect().
969 PP_Resource ws
= websocket_interface_
->Create(instance_
->pp_instance());
971 std::string url
= GetFullURL(kEchoServerURL
);
972 PP_Var url_var
= CreateVarString(url
);
973 TestCompletionCallback
connect_callback(
974 instance_
->pp_instance(), callback_type());
975 int32_t result
= websocket_interface_
->Connect(
976 ws
, url_var
, NULL
, 0,
977 connect_callback
.GetCallback().pp_completion_callback());
978 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
979 core_interface_
->ReleaseResource(ws
);
980 connect_callback
.WaitForResult(result
);
981 ASSERT_EQ(PP_ERROR_ABORTED
, connect_callback
.result());
983 // Test the behavior for Close().
984 ws
= Connect(url
, &result
, std::string());
986 ASSERT_EQ(PP_OK
, result
);
987 PP_Var reason_var
= CreateVarString("abort");
988 TestCompletionCallback
close_callback(
989 instance_
->pp_instance(), callback_type());
990 result
= websocket_interface_
->Close(
991 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason_var
,
992 close_callback
.GetCallback().pp_completion_callback());
993 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
994 core_interface_
->ReleaseResource(ws
);
995 close_callback
.WaitForResult(result
);
996 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
997 ReleaseVar(reason_var
);
999 // Test the behavior for ReceiveMessage().
1000 // Make sure the simplest case to wait for data which never arrives, here.
1001 ws
= Connect(url
, &result
, std::string());
1003 ASSERT_EQ(PP_OK
, result
);
1005 TestCompletionCallback
receive_callback(
1006 instance_
->pp_instance(), callback_type());
1007 result
= websocket_interface_
->ReceiveMessage(
1009 receive_callback
.GetCallback().pp_completion_callback());
1010 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1011 core_interface_
->ReleaseResource(ws
);
1012 receive_callback
.WaitForResult(result
);
1013 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1015 // Release the resource in the aborting receive completion callback which is
1016 // introduced by calling Close().
1017 ws
= Connect(url
, &result
, std::string());
1019 ASSERT_EQ(PP_OK
, result
);
1020 result
= websocket_interface_
->ReceiveMessage(
1022 receive_callback
.GetCallback().pp_completion_callback());
1023 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1024 ReleaseResourceDelegate
receive_delegate(core_interface_
, ws
);
1025 receive_callback
.SetDelegate(&receive_delegate
);
1026 result
= websocket_interface_
->Close(
1027 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1028 close_callback
.GetCallback().pp_completion_callback());
1029 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1030 receive_callback
.WaitForResult(result
);
1031 CHECK_CALLBACK_BEHAVIOR(receive_callback
);
1032 ASSERT_EQ(PP_ERROR_ABORTED
, receive_callback
.result());
1033 close_callback
.WaitForResult(result
);
1034 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1035 ASSERT_EQ(PP_ERROR_ABORTED
, close_callback
.result());
1037 ReleaseVar(url_var
);
1042 std::string
TestWebSocket::TestAbortSendMessageCall() {
1043 // Test the behavior for SendMessage().
1044 // This function doesn't require a callback, but operation will be done
1045 // asynchronously in WebKit and browser process.
1046 std::vector
<uint8_t> large_binary(65 * 1024);
1047 PP_Var large_var
= CreateVarBinary(large_binary
);
1050 std::string url
= GetFullURL(kEchoServerURL
);
1051 PP_Resource ws
= Connect(url
, &result
, std::string());
1053 ASSERT_EQ(PP_OK
, result
);
1054 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1055 ASSERT_EQ(PP_OK
, result
);
1056 core_interface_
->ReleaseResource(ws
);
1057 ReleaseVar(large_var
);
1062 std::string
TestWebSocket::TestAbortCloseCall() {
1063 // Release the resource in the close completion callback.
1065 std::string url
= GetFullURL(kEchoServerURL
);
1066 PP_Resource ws
= Connect(url
, &result
, std::string());
1068 ASSERT_EQ(PP_OK
, result
);
1069 TestCompletionCallback
close_callback(
1070 instance_
->pp_instance(), callback_type());
1071 result
= websocket_interface_
->Close(
1072 ws
, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, PP_MakeUndefined(),
1073 close_callback
.GetCallback().pp_completion_callback());
1074 ReleaseResourceDelegate
close_delegate(core_interface_
, ws
);
1075 close_callback
.SetDelegate(&close_delegate
);
1076 close_callback
.WaitForResult(result
);
1077 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1078 ASSERT_EQ(PP_OK
, close_callback
.result());
1083 std::string
TestWebSocket::TestAbortReceiveMessageCall() {
1084 // Test the behavior where receive process might be in-flight.
1085 std::vector
<uint8_t> large_binary(65 * 1024);
1086 PP_Var large_var
= CreateVarBinary(large_binary
);
1087 const char* text
= "yukarin";
1088 PP_Var text_var
= CreateVarString(text
);
1090 std::string url
= GetFullURL(kEchoServerURL
);
1094 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1095 // number of message(s) before releasing the WebSocket. The WebSocket is
1096 // released while the next message is going to be received.
1097 const int trial_count
= 8;
1098 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1099 ws
= Connect(url
, &result
, std::string());
1101 ASSERT_EQ(PP_OK
, result
);
1102 for (int i
= 0; i
<= trial_count
; ++i
) {
1103 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1104 ASSERT_EQ(PP_OK
, result
);
1106 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1108 for (int i
= 0; i
< trial
; ++i
) {
1109 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1110 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1111 ASSERT_EQ(PP_OK
, callback
.result());
1112 ASSERT_TRUE(AreEqualWithString(var
, text
));
1115 result
= websocket_interface_
->ReceiveMessage(
1116 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1117 core_interface_
->ReleaseResource(ws
);
1118 if (result
!= PP_OK
) {
1119 callback
.WaitForResult(result
);
1120 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1123 // Same test, but the last receiving message is large message over 64KiB.
1124 for (int trial
= 1; trial
<= trial_count
; trial
++) {
1125 ws
= Connect(url
, &result
, std::string());
1127 ASSERT_EQ(PP_OK
, result
);
1128 for (int i
= 0; i
<= trial_count
; ++i
) {
1130 result
= websocket_interface_
->SendMessage(ws
, large_var
);
1132 result
= websocket_interface_
->SendMessage(ws
, text_var
);
1133 ASSERT_EQ(PP_OK
, result
);
1135 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1137 for (int i
= 0; i
< trial
; ++i
) {
1138 callback
.WaitForResult(websocket_interface_
->ReceiveMessage(
1139 ws
, &var
, callback
.GetCallback().pp_completion_callback()));
1140 ASSERT_EQ(PP_OK
, callback
.result());
1141 ASSERT_TRUE(AreEqualWithString(var
, text
));
1144 result
= websocket_interface_
->ReceiveMessage(
1145 ws
, &var
, callback
.GetCallback().pp_completion_callback());
1146 core_interface_
->ReleaseResource(ws
);
1147 if (result
!= PP_OK
) {
1148 callback
.WaitForResult(result
);
1149 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
1153 ReleaseVar(large_var
);
1154 ReleaseVar(text_var
);
1159 std::string
TestWebSocket::TestCcInterfaces() {
1160 // C++ bindings is simple straightforward, then just verifies interfaces work
1161 // as a interface bridge fine.
1162 pp::WebSocket
ws(instance_
);
1164 // Check uninitialized properties access.
1165 ASSERT_EQ(0, ws
.GetBufferedAmount());
1166 ASSERT_EQ(0, ws
.GetCloseCode());
1167 ASSERT_TRUE(AreEqualWithString(ws
.GetCloseReason().pp_var(), std::string()));
1168 ASSERT_EQ(false, ws
.GetCloseWasClean());
1169 ASSERT_TRUE(AreEqualWithString(ws
.GetExtensions().pp_var(), std::string()));
1170 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1171 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID
, ws
.GetReadyState());
1172 ASSERT_TRUE(AreEqualWithString(ws
.GetURL().pp_var(), std::string()));
1174 // Check communication interfaces (connect, send, receive, and close).
1175 TestCompletionCallback
connect_callback(
1176 instance_
->pp_instance(), callback_type());
1177 connect_callback
.WaitForResult(ws
.Connect(
1178 pp::Var(GetFullURL(kCloseServerURL
)), NULL
, 0U,
1179 connect_callback
.GetCallback()));
1180 CHECK_CALLBACK_BEHAVIOR(connect_callback
);
1181 ASSERT_EQ(PP_OK
, connect_callback
.result());
1183 std::string
text_message("hello C++");
1184 int32_t result
= ws
.SendMessage(pp::Var(text_message
));
1185 ASSERT_EQ(PP_OK
, result
);
1187 std::vector
<uint8_t> binary(256);
1188 for (uint32_t i
= 0; i
< binary
.size(); ++i
)
1190 result
= ws
.SendMessage(
1191 pp::Var(pp::PASS_REF
, CreateVarBinary(binary
)));
1192 ASSERT_EQ(PP_OK
, result
);
1194 pp::Var text_receive_var
;
1195 TestCompletionCallback
text_receive_callback(
1196 instance_
->pp_instance(), callback_type());
1197 text_receive_callback
.WaitForResult(
1198 ws
.ReceiveMessage(&text_receive_var
,
1199 text_receive_callback
.GetCallback()));
1200 ASSERT_EQ(PP_OK
, text_receive_callback
.result());
1202 AreEqualWithString(text_receive_var
.pp_var(), text_message
.c_str()));
1204 pp::Var binary_receive_var
;
1205 TestCompletionCallback
binary_receive_callback(
1206 instance_
->pp_instance(), callback_type());
1207 binary_receive_callback
.WaitForResult(
1208 ws
.ReceiveMessage(&binary_receive_var
,
1209 binary_receive_callback
.GetCallback()));
1210 ASSERT_EQ(PP_OK
, binary_receive_callback
.result());
1211 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var
.pp_var(), binary
));
1213 TestCompletionCallback
close_callback(
1214 instance_
->pp_instance(), callback_type());
1215 std::string
reason("bye");
1216 close_callback
.WaitForResult(ws
.Close(
1217 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
),
1218 close_callback
.GetCallback()));
1219 CHECK_CALLBACK_BEHAVIOR(close_callback
);
1220 ASSERT_EQ(PP_OK
, close_callback
.result());
1222 // Check initialized properties access.
1223 ASSERT_EQ(0, ws
.GetBufferedAmount());
1224 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, ws
.GetCloseCode());
1226 AreEqualWithString(ws
.GetCloseReason().pp_var(), reason
.c_str()));
1227 ASSERT_EQ(true, ws
.GetCloseWasClean());
1228 ASSERT_TRUE(AreEqualWithString(ws
.GetProtocol().pp_var(), std::string()));
1229 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, ws
.GetReadyState());
1230 ASSERT_TRUE(AreEqualWithString(
1231 ws
.GetURL().pp_var(), GetFullURL(kCloseServerURL
).c_str()));
1236 std::string
TestWebSocket::TestUtilityInvalidConnect() {
1237 const pp::Var protocols
[] = { pp::Var() };
1239 TestWebSocketAPI
websocket(instance_
);
1240 int32_t result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1241 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1242 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1244 result
= websocket
.Connect(pp::Var(), protocols
, 1U);
1245 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1246 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1248 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1249 TestWebSocketAPI
ws(instance_
);
1250 result
= ws
.Connect(pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1251 if (result
== PP_OK_COMPLETIONPENDING
) {
1253 const std::vector
<WebSocketEvent
>& events
= ws
.GetSeenEvents();
1254 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1255 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1256 ASSERT_EQ(2U, ws
.GetSeenEvents().size());
1258 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1259 ASSERT_EQ(0U, ws
.GetSeenEvents().size());
1266 std::string
TestWebSocket::TestUtilityProtocols() {
1267 const pp::Var bad_protocols
[] = {
1268 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1269 const pp::Var good_protocols
[] = {
1270 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1273 TestWebSocketAPI
websocket(instance_
);
1274 int32_t result
= websocket
.Connect(
1275 pp::Var(GetFullURL(kEchoServerURL
)), bad_protocols
, 2U);
1276 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1277 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1281 TestWebSocketAPI
websocket(instance_
);
1282 int32_t result
= websocket
.Connect(
1283 pp::Var(GetFullURL(kEchoServerURL
)), good_protocols
, 2U);
1284 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1285 websocket
.WaitForConnected();
1286 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1287 // Protocol arguments are valid, but this test run without a WebSocket
1288 // server. As a result, OnError() and OnClose() are invoked because of
1289 // a connection establishment failure.
1290 ASSERT_EQ(2U, events
.size());
1291 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1292 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1293 ASSERT_FALSE(events
[1].was_clean
);
1299 std::string
TestWebSocket::TestUtilityGetURL() {
1300 const pp::Var protocols
[] = { pp::Var() };
1302 for (int i
= 0; kInvalidURLs
[i
]; ++i
) {
1303 TestWebSocketAPI
websocket(instance_
);
1304 int32_t result
= websocket
.Connect(
1305 pp::Var(std::string(kInvalidURLs
[i
])), protocols
, 0U);
1306 if (result
== PP_OK_COMPLETIONPENDING
) {
1307 websocket
.WaitForClosed();
1308 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1309 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[0].event_type
);
1310 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1311 ASSERT_EQ(2U, events
.size());
1313 ASSERT_EQ(PP_ERROR_BADARGUMENT
, result
);
1314 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1316 pp::Var url
= websocket
.GetURL();
1317 ASSERT_TRUE(AreEqualWithString(url
.pp_var(), kInvalidURLs
[i
]));
1323 std::string
TestWebSocket::TestUtilityValidConnect() {
1324 const pp::Var protocols
[] = { pp::Var() };
1325 TestWebSocketAPI
websocket(instance_
);
1326 int32_t result
= websocket
.Connect(
1327 pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1328 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1329 websocket
.WaitForConnected();
1330 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1331 ASSERT_EQ(1U, events
.size());
1332 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1334 AreEqualWithString(websocket
.GetExtensions().pp_var(), std::string()));
1339 std::string
TestWebSocket::TestUtilityInvalidClose() {
1340 const pp::Var reason
= pp::Var(std::string("close for test"));
1342 // Close before connect.
1344 TestWebSocketAPI
websocket(instance_
);
1345 int32_t result
= websocket
.Close(
1346 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, reason
);
1347 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1348 ASSERT_EQ(0U, websocket
.GetSeenEvents().size());
1351 // Close with bad arguments.
1353 TestWebSocketAPI
websocket(instance_
);
1354 int32_t result
= websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)),
1356 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1357 websocket
.WaitForConnected();
1358 result
= websocket
.Close(1U, reason
);
1359 ASSERT_EQ(PP_ERROR_NOACCESS
, result
);
1360 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1361 ASSERT_EQ(1U, events
.size());
1362 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1368 std::string
TestWebSocket::TestUtilityValidClose() {
1369 std::string
reason("close for test");
1370 pp::Var url
= pp::Var(GetFullURL(kCloseServerURL
));
1374 TestWebSocketAPI
websocket(instance_
);
1375 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1376 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1377 websocket
.WaitForConnected();
1378 result
= websocket
.Close(
1379 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1380 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1381 websocket
.WaitForClosed();
1382 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1383 ASSERT_EQ(2U, events
.size());
1384 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1385 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[1].event_type
);
1386 ASSERT_TRUE(events
[1].was_clean
);
1387 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, events
[1].close_code
);
1388 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), reason
.c_str()));
1391 // Close in connecting.
1392 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1395 TestWebSocketAPI
websocket(instance_
);
1396 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1397 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1398 result
= websocket
.Close(
1399 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1400 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1401 websocket
.WaitForClosed();
1402 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1403 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1405 if (events
.size() == 3)
1406 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1407 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1408 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1409 ASSERT_FALSE(events
[index
].was_clean
);
1412 // Close in closing.
1413 // The first close will be done successfully, then the second one failed with
1414 // with PP_ERROR_INPROGRESS immediately.
1416 TestWebSocketAPI
websocket(instance_
);
1417 int32_t result
= websocket
.Connect(url
, NULL
, 0U);
1418 result
= websocket
.Close(
1419 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1420 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1421 result
= websocket
.Close(
1422 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1423 ASSERT_EQ(PP_ERROR_INPROGRESS
, result
);
1424 websocket
.WaitForClosed();
1425 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1426 ASSERT_TRUE(events
.size() == 2 || events
.size() == 3);
1428 if (events
.size() == 3)
1429 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[index
++].event_type
);
1430 ASSERT_EQ(WebSocketEvent::EVENT_ERROR
, events
[index
++].event_type
);
1431 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[index
].event_type
);
1432 ASSERT_FALSE(events
[index
].was_clean
);
1438 std::string
TestWebSocket::TestUtilityGetProtocol() {
1439 const std::string
protocol("x-chat");
1440 const pp::Var protocols
[] = { pp::Var(protocol
) };
1441 std::string
url(GetFullURL(kProtocolTestServerURL
));
1443 TestWebSocketAPI
websocket(instance_
);
1444 int32_t result
= websocket
.Connect(pp::Var(url
), protocols
, 1U);
1445 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1446 websocket
.WaitForReceived();
1447 ASSERT_TRUE(AreEqualWithString(
1448 websocket
.GetProtocol().pp_var(), protocol
.c_str()));
1449 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1450 // The server to which this test connect returns the decided protocol as a
1451 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1452 // after EVENT_OPEN event.
1453 ASSERT_EQ(2U, events
.size());
1454 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1455 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1456 ASSERT_TRUE(AreEqualWithString(events
[1].var
.pp_var(), protocol
.c_str()));
1461 std::string
TestWebSocket::TestUtilityTextSendReceive() {
1462 const pp::Var protocols
[] = { pp::Var() };
1463 TestWebSocketAPI
websocket(instance_
);
1465 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1466 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1467 websocket
.WaitForConnected();
1469 // Send 'hello pepper'.
1470 std::string
message1("hello pepper");
1471 result
= websocket
.Send(pp::Var(std::string(message1
)));
1472 ASSERT_EQ(PP_OK
, result
);
1474 // Receive echoed 'hello pepper'.
1475 websocket
.WaitForReceived();
1477 // Send 'goodbye pepper'.
1478 std::string
message2("goodbye pepper");
1479 result
= websocket
.Send(pp::Var(std::string(message2
)));
1481 // Receive echoed 'goodbye pepper'.
1482 websocket
.WaitForReceived();
1484 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1485 ASSERT_EQ(3U, 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(), message1
.c_str()));
1489 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[2].event_type
);
1490 ASSERT_TRUE(AreEqualWithString(events
[2].var
.pp_var(), message2
.c_str()));
1495 std::string
TestWebSocket::TestUtilityBinarySendReceive() {
1496 const pp::Var protocols
[] = { pp::Var() };
1497 TestWebSocketAPI
websocket(instance_
);
1499 websocket
.Connect(pp::Var(GetFullURL(kEchoServerURL
)), protocols
, 0U);
1500 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, result
);
1501 websocket
.WaitForConnected();
1503 // Send binary message.
1505 std::vector
<uint8_t> binary(len
);
1506 for (uint32_t i
= 0; i
< len
; ++i
)
1508 pp::VarArrayBuffer
message(len
);
1509 uint8_t* var_data
= static_cast<uint8_t*>(message
.Map());
1510 std::copy(binary
.begin(), binary
.end(), var_data
);
1511 result
= websocket
.Send(message
);
1512 ASSERT_EQ(PP_OK
, result
);
1514 // Receive echoed binary message.
1515 websocket
.WaitForReceived();
1517 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1518 ASSERT_EQ(2U, events
.size());
1519 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1520 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[1].event_type
);
1521 ASSERT_TRUE(AreEqualWithBinary(events
[1].var
.pp_var(), binary
));
1526 std::string
TestWebSocket::TestUtilityBufferedAmount() {
1527 // Connect to test echo server.
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 // Prepare a large message that is not aligned with the internal buffer
1537 std::string
message(8193, 'x');
1538 uint64_t buffered_amount
= 0;
1540 for (sent
= 0; sent
< 100; sent
++) {
1541 result
= websocket
.Send(pp::Var(message
));
1542 ASSERT_EQ(PP_OK
, result
);
1543 buffered_amount
= websocket
.GetBufferedAmount();
1544 // Buffered amount size 262144 is too big for the internal buffer size.
1545 if (buffered_amount
> 262144)
1549 // Close connection.
1550 std::string reason
= "close while busy";
1551 result
= websocket
.Close(
1552 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE
, pp::Var(reason
));
1553 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING
, websocket
.GetReadyState());
1554 websocket
.WaitForClosed();
1555 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED
, websocket
.GetReadyState());
1557 uint64_t base_buffered_amount
= websocket
.GetBufferedAmount();
1558 size_t events_on_closed
= websocket
.GetSeenEvents().size();
1560 // After connection closure, all sending requests fail and just increase
1561 // the bufferedAmount property.
1562 result
= websocket
.Send(pp::Var(std::string()));
1563 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1564 buffered_amount
= websocket
.GetBufferedAmount();
1565 ASSERT_EQ(base_buffered_amount
+ kMessageFrameOverhead
, buffered_amount
);
1566 base_buffered_amount
= buffered_amount
;
1568 result
= websocket
.Send(pp::Var(reason
));
1569 ASSERT_EQ(PP_ERROR_FAILED
, result
);
1570 buffered_amount
= websocket
.GetBufferedAmount();
1571 uint64_t reason_frame_size
= kMessageFrameOverhead
+ reason
.length();
1572 ASSERT_EQ(base_buffered_amount
+ reason_frame_size
, buffered_amount
);
1574 const std::vector
<WebSocketEvent
>& events
= websocket
.GetSeenEvents();
1575 ASSERT_EQ(events_on_closed
, events
.size());
1576 ASSERT_EQ(WebSocketEvent::EVENT_OPEN
, events
[0].event_type
);
1577 size_t last_event
= events_on_closed
- 1;
1578 for (uint32_t i
= 1; i
< last_event
; ++i
) {
1579 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE
, events
[i
].event_type
);
1580 ASSERT_TRUE(AreEqualWithString(events
[i
].var
.pp_var(), message
));
1582 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE
, events
[last_event
].event_type
);
1583 ASSERT_TRUE(events
[last_event
].was_clean
);