Remove extra line from unit_tests.isolate
[chromium-blink-merge.git] / ppapi / tests / test_websocket.cc
blob2707b4f2aa889591fc5212ddbe94b1998db88750
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"
7 #include <stdio.h>
8 #include <string.h>
10 #include <algorithm>
11 #include <memory>
12 #include <string>
13 #include <vector>
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 // These servers are provided by pywebsocket server side handlers in
35 // LayoutTests/http/tests/websocket/tests/hybi/*_wsh.
36 // pywebsocket server itself is launched in ppapi_ui_test.cc.
37 const char kEchoServerURL[] = "websocket/tests/hybi/echo-with-no-extension";
39 const char kCloseServerURL[] = "websocket/tests/hybi/close";
41 const char kCloseWithCodeAndReasonServerURL[] =
42 "websocket/tests/hybi/close-code-and-reason";
44 const char kProtocolTestServerURL[] =
45 "websocket/tests/hybi/protocol-test?protocol=";
47 const char* const kInvalidURLs[] = {
48 "http://www.google.com/invalid_scheme",
49 "ws://www.google.com/invalid#fragment",
50 "ws://www.google.com:65535/invalid_port",
51 NULL
54 // Internal packet sizes.
55 const uint64_t kCloseFrameSize = 6;
56 const uint64_t kMessageFrameOverhead = 6;
58 namespace {
60 struct WebSocketEvent {
61 enum EventType {
62 EVENT_OPEN,
63 EVENT_MESSAGE,
64 EVENT_ERROR,
65 EVENT_CLOSE
68 WebSocketEvent(EventType type,
69 bool was_clean,
70 uint16_t close_code,
71 const pp::Var& var)
72 : event_type(type),
73 was_clean(was_clean),
74 close_code(close_code),
75 var(var) {
77 EventType event_type;
78 bool was_clean;
79 uint16_t close_code;
80 pp::Var var;
83 class ReleaseResourceDelegate : public TestCompletionCallback::Delegate {
84 public:
85 explicit ReleaseResourceDelegate(const PPB_Core* core_interface,
86 PP_Resource resource)
87 : core_interface_(core_interface),
88 resource_(resource) {
91 // TestCompletionCallback::Delegate implementation.
92 virtual void OnCallback(void* user_data, int32_t result) {
93 if (resource_)
94 core_interface_->ReleaseResource(resource_);
97 private:
98 const PPB_Core* core_interface_;
99 PP_Resource resource_;
102 class TestWebSocketAPI : public pp::WebSocketAPI {
103 public:
104 explicit TestWebSocketAPI(pp::Instance* instance)
105 : pp::WebSocketAPI(instance),
106 connected_(false),
107 received_(false),
108 closed_(false),
109 wait_for_connected_(false),
110 wait_for_received_(false),
111 wait_for_closed_(false),
112 instance_(instance->pp_instance()) {
115 virtual void WebSocketDidOpen() {
116 events_.push_back(
117 WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var()));
118 connected_ = true;
119 if (wait_for_connected_) {
120 GetTestingInterface()->QuitMessageLoop(instance_);
121 wait_for_connected_ = false;
125 virtual void WebSocketDidClose(
126 bool was_clean, uint16_t code, const pp::Var& reason) {
127 events_.push_back(
128 WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason));
129 connected_ = true;
130 closed_ = true;
131 if (wait_for_connected_ || wait_for_closed_) {
132 GetTestingInterface()->QuitMessageLoop(instance_);
133 wait_for_connected_ = false;
134 wait_for_closed_ = false;
138 virtual void HandleWebSocketMessage(const pp::Var &message) {
139 events_.push_back(
140 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message));
141 received_ = true;
142 if (wait_for_received_) {
143 GetTestingInterface()->QuitMessageLoop(instance_);
144 wait_for_received_ = false;
145 received_ = false;
149 virtual void HandleWebSocketError() {
150 events_.push_back(
151 WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var()));
154 void WaitForConnected() {
155 if (!connected_) {
156 wait_for_connected_ = true;
157 GetTestingInterface()->RunMessageLoop(instance_);
161 void WaitForReceived() {
162 if (!received_) {
163 wait_for_received_ = true;
164 GetTestingInterface()->RunMessageLoop(instance_);
168 void WaitForClosed() {
169 if (!closed_) {
170 wait_for_closed_ = true;
171 GetTestingInterface()->RunMessageLoop(instance_);
175 const std::vector<WebSocketEvent>& GetSeenEvents() const {
176 return events_;
179 private:
180 std::vector<WebSocketEvent> events_;
181 bool connected_;
182 bool received_;
183 bool closed_;
184 bool wait_for_connected_;
185 bool wait_for_received_;
186 bool wait_for_closed_;
187 PP_Instance instance_;
190 } // namespace
192 REGISTER_TEST_CASE(WebSocket);
194 bool TestWebSocket::Init() {
195 websocket_interface_ = static_cast<const PPB_WebSocket*>(
196 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE));
197 var_interface_ = static_cast<const PPB_Var*>(
198 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
199 arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>(
200 pp::Module::Get()->GetBrowserInterface(
201 PPB_VAR_ARRAY_BUFFER_INTERFACE));
202 core_interface_ = static_cast<const PPB_Core*>(
203 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
204 if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ ||
205 !core_interface_)
206 return false;
208 return CheckTestingInterface();
211 void TestWebSocket::RunTests(const std::string& filter) {
212 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter);
213 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter);
214 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter);
215 RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter);
216 RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter);
217 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter);
218 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter);
219 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter);
220 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter);
221 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter);
222 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive, filter);
223 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive, filter);
224 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount, filter);
225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCalls, filter);
227 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter);
229 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect, filter);
230 RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols, filter);
231 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL, filter);
232 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect, filter);
233 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose, filter);
234 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose, filter);
235 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol, filter);
236 RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive, filter);
237 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive, filter);
238 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount, filter);
241 std::string TestWebSocket::GetFullURL(const char* url) {
242 std::string rv = "ws://localhost";
243 // Some WebSocket tests don't start the server so there'll be no port.
244 if (instance_->websocket_port() != -1) {
245 char buffer[10];
246 sprintf(buffer, ":%d", instance_->websocket_port());
247 rv += std::string(buffer);
249 rv += "/";
250 rv += url;
251 return rv;
254 PP_Var TestWebSocket::CreateVarString(const std::string& string) {
255 return var_interface_->VarFromUtf8(string.c_str(), string.size());
258 PP_Var TestWebSocket::CreateVarBinary(const std::vector<uint8_t>& binary) {
259 PP_Var var = arraybuffer_interface_->Create(binary.size());
260 uint8_t* var_data = static_cast<uint8_t*>(arraybuffer_interface_->Map(var));
261 std::copy(binary.begin(), binary.end(), var_data);
262 return var;
265 void TestWebSocket::ReleaseVar(const PP_Var& var) {
266 var_interface_->Release(var);
269 bool TestWebSocket::AreEqualWithString(const PP_Var& var,
270 const std::string& string) {
271 if (var.type != PP_VARTYPE_STRING)
272 return false;
273 uint32_t utf8_length;
274 const char* utf8 = var_interface_->VarToUtf8(var, &utf8_length);
275 if (utf8_length != string.size())
276 return false;
277 if (string.compare(utf8))
278 return false;
279 return true;
282 bool TestWebSocket::AreEqualWithBinary(const PP_Var& var,
283 const std::vector<uint8_t>& binary) {
284 uint32_t buffer_size = 0;
285 PP_Bool success = arraybuffer_interface_->ByteLength(var, &buffer_size);
286 if (!success || buffer_size != binary.size())
287 return false;
288 if (!std::equal(binary.begin(), binary.end(),
289 static_cast<uint8_t*>(arraybuffer_interface_->Map(var))))
290 return false;
291 return true;
294 PP_Resource TestWebSocket::Connect(const std::string& url,
295 int32_t* result,
296 const std::string& protocol) {
297 PP_Var protocols[] = { PP_MakeUndefined() };
298 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
299 if (!ws)
300 return 0;
301 PP_Var url_var = CreateVarString(url);
302 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
303 uint32_t protocol_count = 0U;
304 if (protocol.size()) {
305 protocols[0] = CreateVarString(protocol);
306 protocol_count = 1U;
308 callback.WaitForResult(websocket_interface_->Connect(
309 ws, url_var, protocols, protocol_count,
310 callback.GetCallback().pp_completion_callback()));
311 ReleaseVar(url_var);
312 if (protocol.size())
313 ReleaseVar(protocols[0]);
314 *result = callback.result();
315 return ws;
318 std::string TestWebSocket::TestIsWebSocket() {
319 // Test that a NULL resource isn't a websocket.
320 pp::Resource null_resource;
321 PP_Bool result =
322 websocket_interface_->IsWebSocket(null_resource.pp_resource());
323 ASSERT_FALSE(result);
325 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
326 ASSERT_TRUE(ws);
328 result = websocket_interface_->IsWebSocket(ws);
329 ASSERT_TRUE(result);
331 core_interface_->ReleaseResource(ws);
333 PASS();
336 std::string TestWebSocket::TestUninitializedPropertiesAccess() {
337 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
338 ASSERT_TRUE(ws);
340 uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws);
341 ASSERT_EQ(0U, bufferedAmount);
343 uint16_t close_code = websocket_interface_->GetCloseCode(ws);
344 ASSERT_EQ(0U, close_code);
346 PP_Var close_reason = websocket_interface_->GetCloseReason(ws);
347 ASSERT_TRUE(AreEqualWithString(close_reason, ""));
348 ReleaseVar(close_reason);
350 PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws);
351 ASSERT_EQ(PP_FALSE, close_was_clean);
353 PP_Var extensions = websocket_interface_->GetExtensions(ws);
354 ASSERT_TRUE(AreEqualWithString(extensions, ""));
355 ReleaseVar(extensions);
357 PP_Var protocol = websocket_interface_->GetProtocol(ws);
358 ASSERT_TRUE(AreEqualWithString(protocol, ""));
359 ReleaseVar(protocol);
361 PP_WebSocketReadyState ready_state =
362 websocket_interface_->GetReadyState(ws);
363 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state);
365 PP_Var url = websocket_interface_->GetURL(ws);
366 ASSERT_TRUE(AreEqualWithString(url, ""));
367 ReleaseVar(url);
369 core_interface_->ReleaseResource(ws);
371 PASS();
374 std::string TestWebSocket::TestInvalidConnect() {
375 PP_Var protocols[] = { PP_MakeUndefined() };
377 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
378 ASSERT_TRUE(ws);
380 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
381 callback.WaitForResult(websocket_interface_->Connect(
382 ws, PP_MakeUndefined(), protocols, 1U,
383 callback.GetCallback().pp_completion_callback()));
384 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
386 callback.WaitForResult(websocket_interface_->Connect(
387 ws, PP_MakeUndefined(), protocols, 1U,
388 callback.GetCallback().pp_completion_callback()));
389 ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result());
391 core_interface_->ReleaseResource(ws);
393 for (int i = 0; kInvalidURLs[i]; ++i) {
394 int32_t result;
395 ws = Connect(kInvalidURLs[i], &result, "");
396 ASSERT_TRUE(ws);
397 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
399 core_interface_->ReleaseResource(ws);
402 PASS();
405 std::string TestWebSocket::TestProtocols() {
406 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
407 PP_Var bad_protocols[] = {
408 CreateVarString("x-test"),
409 CreateVarString("x-test")
411 PP_Var good_protocols[] = {
412 CreateVarString("x-test"),
413 CreateVarString("x-yatest")
416 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
417 ASSERT_TRUE(ws);
418 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
419 callback.WaitForResult(websocket_interface_->Connect(
420 ws, url, bad_protocols, 2U,
421 callback.GetCallback().pp_completion_callback()));
422 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
423 core_interface_->ReleaseResource(ws);
425 ws = websocket_interface_->Create(instance_->pp_instance());
426 ASSERT_TRUE(ws);
427 int32_t result = websocket_interface_->Connect(
428 ws, url, good_protocols, 2U, PP_BlockUntilComplete());
429 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result);
430 core_interface_->ReleaseResource(ws);
432 ReleaseVar(url);
433 for (int i = 0; i < 2; ++i) {
434 ReleaseVar(bad_protocols[i]);
435 ReleaseVar(good_protocols[i]);
437 core_interface_->ReleaseResource(ws);
439 PASS();
442 std::string TestWebSocket::TestGetURL() {
443 for (int i = 0; kInvalidURLs[i]; ++i) {
444 int32_t result;
445 PP_Resource ws = Connect(kInvalidURLs[i], &result, "");
446 ASSERT_TRUE(ws);
447 PP_Var url = websocket_interface_->GetURL(ws);
448 ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i]));
449 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
451 ReleaseVar(url);
452 core_interface_->ReleaseResource(ws);
455 PASS();
458 std::string TestWebSocket::TestValidConnect() {
459 int32_t result;
460 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, "");
461 ASSERT_TRUE(ws);
462 ASSERT_EQ(PP_OK, result);
463 PP_Var extensions = websocket_interface_->GetExtensions(ws);
464 ASSERT_TRUE(AreEqualWithString(extensions, ""));
465 core_interface_->ReleaseResource(ws);
467 PASS();
470 std::string TestWebSocket::TestInvalidClose() {
471 PP_Var reason = CreateVarString("close for test");
472 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
473 TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED);
475 // Close before connect.
476 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
477 callback.WaitForResult(websocket_interface_->Close(
478 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
479 callback.GetCallback().pp_completion_callback()));
480 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
481 core_interface_->ReleaseResource(ws);
483 // Close with bad arguments.
484 int32_t result;
485 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
486 ASSERT_TRUE(ws);
487 ASSERT_EQ(PP_OK, result);
488 callback.WaitForResult(websocket_interface_->Close(
489 ws, 1U, reason, callback.GetCallback().pp_completion_callback()));
490 ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
491 core_interface_->ReleaseResource(ws);
493 // Close with PP_VARTYPE_NULL.
494 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
495 ASSERT_TRUE(ws);
496 ASSERT_EQ(PP_OK, result);
497 callback.WaitForResult(websocket_interface_->Close(
498 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
499 callback.GetCallback().pp_completion_callback()));
500 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
501 core_interface_->ReleaseResource(ws);
503 // Close with PP_VARTYPE_NULL and ongoing receive message.
504 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
505 ASSERT_TRUE(ws);
506 ASSERT_EQ(PP_OK, result);
507 PP_Var receive_message_var;
508 result = websocket_interface_->ReceiveMessage(
509 ws, &receive_message_var,
510 async_callback.GetCallback().pp_completion_callback());
511 ASSERT_EQ(PP_OK_COMPLETIONPENDING, 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 const char* send_message = "hi";
517 PP_Var send_message_var = CreateVarString(send_message);
518 result = websocket_interface_->SendMessage(ws, send_message_var);
519 ReleaseVar(send_message_var);
520 ASSERT_EQ(PP_OK, result);
521 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
522 ASSERT_EQ(PP_OK, async_callback.result());
523 ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message));
524 ReleaseVar(receive_message_var);
525 core_interface_->ReleaseResource(ws);
527 // Close twice.
528 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
529 ASSERT_TRUE(ws);
530 ASSERT_EQ(PP_OK, result);
531 result = websocket_interface_->Close(
532 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
533 async_callback.GetCallback().pp_completion_callback());
534 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
535 // Call another Close() before previous one is in progress.
536 result = websocket_interface_->Close(
537 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
538 callback.GetCallback().pp_completion_callback());
539 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
540 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
541 ASSERT_EQ(PP_OK, async_callback.result());
542 // Call another Close() after previous one is completed.
543 // This Close() must do nothing and reports no error.
544 callback.WaitForResult(websocket_interface_->Close(
545 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
546 callback.GetCallback().pp_completion_callback()));
547 ASSERT_EQ(PP_OK, callback.result());
548 core_interface_->ReleaseResource(ws);
550 ReleaseVar(reason);
552 PASS();
555 std::string TestWebSocket::TestValidClose() {
556 PP_Var reason = CreateVarString("close for test");
557 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
558 PP_Var protocols[] = { PP_MakeUndefined() };
559 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
560 TestCompletionCallback another_callback(
561 instance_->pp_instance(), callback_type());
563 // Close.
564 int32_t result;
565 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, "");
566 ASSERT_TRUE(ws);
567 ASSERT_EQ(PP_OK, result);
568 callback.WaitForResult(websocket_interface_->Close(
569 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
570 callback.GetCallback().pp_completion_callback()));
571 CHECK_CALLBACK_BEHAVIOR(callback);
572 ASSERT_EQ(PP_OK, callback.result());
573 core_interface_->ReleaseResource(ws);
575 // Close without code and reason.
576 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
577 ASSERT_TRUE(ws);
578 ASSERT_EQ(PP_OK, result);
579 callback.WaitForResult(websocket_interface_->Close(
580 ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason,
581 callback.GetCallback().pp_completion_callback()));
582 ASSERT_EQ(PP_OK, callback.result());
583 core_interface_->ReleaseResource(ws);
585 // Close with PP_VARTYPE_UNDEFINED.
586 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
587 ASSERT_TRUE(ws);
588 ASSERT_EQ(PP_OK, result);
589 callback.WaitForResult(websocket_interface_->Close(
590 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
591 callback.GetCallback().pp_completion_callback()));
592 CHECK_CALLBACK_BEHAVIOR(callback);
593 ASSERT_EQ(PP_OK, callback.result());
594 core_interface_->ReleaseResource(ws);
596 // Close in connecting.
597 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
598 // successfully.
599 ws = websocket_interface_->Create(instance_->pp_instance());
600 result = websocket_interface_->Connect(
601 ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback());
602 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
603 result = websocket_interface_->Close(
604 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
605 another_callback.GetCallback().pp_completion_callback());
606 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
607 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
608 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
609 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
610 ASSERT_EQ(PP_OK, another_callback.result());
611 core_interface_->ReleaseResource(ws);
613 // Close in closing.
614 // The first close will be done successfully, then the second one failed with
615 // with PP_ERROR_INPROGRESS immediately.
616 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
617 ASSERT_TRUE(ws);
618 ASSERT_EQ(PP_OK, result);
619 result = websocket_interface_->Close(
620 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
621 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_ERROR_INPROGRESS, result);
627 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
628 ASSERT_EQ(PP_OK, callback.result());
629 core_interface_->ReleaseResource(ws);
631 // Close with ongoing receive message.
632 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
633 ASSERT_TRUE(ws);
634 ASSERT_EQ(PP_OK, result);
635 PP_Var receive_message_var;
636 result = websocket_interface_->ReceiveMessage(
637 ws, &receive_message_var,
638 callback.GetCallback().pp_completion_callback());
639 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
640 result = websocket_interface_->Close(
641 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
642 another_callback.GetCallback().pp_completion_callback());
643 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
644 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
645 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
646 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
647 ASSERT_EQ(PP_OK, another_callback.result());
648 core_interface_->ReleaseResource(ws);
650 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
651 ws = Connect(GetFullURL(kEchoServerURL), &result, "");
652 ASSERT_TRUE(ws);
653 ASSERT_EQ(PP_OK, result);
654 result = websocket_interface_->ReceiveMessage(
655 ws, &receive_message_var,
656 callback.GetCallback().pp_completion_callback());
657 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
658 result = websocket_interface_->Close(
659 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
660 another_callback.GetCallback().pp_completion_callback());
661 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
662 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
663 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
664 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
665 ASSERT_EQ(PP_OK, another_callback.result());
666 core_interface_->ReleaseResource(ws);
668 // Server initiated closing handshake.
669 ws = Connect(GetFullURL(kCloseWithCodeAndReasonServerURL), &result, "");
670 ASSERT_TRUE(ws);
671 ASSERT_EQ(PP_OK, result);
672 // Text messsage "1000 bye" requests the server to initiate closing handshake
673 // with code being 1000 and reason being "bye".
674 PP_Var close_request_var = CreateVarString("1000 bye");
675 result = websocket_interface_->SendMessage(ws, close_request_var);
676 ReleaseVar(close_request_var);
677 callback.WaitForResult(websocket_interface_->ReceiveMessage(
678 ws, &receive_message_var,
679 callback.GetCallback().pp_completion_callback()));
680 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
681 core_interface_->ReleaseResource(ws);
683 ReleaseVar(reason);
684 ReleaseVar(url);
686 PASS();
689 std::string TestWebSocket::TestGetProtocol() {
690 const char* expected_protocols[] = {
691 "x-chat",
692 "hoehoe",
693 NULL
695 for (int i = 0; expected_protocols[i]; ++i) {
696 std::string url(GetFullURL(kProtocolTestServerURL));
697 url += expected_protocols[i];
698 int32_t result;
699 PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]);
700 ASSERT_TRUE(ws);
701 ASSERT_EQ(PP_OK, result);
703 PP_Var protocol = websocket_interface_->GetProtocol(ws);
704 ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i]));
706 ReleaseVar(protocol);
707 core_interface_->ReleaseResource(ws);
710 PASS();
713 std::string TestWebSocket::TestTextSendReceive() {
714 // Connect to test echo server.
715 int32_t connect_result;
716 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &connect_result, "");
717 ASSERT_TRUE(ws);
718 ASSERT_EQ(PP_OK, connect_result);
720 // Send 'hello pepper' text message.
721 const char* message = "hello pepper";
722 PP_Var message_var = CreateVarString(message);
723 int32_t result = websocket_interface_->SendMessage(ws, message_var);
724 ReleaseVar(message_var);
725 ASSERT_EQ(PP_OK, result);
727 // Receive echoed 'hello pepper'.
728 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
729 PP_Var received_message;
730 callback.WaitForResult(websocket_interface_->ReceiveMessage(
731 ws, &received_message, callback.GetCallback().pp_completion_callback()));
732 ASSERT_EQ(PP_OK, callback.result());
733 ASSERT_TRUE(AreEqualWithString(received_message, message));
734 ReleaseVar(received_message);
735 core_interface_->ReleaseResource(ws);
737 PASS();
740 std::string TestWebSocket::TestBinarySendReceive() {
741 // Connect to test echo server.
742 int32_t connect_result;
743 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &connect_result, "");
744 ASSERT_TRUE(ws);
745 ASSERT_EQ(PP_OK, connect_result);
747 // Send binary message.
748 std::vector<uint8_t> binary(256);
749 for (uint32_t i = 0; i < binary.size(); ++i)
750 binary[i] = i;
751 PP_Var message_var = CreateVarBinary(binary);
752 int32_t result = websocket_interface_->SendMessage(ws, message_var);
753 ReleaseVar(message_var);
754 ASSERT_EQ(PP_OK, result);
756 // Receive echoed binary.
757 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
758 PP_Var received_message;
759 callback.WaitForResult(websocket_interface_->ReceiveMessage(
760 ws, &received_message, callback.GetCallback().pp_completion_callback()));
761 ASSERT_EQ(PP_OK, callback.result());
762 ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
763 ReleaseVar(received_message);
764 core_interface_->ReleaseResource(ws);
766 PASS();
769 std::string TestWebSocket::TestStressedSendReceive() {
770 // Connect to test echo server.
771 int32_t connect_result;
772 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &connect_result, "");
773 ASSERT_TRUE(ws);
774 ASSERT_EQ(PP_OK, connect_result);
776 // Prepare PP_Var objects to send.
777 const char* text = "hello pepper";
778 PP_Var text_var = CreateVarString(text);
779 std::vector<uint8_t> binary(256);
780 for (uint32_t i = 0; i < binary.size(); ++i)
781 binary[i] = i;
782 PP_Var binary_var = CreateVarBinary(binary);
783 // Prepare very large binary data over 64KiB. Object serializer in
784 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
785 // to SRPC. In case received data over 64KiB exists, a specific code handles
786 // this large data via asynchronous callback from main thread. This data
787 // intends to test the code.
788 std::vector<uint8_t> large_binary(65 * 1024);
789 for (uint32_t i = 0; i < large_binary.size(); ++i)
790 large_binary[i] = i & 0xff;
791 PP_Var large_binary_var = CreateVarBinary(large_binary);
793 // Send many messages.
794 int32_t result;
795 for (int i = 0; i < 256; ++i) {
796 result = websocket_interface_->SendMessage(ws, text_var);
797 ASSERT_EQ(PP_OK, result);
798 result = websocket_interface_->SendMessage(ws, binary_var);
799 ASSERT_EQ(PP_OK, result);
801 result = websocket_interface_->SendMessage(ws, large_binary_var);
802 ASSERT_EQ(PP_OK, result);
803 ReleaseVar(text_var);
804 ReleaseVar(binary_var);
805 ReleaseVar(large_binary_var);
807 // Receive echoed data.
808 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
809 for (int i = 0; i <= 512; ++i) {
810 PP_Var received_message;
811 callback.WaitForResult(websocket_interface_->ReceiveMessage(
812 ws, &received_message,
813 callback.GetCallback().pp_completion_callback()));
814 ASSERT_EQ(PP_OK, callback.result());
815 if (i == 512) {
816 ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary));
817 } else if (i & 1) {
818 ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
819 } else {
820 ASSERT_TRUE(AreEqualWithString(received_message, text));
822 ReleaseVar(received_message);
824 core_interface_->ReleaseResource(ws);
826 PASS();
829 std::string TestWebSocket::TestBufferedAmount() {
830 // Connect to test echo server.
831 int32_t connect_result;
832 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &connect_result, "");
833 ASSERT_TRUE(ws);
834 ASSERT_EQ(PP_OK, connect_result);
836 // Prepare a large message that is not aligned with the internal buffer
837 // sizes.
838 std::string message(8193, 'x');
839 PP_Var message_var = CreateVarString(message);
841 uint64_t buffered_amount = 0;
842 int32_t result;
843 for (int i = 0; i < 100; i++) {
844 result = websocket_interface_->SendMessage(ws, message_var);
845 ASSERT_EQ(PP_OK, result);
846 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
847 // Buffered amount size 262144 is too big for the internal buffer size.
848 if (buffered_amount > 262144)
849 break;
852 // Close connection.
853 std::string reason_str = "close while busy";
854 PP_Var reason = CreateVarString(reason_str.c_str());
855 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
856 result = websocket_interface_->Close(
857 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
858 callback.GetCallback().pp_completion_callback());
859 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
860 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING,
861 websocket_interface_->GetReadyState(ws));
863 callback.WaitForResult(result);
864 ASSERT_EQ(PP_OK, callback.result());
865 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED,
866 websocket_interface_->GetReadyState(ws));
868 uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws);
870 // After connection closure, all sending requests fail and just increase
871 // the bufferedAmount property.
872 PP_Var empty_string = CreateVarString("");
873 result = websocket_interface_->SendMessage(ws, empty_string);
874 ASSERT_EQ(PP_ERROR_FAILED, result);
875 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
876 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
877 base_buffered_amount = buffered_amount;
879 result = websocket_interface_->SendMessage(ws, reason);
880 ASSERT_EQ(PP_ERROR_FAILED, result);
881 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
882 uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length();
883 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
885 ReleaseVar(message_var);
886 ReleaseVar(reason);
887 ReleaseVar(empty_string);
888 core_interface_->ReleaseResource(ws);
890 PASS();
893 std::string TestWebSocket::TestAbortCalls() {
894 // Test abort behaviors where a WebSocket PP_Resource is released while
895 // each function is in-flight on the WebSocket PP_Resource.
896 std::vector<uint8_t> large_binary(65 * 1024);
897 PP_Var large_var = CreateVarBinary(large_binary);
899 // Firstly, test the behavior for SendMessage().
900 // This function doesn't require a callback, but operation will be done
901 // asynchronously in WebKit and browser process.
902 int32_t result;
903 std::string url = GetFullURL(kEchoServerURL);
904 PP_Resource ws = Connect(url, &result, "");
905 ASSERT_TRUE(ws);
906 ASSERT_EQ(PP_OK, result);
907 result = websocket_interface_->SendMessage(ws, large_var);
908 ASSERT_EQ(PP_OK, result);
909 core_interface_->ReleaseResource(ws);
911 // Following tests make sure the behavior for functions which require a
912 // callback. The callback must get a PP_ERROR_ABORTED.
913 // Test the behavior for Connect().
914 ws = websocket_interface_->Create(instance_->pp_instance());
915 ASSERT_TRUE(ws);
916 PP_Var url_var = CreateVarString(url);
917 TestCompletionCallback connect_callback(
918 instance_->pp_instance(), callback_type());
919 result = websocket_interface_->Connect(
920 ws, url_var, NULL, 0,
921 connect_callback.GetCallback().pp_completion_callback());
922 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
923 core_interface_->ReleaseResource(ws);
924 connect_callback.WaitForResult(result);
925 ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result());
926 ReleaseVar(url_var);
928 // Test the behavior for Close().
929 ws = Connect(url, &result, "");
930 ASSERT_TRUE(ws);
931 ASSERT_EQ(PP_OK, result);
932 PP_Var reason_var = CreateVarString("abort");
933 TestCompletionCallback close_callback(
934 instance_->pp_instance(), callback_type());
935 result = websocket_interface_->Close(
936 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var,
937 close_callback.GetCallback().pp_completion_callback());
938 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
939 core_interface_->ReleaseResource(ws);
940 close_callback.WaitForResult(result);
941 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
942 ReleaseVar(reason_var);
944 // Test the behavior for ReceiveMessage().
945 // Firstly, make sure the simplest case to wait for data which never arrives.
946 ws = Connect(url, &result, "");
947 ASSERT_TRUE(ws);
948 ASSERT_EQ(PP_OK, result);
949 PP_Var receive_var;
950 TestCompletionCallback receive_callback(
951 instance_->pp_instance(), callback_type());
952 result = websocket_interface_->ReceiveMessage(
953 ws, &receive_var,
954 receive_callback.GetCallback().pp_completion_callback());
955 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
956 core_interface_->ReleaseResource(ws);
957 receive_callback.WaitForResult(result);
958 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
960 // Release the resource in the close completion callback.
961 ws = Connect(url, &result, "");
962 ASSERT_TRUE(ws);
963 ASSERT_EQ(PP_OK, result);
964 result = websocket_interface_->Close(
965 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
966 close_callback.GetCallback().pp_completion_callback());
967 ReleaseResourceDelegate close_delegate(core_interface_, ws);
968 close_callback.SetDelegate(&close_delegate);
969 close_callback.WaitForResult(result);
970 CHECK_CALLBACK_BEHAVIOR(close_callback);
971 ASSERT_EQ(PP_OK, close_callback.result());
973 // Release the resource in the aborting receive completion callback which is
974 // introduced by calling Close().
975 ws = Connect(url, &result, "");
976 ASSERT_TRUE(ws);
977 ASSERT_EQ(PP_OK, result);
978 result = websocket_interface_->ReceiveMessage(
979 ws, &receive_var,
980 receive_callback.GetCallback().pp_completion_callback());
981 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
982 ReleaseResourceDelegate receive_delegate(core_interface_, ws);
983 receive_callback.SetDelegate(&receive_delegate);
984 result = websocket_interface_->Close(
985 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
986 close_callback.GetCallback().pp_completion_callback());
987 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
988 receive_callback.WaitForResult(result);
989 CHECK_CALLBACK_BEHAVIOR(receive_callback);
990 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
991 close_callback.WaitForResult(result);
992 CHECK_CALLBACK_BEHAVIOR(close_callback);
993 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
995 // Test the behavior where receive process might be in-flight.
996 const char* text = "yukarin";
997 PP_Var text_var = CreateVarString(text);
999 // Each trial sends 17 messages and receives just |trial| number of
1000 // message(s) before releasing the WebSocket. The WebSocket is released while
1001 // the next message is going to be received.
1002 for (int trial = 1; trial <= 16; trial++) {
1003 ws = Connect(url, &result, "");
1004 ASSERT_TRUE(ws);
1005 ASSERT_EQ(PP_OK, result);
1006 for (int i = 0; i <= 16; ++i) {
1007 result = websocket_interface_->SendMessage(ws, text_var);
1008 ASSERT_EQ(PP_OK, result);
1010 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1011 PP_Var var;
1012 for (int i = 0; i < trial; ++i) {
1013 callback.WaitForResult(websocket_interface_->ReceiveMessage(
1014 ws, &var, callback.GetCallback().pp_completion_callback()));
1015 ASSERT_EQ(PP_OK, callback.result());
1016 ASSERT_TRUE(AreEqualWithString(var, text));
1017 ReleaseVar(var);
1019 result = websocket_interface_->ReceiveMessage(
1020 ws, &var, callback.GetCallback().pp_completion_callback());
1021 core_interface_->ReleaseResource(ws);
1022 if (result != PP_OK) {
1023 callback.WaitForResult(result);
1024 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1027 // Same test, but the last receiving message is large message over 64KiB.
1028 for (int trial = 1; trial <= 16; trial++) {
1029 ws = Connect(url, &result, "");
1030 ASSERT_TRUE(ws);
1031 ASSERT_EQ(PP_OK, result);
1032 for (int i = 0; i <= 16; ++i) {
1033 if (i == trial)
1034 result = websocket_interface_->SendMessage(ws, large_var);
1035 else
1036 result = websocket_interface_->SendMessage(ws, text_var);
1037 ASSERT_EQ(PP_OK, result);
1039 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1040 PP_Var var;
1041 for (int i = 0; i < trial; ++i) {
1042 callback.WaitForResult(websocket_interface_->ReceiveMessage(
1043 ws, &var, callback.GetCallback().pp_completion_callback()));
1044 ASSERT_EQ(PP_OK, callback.result());
1045 ASSERT_TRUE(AreEqualWithString(var, text));
1046 ReleaseVar(var);
1048 result = websocket_interface_->ReceiveMessage(
1049 ws, &var, callback.GetCallback().pp_completion_callback());
1050 core_interface_->ReleaseResource(ws);
1051 if (result != PP_OK) {
1052 callback.WaitForResult(result);
1053 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1057 ReleaseVar(large_var);
1058 ReleaseVar(text_var);
1060 PASS();
1063 std::string TestWebSocket::TestCcInterfaces() {
1064 // C++ bindings is simple straightforward, then just verifies interfaces work
1065 // as a interface bridge fine.
1066 pp::WebSocket ws(instance_);
1068 // Check uninitialized properties access.
1069 ASSERT_EQ(0, ws.GetBufferedAmount());
1070 ASSERT_EQ(0, ws.GetCloseCode());
1071 ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), ""));
1072 ASSERT_EQ(false, ws.GetCloseWasClean());
1073 ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), ""));
1074 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), ""));
1075 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState());
1076 ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), ""));
1078 // Check communication interfaces (connect, send, receive, and close).
1079 TestCompletionCallback connect_callback(
1080 instance_->pp_instance(), callback_type());
1081 connect_callback.WaitForResult(ws.Connect(
1082 pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U, connect_callback));
1083 CHECK_CALLBACK_BEHAVIOR(connect_callback);
1084 ASSERT_EQ(PP_OK, connect_callback.result());
1086 std::string text_message("hello C++");
1087 int32_t result = ws.SendMessage(pp::Var(text_message));
1088 ASSERT_EQ(PP_OK, result);
1090 std::vector<uint8_t> binary(256);
1091 for (uint32_t i = 0; i < binary.size(); ++i)
1092 binary[i] = i;
1093 result = ws.SendMessage(
1094 pp::Var(pp::PASS_REF, CreateVarBinary(binary)));
1095 ASSERT_EQ(PP_OK, result);
1097 pp::Var text_receive_var;
1098 TestCompletionCallback text_receive_callback(
1099 instance_->pp_instance(), callback_type());
1100 text_receive_callback.WaitForResult(
1101 ws.ReceiveMessage(&text_receive_var, text_receive_callback));
1102 ASSERT_EQ(PP_OK, text_receive_callback.result());
1103 ASSERT_TRUE(
1104 AreEqualWithString(text_receive_var.pp_var(), text_message.c_str()));
1106 pp::Var binary_receive_var;
1107 TestCompletionCallback binary_receive_callback(
1108 instance_->pp_instance(), callback_type());
1109 binary_receive_callback.WaitForResult(
1110 ws.ReceiveMessage(&binary_receive_var, binary_receive_callback));
1111 ASSERT_EQ(PP_OK, binary_receive_callback.result());
1112 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary));
1114 TestCompletionCallback close_callback(
1115 instance_->pp_instance(), callback_type());
1116 std::string reason("bye");
1117 close_callback.WaitForResult(ws.Close(
1118 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason), close_callback));
1119 CHECK_CALLBACK_BEHAVIOR(close_callback);
1120 ASSERT_EQ(PP_OK, close_callback.result());
1122 // Check initialized properties access.
1123 ASSERT_EQ(0, ws.GetBufferedAmount());
1124 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode());
1125 ASSERT_TRUE(
1126 AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str()));
1127 ASSERT_EQ(true, ws.GetCloseWasClean());
1128 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), ""));
1129 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState());
1130 ASSERT_TRUE(AreEqualWithString(
1131 ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str()));
1133 PASS();
1136 std::string TestWebSocket::TestUtilityInvalidConnect() {
1137 const pp::Var protocols[] = { pp::Var() };
1139 TestWebSocketAPI websocket(instance_);
1140 int32_t result = websocket.Connect(pp::Var(), protocols, 1U);
1141 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1142 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1144 result = websocket.Connect(pp::Var(), protocols, 1U);
1145 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1146 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1148 for (int i = 0; kInvalidURLs[i]; ++i) {
1149 TestWebSocketAPI ws(instance_);
1150 result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1151 if (result == PP_OK_COMPLETIONPENDING) {
1152 ws.WaitForClosed();
1153 const std::vector<WebSocketEvent>& events = ws.GetSeenEvents();
1154 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1155 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1156 ASSERT_EQ(2U, ws.GetSeenEvents().size());
1157 } else {
1158 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1159 ASSERT_EQ(0U, ws.GetSeenEvents().size());
1163 PASS();
1166 std::string TestWebSocket::TestUtilityProtocols() {
1167 const pp::Var bad_protocols[] = {
1168 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1169 const pp::Var good_protocols[] = {
1170 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1173 TestWebSocketAPI websocket(instance_);
1174 int32_t result = websocket.Connect(
1175 pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U);
1176 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1177 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1181 TestWebSocketAPI websocket(instance_);
1182 int32_t result = websocket.Connect(
1183 pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U);
1184 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1185 websocket.WaitForConnected();
1186 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1187 // Protocol arguments are valid, but this test run without a WebSocket
1188 // server. As a result, OnError() and OnClose() are invoked because of
1189 // a connection establishment failure.
1190 ASSERT_EQ(2U, events.size());
1191 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1192 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1193 ASSERT_FALSE(events[1].was_clean);
1196 PASS();
1199 std::string TestWebSocket::TestUtilityGetURL() {
1200 const pp::Var protocols[] = { pp::Var() };
1202 for (int i = 0; kInvalidURLs[i]; ++i) {
1203 TestWebSocketAPI websocket(instance_);
1204 int32_t result = websocket.Connect(
1205 pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1206 if (result == PP_OK_COMPLETIONPENDING) {
1207 websocket.WaitForClosed();
1208 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1209 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1210 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1211 ASSERT_EQ(2U, events.size());
1212 } else {
1213 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1214 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1216 pp::Var url = websocket.GetURL();
1217 ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i]));
1220 PASS();
1223 std::string TestWebSocket::TestUtilityValidConnect() {
1224 const pp::Var protocols[] = { pp::Var() };
1225 TestWebSocketAPI websocket(instance_);
1226 int32_t result = websocket.Connect(
1227 pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1228 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1229 websocket.WaitForConnected();
1230 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1231 ASSERT_EQ(1U, events.size());
1232 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1233 ASSERT_TRUE(AreEqualWithString(websocket.GetExtensions().pp_var(), ""));
1235 PASS();
1238 std::string TestWebSocket::TestUtilityInvalidClose() {
1239 const pp::Var reason = pp::Var(std::string("close for test"));
1241 // Close before connect.
1243 TestWebSocketAPI websocket(instance_);
1244 int32_t result = websocket.Close(
1245 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason);
1246 ASSERT_EQ(PP_ERROR_FAILED, result);
1247 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1250 // Close with bad arguments.
1252 TestWebSocketAPI websocket(instance_);
1253 int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)),
1254 NULL, 0);
1255 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1256 websocket.WaitForConnected();
1257 result = websocket.Close(1U, reason);
1258 ASSERT_EQ(PP_ERROR_NOACCESS, result);
1259 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1260 ASSERT_EQ(1U, events.size());
1261 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1264 PASS();
1267 std::string TestWebSocket::TestUtilityValidClose() {
1268 std::string reason("close for test");
1269 pp::Var url = pp::Var(GetFullURL(kCloseServerURL));
1271 // Close.
1273 TestWebSocketAPI websocket(instance_);
1274 int32_t result = websocket.Connect(url, NULL, 0U);
1275 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1276 websocket.WaitForConnected();
1277 result = websocket.Close(
1278 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1279 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1280 websocket.WaitForClosed();
1281 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1282 ASSERT_EQ(2U, events.size());
1283 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1284 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1285 ASSERT_TRUE(events[1].was_clean);
1286 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code);
1287 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str()));
1290 // Close in connecting.
1291 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1292 // successfully.
1294 TestWebSocketAPI websocket(instance_);
1295 int32_t result = websocket.Connect(url, NULL, 0U);
1296 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1297 result = websocket.Close(
1298 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1299 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1300 websocket.WaitForClosed();
1301 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1302 ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1303 int index = 0;
1304 if (events.size() == 3)
1305 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1306 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1307 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1308 ASSERT_FALSE(events[index].was_clean);
1311 // Close in closing.
1312 // The first close will be done successfully, then the second one failed with
1313 // with PP_ERROR_INPROGRESS immediately.
1315 TestWebSocketAPI websocket(instance_);
1316 int32_t result = websocket.Connect(url, NULL, 0U);
1317 result = websocket.Close(
1318 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1319 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1320 result = websocket.Close(
1321 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1322 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1323 websocket.WaitForClosed();
1324 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1325 ASSERT_TRUE(events.size() == 2 || events.size() == 3)
1326 int index = 0;
1327 if (events.size() == 3)
1328 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1329 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1330 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1331 ASSERT_FALSE(events[index].was_clean);
1334 PASS();
1337 std::string TestWebSocket::TestUtilityGetProtocol() {
1338 const std::string protocol("x-chat");
1339 const pp::Var protocols[] = { pp::Var(protocol) };
1340 std::string url(GetFullURL(kProtocolTestServerURL));
1341 url += protocol;
1342 TestWebSocketAPI websocket(instance_);
1343 int32_t result = websocket.Connect(pp::Var(url), protocols, 1U);
1344 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1345 websocket.WaitForReceived();
1346 ASSERT_TRUE(AreEqualWithString(
1347 websocket.GetProtocol().pp_var(), protocol.c_str()));
1348 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1349 // The server to which this test connect returns the decided protocol as a
1350 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1351 // after EVENT_OPEN event.
1352 ASSERT_EQ(2U, events.size());
1353 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1354 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1355 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str()));
1357 PASS();
1360 std::string TestWebSocket::TestUtilityTextSendReceive() {
1361 const pp::Var protocols[] = { pp::Var() };
1362 TestWebSocketAPI websocket(instance_);
1363 int32_t result =
1364 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1365 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1366 websocket.WaitForConnected();
1368 // Send 'hello pepper'.
1369 std::string message1("hello pepper");
1370 result = websocket.Send(pp::Var(std::string(message1)));
1371 ASSERT_EQ(PP_OK, result);
1373 // Receive echoed 'hello pepper'.
1374 websocket.WaitForReceived();
1376 // Send 'goodbye pepper'.
1377 std::string message2("goodbye pepper");
1378 result = websocket.Send(pp::Var(std::string(message2)));
1380 // Receive echoed 'goodbye pepper'.
1381 websocket.WaitForReceived();
1383 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1384 ASSERT_EQ(3U, events.size());
1385 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1386 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1387 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str()));
1388 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type);
1389 ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str()));
1391 PASS();
1394 std::string TestWebSocket::TestUtilityBinarySendReceive() {
1395 const pp::Var protocols[] = { pp::Var() };
1396 TestWebSocketAPI websocket(instance_);
1397 int32_t result =
1398 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1399 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1400 websocket.WaitForConnected();
1402 // Send binary message.
1403 uint32_t len = 256;
1404 std::vector<uint8_t> binary(len);
1405 for (uint32_t i = 0; i < len; ++i)
1406 binary[i] = i;
1407 pp::VarArrayBuffer message(len);
1408 uint8_t* var_data = static_cast<uint8_t*>(message.Map());
1409 std::copy(binary.begin(), binary.end(), var_data);
1410 result = websocket.Send(message);
1411 ASSERT_EQ(PP_OK, result);
1413 // Receive echoed binary message.
1414 websocket.WaitForReceived();
1416 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1417 ASSERT_EQ(2U, events.size());
1418 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1419 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1420 ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary));
1422 PASS();
1425 std::string TestWebSocket::TestUtilityBufferedAmount() {
1426 // Connect to test echo server.
1427 const pp::Var protocols[] = { pp::Var() };
1428 TestWebSocketAPI websocket(instance_);
1429 int32_t result =
1430 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1431 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1432 websocket.WaitForConnected();
1434 // Prepare a large message that is not aligned with the internal buffer
1435 // sizes.
1436 std::string message(8193, 'x');
1437 uint64_t buffered_amount = 0;
1438 uint32_t sent;
1439 for (sent = 0; sent < 100; sent++) {
1440 result = websocket.Send(pp::Var(message));
1441 ASSERT_EQ(PP_OK, result);
1442 buffered_amount = websocket.GetBufferedAmount();
1443 // Buffered amount size 262144 is too big for the internal buffer size.
1444 if (buffered_amount > 262144)
1445 break;
1448 // Close connection.
1449 std::string reason = "close while busy";
1450 result = websocket.Close(
1451 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1452 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState());
1453 websocket.WaitForClosed();
1454 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState());
1456 uint64_t base_buffered_amount = websocket.GetBufferedAmount();
1457 size_t events_on_closed = websocket.GetSeenEvents().size();
1459 // After connection closure, all sending requests fail and just increase
1460 // the bufferedAmount property.
1461 result = websocket.Send(pp::Var(std::string("")));
1462 ASSERT_EQ(PP_ERROR_FAILED, result);
1463 buffered_amount = websocket.GetBufferedAmount();
1464 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
1465 base_buffered_amount = buffered_amount;
1467 result = websocket.Send(pp::Var(reason));
1468 ASSERT_EQ(PP_ERROR_FAILED, result);
1469 buffered_amount = websocket.GetBufferedAmount();
1470 uint64_t reason_frame_size = kMessageFrameOverhead + reason.length();
1471 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
1473 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1474 ASSERT_EQ(events_on_closed, events.size());
1475 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1476 size_t last_event = events_on_closed - 1;
1477 for (uint32_t i = 1; i < last_event; ++i) {
1478 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type);
1479 ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message));
1481 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type);
1482 ASSERT_TRUE(events[last_event].was_clean);
1484 PASS();