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. 4 5 #include "ppapi/tests/test_websocket.h" 6 7 #include <stdio.h> 8 #include <string.h> 9 10 #include <algorithm> 11 #include <memory> 12 #include <string> 13 #include <vector> 14 15 #include "ppapi/c/pp_bool.h" 16 #include "ppapi/c/pp_completion_callback.h" 17 #include "ppapi/c/pp_errors.h" 18 #include "ppapi/c/pp_instance.h" 19 #include "ppapi/c/pp_resource.h" 20 #include "ppapi/c/pp_var.h" 21 #include "ppapi/c/ppb_core.h" 22 #include "ppapi/c/ppb_var.h" 23 #include "ppapi/c/ppb_var_array_buffer.h" 24 #include "ppapi/c/ppb_websocket.h" 25 #include "ppapi/c/private/ppb_testing_private.h" 26 #include "ppapi/cpp/instance.h" 27 #include "ppapi/cpp/module.h" 28 #include "ppapi/cpp/var_array_buffer.h" 29 #include "ppapi/cpp/websocket.h" 30 #include "ppapi/tests/test_utils.h" 31 #include "ppapi/tests/testing_instance.h" 32 #include "ppapi/utility/websocket/websocket_api.h" 33 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="; 41 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", 46 NULL 47 }; 48 49 // Internal packet sizes. 50 const uint64_t kMessageFrameOverhead = 6; 51 52 namespace { 53 54 struct WebSocketEvent { 55 enum EventType { 56 EVENT_OPEN, 57 EVENT_MESSAGE, 58 EVENT_ERROR, 59 EVENT_CLOSE 60 }; 61 62 WebSocketEvent(EventType type, 63 bool was_clean, 64 uint16_t close_code, 65 const pp::Var& var) 66 : event_type(type), 67 was_clean(was_clean), 68 close_code(close_code), 69 var(var) { 70 } 71 EventType event_type; 72 bool was_clean; 73 uint16_t close_code; 74 pp::Var var; 75 }; 76 77 class ReleaseResourceDelegate : public TestCompletionCallback::Delegate { 78 public: 79 explicit ReleaseResourceDelegate(const PPB_Core* core_interface, 80 PP_Resource resource) 81 : core_interface_(core_interface), 82 resource_(resource) { 83 } 84 85 // TestCompletionCallback::Delegate implementation. 86 virtual void OnCallback(void* user_data, int32_t result) { 87 if (resource_) 88 core_interface_->ReleaseResource(resource_); 89 } 90 91 private: 92 const PPB_Core* core_interface_; 93 PP_Resource resource_; 94 }; 95 96 class TestWebSocketAPI : public pp::WebSocketAPI { 97 public: 98 explicit TestWebSocketAPI(pp::Instance* instance) 99 : pp::WebSocketAPI(instance), 100 connected_(false), 101 received_(false), 102 closed_(false), 103 wait_for_connected_(false), 104 wait_for_received_(false), 105 wait_for_closed_(false), 106 instance_(instance->pp_instance()) { 107 } 108 109 virtual void WebSocketDidOpen() { 110 events_.push_back( 111 WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var())); 112 connected_ = true; 113 if (wait_for_connected_) { 114 GetTestingInterface()->QuitMessageLoop(instance_); 115 wait_for_connected_ = false; 116 } 117 } 118 119 virtual void WebSocketDidClose( 120 bool was_clean, uint16_t code, const pp::Var& reason) { 121 events_.push_back( 122 WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason)); 123 connected_ = true; 124 closed_ = true; 125 if (wait_for_connected_ || wait_for_closed_) { 126 GetTestingInterface()->QuitMessageLoop(instance_); 127 wait_for_connected_ = false; 128 wait_for_closed_ = false; 129 } 130 } 131 132 virtual void HandleWebSocketMessage(const pp::Var &message) { 133 events_.push_back( 134 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message)); 135 received_ = true; 136 if (wait_for_received_) { 137 GetTestingInterface()->QuitMessageLoop(instance_); 138 wait_for_received_ = false; 139 received_ = false; 140 } 141 } 142 143 virtual void HandleWebSocketError() { 144 events_.push_back( 145 WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var())); 146 } 147 148 void WaitForConnected() { 149 if (!connected_) { 150 wait_for_connected_ = true; 151 GetTestingInterface()->RunMessageLoop(instance_); 152 } 153 } 154 155 void WaitForReceived() { 156 if (!received_) { 157 wait_for_received_ = true; 158 GetTestingInterface()->RunMessageLoop(instance_); 159 } 160 } 161 162 void WaitForClosed() { 163 if (!closed_) { 164 wait_for_closed_ = true; 165 GetTestingInterface()->RunMessageLoop(instance_); 166 } 167 } 168 169 const std::vector<WebSocketEvent>& GetSeenEvents() const { 170 return events_; 171 } 172 173 private: 174 std::vector<WebSocketEvent> events_; 175 bool connected_; 176 bool received_; 177 bool closed_; 178 bool wait_for_connected_; 179 bool wait_for_received_; 180 bool wait_for_closed_; 181 PP_Instance instance_; 182 }; 183 184 } // namespace 185 186 REGISTER_TEST_CASE(WebSocket); 187 188 bool TestWebSocket::Init() { 189 websocket_interface_ = static_cast<const PPB_WebSocket*>( 190 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE)); 191 var_interface_ = static_cast<const PPB_Var*>( 192 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); 193 arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>( 194 pp::Module::Get()->GetBrowserInterface( 195 PPB_VAR_ARRAY_BUFFER_INTERFACE)); 196 core_interface_ = static_cast<const PPB_Core*>( 197 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE)); 198 if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ || 199 !core_interface_) 200 return false; 201 202 return CheckTestingInterface(); 203 } 204 205 void TestWebSocket::RunTests(const std::string& filter) { 206 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter); 207 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter); 208 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter); 209 RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter); 210 RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter); 211 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter); 212 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter); 213 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter); 214 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter); 215 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter); 216 RUN_TEST_BACKGROUND(TestWebSocket, TextSendReceiveTwice, filter); 217 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive, filter); 218 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive, filter); 219 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount, filter); 220 // PP_Resource for WebSocket may be released later because of an internal 221 // reference for asynchronous IPC handling. So, suppress reference check on 222 // the following AbortCallsWithCallback test. 223 RUN_TEST(AbortCallsWithCallback, filter); 224 RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall, filter); 225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall, filter); 226 RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall, filter); 227 228 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter); 229 230 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect, filter); 231 RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols, filter); 232 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL, filter); 233 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect, filter); 234 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose, filter); 235 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose, filter); 236 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol, filter); 237 RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive, filter); 238 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive, filter); 239 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount, filter); 240 } 241 242 std::string TestWebSocket::GetFullURL(const char* url) { 243 std::string rv = "ws://"; 244 // Some WebSocket tests don't start the server so there'll be no host and 245 // port. 246 if (instance_->websocket_host().empty()) 247 rv += "127.0.0.1"; 248 else 249 rv += instance_->websocket_host(); 250 if (instance_->websocket_port() != -1) { 251 char buffer[10]; 252 sprintf(buffer, ":%d", instance_->websocket_port()); 253 rv += std::string(buffer); 254 } 255 rv += "/"; 256 rv += url; 257 return rv; 258 } 259 260 PP_Var TestWebSocket::CreateVarString(const std::string& string) { 261 return var_interface_->VarFromUtf8(string.c_str(), string.size()); 262 } 263 264 PP_Var TestWebSocket::CreateVarBinary(const std::vector<uint8_t>& binary) { 265 PP_Var var = arraybuffer_interface_->Create(binary.size()); 266 uint8_t* var_data = static_cast<uint8_t*>(arraybuffer_interface_->Map(var)); 267 std::copy(binary.begin(), binary.end(), var_data); 268 return var; 269 } 270 271 void TestWebSocket::ReleaseVar(const PP_Var& var) { 272 var_interface_->Release(var); 273 } 274 275 bool TestWebSocket::AreEqualWithString(const PP_Var& var, 276 const std::string& string) { 277 if (var.type != PP_VARTYPE_STRING) 278 return false; 279 uint32_t utf8_length; 280 const char* utf8 = var_interface_->VarToUtf8(var, &utf8_length); 281 if (utf8_length != string.size()) 282 return false; 283 if (string.compare(utf8)) 284 return false; 285 return true; 286 } 287 288 bool TestWebSocket::AreEqualWithBinary(const PP_Var& var, 289 const std::vector<uint8_t>& binary) { 290 uint32_t buffer_size = 0; 291 PP_Bool success = arraybuffer_interface_->ByteLength(var, &buffer_size); 292 if (!success || buffer_size != binary.size()) 293 return false; 294 if (!std::equal(binary.begin(), binary.end(), 295 static_cast<uint8_t*>(arraybuffer_interface_->Map(var)))) 296 return false; 297 return true; 298 } 299 300 PP_Resource TestWebSocket::Connect(const std::string& url, 301 int32_t* result, 302 const std::string& protocol) { 303 PP_Var protocols[] = { PP_MakeUndefined() }; 304 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 305 if (!ws) 306 return 0; 307 PP_Var url_var = CreateVarString(url); 308 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 309 uint32_t protocol_count = 0U; 310 if (protocol.size()) { 311 protocols[0] = CreateVarString(protocol); 312 protocol_count = 1U; 313 } 314 callback.WaitForResult(websocket_interface_->Connect( 315 ws, url_var, protocols, protocol_count, 316 callback.GetCallback().pp_completion_callback())); 317 ReleaseVar(url_var); 318 if (protocol.size()) 319 ReleaseVar(protocols[0]); 320 *result = callback.result(); 321 return ws; 322 } 323 324 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws, 325 const std::string& message) { 326 PP_Var message_var = CreateVarString(message); 327 websocket_interface_->SendMessage(ws, message_var); 328 ReleaseVar(message_var); 329 } 330 331 std::string TestWebSocket::TestIsWebSocket() { 332 // Test that a NULL resource isn't a websocket. 333 pp::Resource null_resource; 334 PP_Bool result = 335 websocket_interface_->IsWebSocket(null_resource.pp_resource()); 336 ASSERT_FALSE(result); 337 338 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 339 ASSERT_TRUE(ws); 340 341 result = websocket_interface_->IsWebSocket(ws); 342 ASSERT_TRUE(result); 343 344 core_interface_->ReleaseResource(ws); 345 346 PASS(); 347 } 348 349 std::string TestWebSocket::TestUninitializedPropertiesAccess() { 350 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 351 ASSERT_TRUE(ws); 352 353 uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws); 354 ASSERT_EQ(0U, bufferedAmount); 355 356 uint16_t close_code = websocket_interface_->GetCloseCode(ws); 357 ASSERT_EQ(0U, close_code); 358 359 PP_Var close_reason = websocket_interface_->GetCloseReason(ws); 360 ASSERT_TRUE(AreEqualWithString(close_reason, std::string())); 361 ReleaseVar(close_reason); 362 363 PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws); 364 ASSERT_EQ(PP_FALSE, close_was_clean); 365 366 PP_Var extensions = websocket_interface_->GetExtensions(ws); 367 ASSERT_TRUE(AreEqualWithString(extensions, std::string())); 368 ReleaseVar(extensions); 369 370 PP_Var protocol = websocket_interface_->GetProtocol(ws); 371 ASSERT_TRUE(AreEqualWithString(protocol, std::string())); 372 ReleaseVar(protocol); 373 374 PP_WebSocketReadyState ready_state = 375 websocket_interface_->GetReadyState(ws); 376 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state); 377 378 PP_Var url = websocket_interface_->GetURL(ws); 379 ASSERT_TRUE(AreEqualWithString(url, std::string())); 380 ReleaseVar(url); 381 382 core_interface_->ReleaseResource(ws); 383 384 PASS(); 385 } 386 387 std::string TestWebSocket::TestInvalidConnect() { 388 PP_Var protocols[] = { PP_MakeUndefined() }; 389 390 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 391 ASSERT_TRUE(ws); 392 393 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 394 callback.WaitForResult(websocket_interface_->Connect( 395 ws, PP_MakeUndefined(), protocols, 1U, 396 callback.GetCallback().pp_completion_callback())); 397 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 398 399 callback.WaitForResult(websocket_interface_->Connect( 400 ws, PP_MakeUndefined(), protocols, 1U, 401 callback.GetCallback().pp_completion_callback())); 402 ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result()); 403 404 core_interface_->ReleaseResource(ws); 405 406 for (int i = 0; kInvalidURLs[i]; ++i) { 407 int32_t result; 408 ws = Connect(kInvalidURLs[i], &result, std::string()); 409 ASSERT_TRUE(ws); 410 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 411 412 core_interface_->ReleaseResource(ws); 413 } 414 415 PASS(); 416 } 417 418 std::string TestWebSocket::TestProtocols() { 419 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str()); 420 PP_Var bad_protocols[] = { 421 CreateVarString("x-test"), 422 CreateVarString("x-test") 423 }; 424 PP_Var good_protocols[] = { 425 CreateVarString("x-test"), 426 CreateVarString("x-yatest") 427 }; 428 429 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 430 ASSERT_TRUE(ws); 431 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 432 callback.WaitForResult(websocket_interface_->Connect( 433 ws, url, bad_protocols, 2U, 434 callback.GetCallback().pp_completion_callback())); 435 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 436 core_interface_->ReleaseResource(ws); 437 438 ws = websocket_interface_->Create(instance_->pp_instance()); 439 ASSERT_TRUE(ws); 440 int32_t result = websocket_interface_->Connect( 441 ws, url, good_protocols, 2U, PP_BlockUntilComplete()); 442 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result); 443 core_interface_->ReleaseResource(ws); 444 445 ReleaseVar(url); 446 for (int i = 0; i < 2; ++i) { 447 ReleaseVar(bad_protocols[i]); 448 ReleaseVar(good_protocols[i]); 449 } 450 core_interface_->ReleaseResource(ws); 451 452 PASS(); 453 } 454 455 std::string TestWebSocket::TestGetURL() { 456 for (int i = 0; kInvalidURLs[i]; ++i) { 457 int32_t result; 458 PP_Resource ws = Connect(kInvalidURLs[i], &result, std::string()); 459 ASSERT_TRUE(ws); 460 PP_Var url = websocket_interface_->GetURL(ws); 461 ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i])); 462 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 463 464 ReleaseVar(url); 465 core_interface_->ReleaseResource(ws); 466 } 467 468 PASS(); 469 } 470 471 std::string TestWebSocket::TestValidConnect() { 472 int32_t result; 473 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 474 ASSERT_TRUE(ws); 475 ASSERT_EQ(PP_OK, result); 476 PP_Var extensions = websocket_interface_->GetExtensions(ws); 477 ASSERT_TRUE(AreEqualWithString(extensions, std::string())); 478 core_interface_->ReleaseResource(ws); 479 ReleaseVar(extensions); 480 481 PASS(); 482 } 483 484 std::string TestWebSocket::TestInvalidClose() { 485 PP_Var reason = CreateVarString("close for test"); 486 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 487 TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED); 488 489 // Close before connect. 490 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 491 callback.WaitForResult(websocket_interface_->Close( 492 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 493 callback.GetCallback().pp_completion_callback())); 494 ASSERT_EQ(PP_ERROR_FAILED, callback.result()); 495 core_interface_->ReleaseResource(ws); 496 497 // Close with bad arguments. 498 int32_t result; 499 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 500 ASSERT_TRUE(ws); 501 ASSERT_EQ(PP_OK, result); 502 callback.WaitForResult(websocket_interface_->Close( 503 ws, 1U, reason, callback.GetCallback().pp_completion_callback())); 504 ASSERT_EQ(PP_ERROR_NOACCESS, callback.result()); 505 core_interface_->ReleaseResource(ws); 506 507 // Close with PP_VARTYPE_NULL. 508 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 509 ASSERT_TRUE(ws); 510 ASSERT_EQ(PP_OK, result); 511 callback.WaitForResult(websocket_interface_->Close( 512 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(), 513 callback.GetCallback().pp_completion_callback())); 514 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 515 core_interface_->ReleaseResource(ws); 516 517 // Close with PP_VARTYPE_NULL and ongoing receive message. 518 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 519 ASSERT_TRUE(ws); 520 ASSERT_EQ(PP_OK, result); 521 PP_Var receive_message_var; 522 result = websocket_interface_->ReceiveMessage( 523 ws, &receive_message_var, 524 async_callback.GetCallback().pp_completion_callback()); 525 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 526 callback.WaitForResult(websocket_interface_->Close( 527 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(), 528 callback.GetCallback().pp_completion_callback())); 529 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 530 const char* send_message = "hi"; 531 PP_Var send_message_var = CreateVarString(send_message); 532 result = websocket_interface_->SendMessage(ws, send_message_var); 533 ReleaseVar(send_message_var); 534 ASSERT_EQ(PP_OK, result); 535 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 536 ASSERT_EQ(PP_OK, async_callback.result()); 537 ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message)); 538 ReleaseVar(receive_message_var); 539 core_interface_->ReleaseResource(ws); 540 541 // Close twice. 542 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 543 ASSERT_TRUE(ws); 544 ASSERT_EQ(PP_OK, result); 545 result = websocket_interface_->Close( 546 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 547 async_callback.GetCallback().pp_completion_callback()); 548 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 549 // Call another Close() before previous one is in progress. 550 result = websocket_interface_->Close( 551 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 552 callback.GetCallback().pp_completion_callback()); 553 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 554 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 555 ASSERT_EQ(PP_OK, async_callback.result()); 556 // Call another Close() after previous one is completed. 557 // This Close() must do nothing and reports no error. 558 callback.WaitForResult(websocket_interface_->Close( 559 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 560 callback.GetCallback().pp_completion_callback())); 561 ASSERT_EQ(PP_OK, callback.result()); 562 core_interface_->ReleaseResource(ws); 563 564 ReleaseVar(reason); 565 566 PASS(); 567 } 568 569 std::string TestWebSocket::TestValidClose() { 570 PP_Var reason = CreateVarString("close for test"); 571 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str()); 572 PP_Var protocols[] = { PP_MakeUndefined() }; 573 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 574 TestCompletionCallback another_callback( 575 instance_->pp_instance(), callback_type()); 576 577 // Close. 578 int32_t result; 579 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 580 ASSERT_TRUE(ws); 581 ASSERT_EQ(PP_OK, result); 582 callback.WaitForResult(websocket_interface_->Close( 583 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 584 callback.GetCallback().pp_completion_callback())); 585 CHECK_CALLBACK_BEHAVIOR(callback); 586 ASSERT_EQ(PP_OK, callback.result()); 587 core_interface_->ReleaseResource(ws); 588 589 // Close without code and reason. 590 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 591 ASSERT_TRUE(ws); 592 ASSERT_EQ(PP_OK, result); 593 callback.WaitForResult(websocket_interface_->Close( 594 ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason, 595 callback.GetCallback().pp_completion_callback())); 596 ASSERT_EQ(PP_OK, callback.result()); 597 core_interface_->ReleaseResource(ws); 598 599 // Close with PP_VARTYPE_UNDEFINED. 600 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 601 ASSERT_TRUE(ws); 602 ASSERT_EQ(PP_OK, result); 603 callback.WaitForResult(websocket_interface_->Close( 604 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 605 callback.GetCallback().pp_completion_callback())); 606 CHECK_CALLBACK_BEHAVIOR(callback); 607 ASSERT_EQ(PP_OK, callback.result()); 608 core_interface_->ReleaseResource(ws); 609 610 // Close in connecting. 611 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done 612 // successfully. 613 ws = websocket_interface_->Create(instance_->pp_instance()); 614 result = websocket_interface_->Connect( 615 ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback()); 616 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 617 result = websocket_interface_->Close( 618 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 619 another_callback.GetCallback().pp_completion_callback()); 620 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 621 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 622 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 623 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 624 ASSERT_EQ(PP_OK, another_callback.result()); 625 core_interface_->ReleaseResource(ws); 626 627 // Close in closing. 628 // The first close will be done successfully, then the second one failed with 629 // with PP_ERROR_INPROGRESS immediately. 630 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 631 ASSERT_TRUE(ws); 632 ASSERT_EQ(PP_OK, result); 633 result = websocket_interface_->Close( 634 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 635 callback.GetCallback().pp_completion_callback()); 636 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 637 result = websocket_interface_->Close( 638 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 639 another_callback.GetCallback().pp_completion_callback()); 640 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 641 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 642 ASSERT_EQ(PP_OK, callback.result()); 643 core_interface_->ReleaseResource(ws); 644 645 // Close with ongoing receive message. 646 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 647 ASSERT_TRUE(ws); 648 ASSERT_EQ(PP_OK, result); 649 PP_Var receive_message_var; 650 result = websocket_interface_->ReceiveMessage( 651 ws, &receive_message_var, 652 callback.GetCallback().pp_completion_callback()); 653 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 654 result = websocket_interface_->Close( 655 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 656 another_callback.GetCallback().pp_completion_callback()); 657 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 658 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 659 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 660 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 661 ASSERT_EQ(PP_OK, another_callback.result()); 662 core_interface_->ReleaseResource(ws); 663 664 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message. 665 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 666 ASSERT_TRUE(ws); 667 ASSERT_EQ(PP_OK, result); 668 result = websocket_interface_->ReceiveMessage( 669 ws, &receive_message_var, 670 callback.GetCallback().pp_completion_callback()); 671 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 672 result = websocket_interface_->Close( 673 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 674 another_callback.GetCallback().pp_completion_callback()); 675 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 676 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 677 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 678 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 679 ASSERT_EQ(PP_OK, another_callback.result()); 680 core_interface_->ReleaseResource(ws); 681 682 // Server initiated closing handshake. 683 ws = Connect( 684 GetFullURL(kCloseWithCodeAndReasonServerURL), &result, std::string()); 685 ASSERT_TRUE(ws); 686 ASSERT_EQ(PP_OK, result); 687 // Text messsage "1000 bye" requests the server to initiate closing handshake 688 // with code being 1000 and reason being "bye". 689 PP_Var close_request_var = CreateVarString("1000 bye"); 690 result = websocket_interface_->SendMessage(ws, close_request_var); 691 ReleaseVar(close_request_var); 692 callback.WaitForResult(websocket_interface_->ReceiveMessage( 693 ws, &receive_message_var, 694 callback.GetCallback().pp_completion_callback())); 695 ASSERT_EQ(PP_ERROR_FAILED, callback.result()); 696 core_interface_->ReleaseResource(ws); 697 698 ReleaseVar(reason); 699 ReleaseVar(url); 700 701 PASS(); 702 } 703 704 std::string TestWebSocket::TestGetProtocol() { 705 const char* expected_protocols[] = { 706 "x-chat", 707 "hoehoe", 708 NULL 709 }; 710 for (int i = 0; expected_protocols[i]; ++i) { 711 std::string url(GetFullURL(kProtocolTestServerURL)); 712 url += expected_protocols[i]; 713 int32_t result; 714 PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]); 715 ASSERT_TRUE(ws); 716 ASSERT_EQ(PP_OK, result); 717 718 PP_Var protocol = websocket_interface_->GetProtocol(ws); 719 ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i])); 720 721 ReleaseVar(protocol); 722 core_interface_->ReleaseResource(ws); 723 } 724 725 PASS(); 726 } 727 728 std::string TestWebSocket::TestTextSendReceive() { 729 // Connect to test echo server. 730 int32_t connect_result; 731 PP_Resource ws = 732 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 733 ASSERT_TRUE(ws); 734 ASSERT_EQ(PP_OK, connect_result); 735 736 // Send 'hello pepper' text message. 737 const char* message = "hello pepper"; 738 PP_Var message_var = CreateVarString(message); 739 int32_t result = websocket_interface_->SendMessage(ws, message_var); 740 ReleaseVar(message_var); 741 ASSERT_EQ(PP_OK, result); 742 743 // Receive echoed 'hello pepper'. 744 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 745 PP_Var received_message; 746 callback.WaitForResult(websocket_interface_->ReceiveMessage( 747 ws, &received_message, callback.GetCallback().pp_completion_callback())); 748 ASSERT_EQ(PP_OK, callback.result()); 749 ASSERT_TRUE(AreEqualWithString(received_message, message)); 750 ReleaseVar(received_message); 751 core_interface_->ReleaseResource(ws); 752 753 PASS(); 754 } 755 756 // Run as a BACKGROUND test. 757 std::string TestWebSocket::TestTextSendReceiveTwice() { 758 // Connect to test echo server. 759 int32_t connect_result; 760 PP_Resource ws = 761 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 762 ASSERT_TRUE(ws); 763 ASSERT_EQ(PP_OK, connect_result); 764 pp::MessageLoop message_loop = pp::MessageLoop::GetCurrent(); 765 pp::CompletionCallbackFactory<TestWebSocket> factory(this); 766 767 message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send, 768 ws, std::string("hello"))); 769 // When the server receives 'Goodbye', it closes the session. 770 message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send, 771 ws, std::string("Goodbye"))); 772 message_loop.PostQuit(false); 773 message_loop.Run(); 774 775 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 776 PP_Var received_message; 777 int32_t result = websocket_interface_->ReceiveMessage( 778 ws, &received_message, callback.GetCallback().pp_completion_callback()); 779 ASSERT_EQ(PP_OK, result); 780 // Since we don't run the message loop, the callback will stay 781 // "pending and scheduled to run" state. 782 783 // Waiting for the connection close which will be done by the server. 784 while (true) { 785 PP_WebSocketReadyState ready_state = 786 websocket_interface_->GetReadyState(ws); 787 if (ready_state != PP_WEBSOCKETREADYSTATE_CONNECTING && 788 ready_state != PP_WEBSOCKETREADYSTATE_OPEN) { 789 break; 790 } 791 PlatformSleep(100); // 100ms 792 } 793 794 // Cleanup the message loop 795 message_loop.PostQuit(false); 796 message_loop.Run(); 797 798 ASSERT_EQ(PP_OK, callback.result()); 799 ASSERT_TRUE(AreEqualWithString(received_message, "hello")); 800 ReleaseVar(received_message); 801 core_interface_->ReleaseResource(ws); 802 PASS(); 803 } 804 805 std::string TestWebSocket::TestBinarySendReceive() { 806 // Connect to test echo server. 807 int32_t connect_result; 808 PP_Resource ws = 809 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 810 ASSERT_TRUE(ws); 811 ASSERT_EQ(PP_OK, connect_result); 812 813 // Send binary message. 814 std::vector<uint8_t> binary(256); 815 for (uint32_t i = 0; i < binary.size(); ++i) 816 binary[i] = i; 817 PP_Var message_var = CreateVarBinary(binary); 818 int32_t result = websocket_interface_->SendMessage(ws, message_var); 819 ReleaseVar(message_var); 820 ASSERT_EQ(PP_OK, result); 821 822 // Receive echoed binary. 823 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 824 PP_Var received_message; 825 callback.WaitForResult(websocket_interface_->ReceiveMessage( 826 ws, &received_message, callback.GetCallback().pp_completion_callback())); 827 ASSERT_EQ(PP_OK, callback.result()); 828 ASSERT_TRUE(AreEqualWithBinary(received_message, binary)); 829 ReleaseVar(received_message); 830 core_interface_->ReleaseResource(ws); 831 832 PASS(); 833 } 834 835 std::string TestWebSocket::TestStressedSendReceive() { 836 // Connect to test echo server. 837 int32_t connect_result; 838 PP_Resource ws = 839 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 840 ASSERT_TRUE(ws); 841 ASSERT_EQ(PP_OK, connect_result); 842 843 // Prepare PP_Var objects to send. 844 const char* text = "hello pepper"; 845 PP_Var text_var = CreateVarString(text); 846 std::vector<uint8_t> binary(256); 847 for (uint32_t i = 0; i < binary.size(); ++i) 848 binary[i] = i; 849 PP_Var binary_var = CreateVarBinary(binary); 850 // Prepare very large binary data over 64KiB. Object serializer in 851 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size 852 // to SRPC. In case received data over 64KiB exists, a specific code handles 853 // this large data via asynchronous callback from main thread. This data 854 // intends to test the code. 855 std::vector<uint8_t> large_binary(65 * 1024); 856 for (uint32_t i = 0; i < large_binary.size(); ++i) 857 large_binary[i] = i & 0xff; 858 PP_Var large_binary_var = CreateVarBinary(large_binary); 859 860 // Send many messages. 861 int32_t result; 862 for (int i = 0; i < 256; ++i) { 863 result = websocket_interface_->SendMessage(ws, text_var); 864 ASSERT_EQ(PP_OK, result); 865 result = websocket_interface_->SendMessage(ws, binary_var); 866 ASSERT_EQ(PP_OK, result); 867 } 868 result = websocket_interface_->SendMessage(ws, large_binary_var); 869 ASSERT_EQ(PP_OK, result); 870 ReleaseVar(text_var); 871 ReleaseVar(binary_var); 872 ReleaseVar(large_binary_var); 873 874 // Receive echoed data. 875 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 876 for (int i = 0; i <= 512; ++i) { 877 PP_Var received_message; 878 callback.WaitForResult(websocket_interface_->ReceiveMessage( 879 ws, &received_message, 880 callback.GetCallback().pp_completion_callback())); 881 ASSERT_EQ(PP_OK, callback.result()); 882 if (i == 512) { 883 ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary)); 884 } else if (i & 1) { 885 ASSERT_TRUE(AreEqualWithBinary(received_message, binary)); 886 } else { 887 ASSERT_TRUE(AreEqualWithString(received_message, text)); 888 } 889 ReleaseVar(received_message); 890 } 891 core_interface_->ReleaseResource(ws); 892 893 PASS(); 894 } 895 896 std::string TestWebSocket::TestBufferedAmount() { 897 // Connect to test echo server. 898 int32_t connect_result; 899 PP_Resource ws = 900 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 901 ASSERT_TRUE(ws); 902 ASSERT_EQ(PP_OK, connect_result); 903 904 // Prepare a large message that is not aligned with the internal buffer 905 // sizes. 906 std::string message(8193, 'x'); 907 PP_Var message_var = CreateVarString(message); 908 909 uint64_t buffered_amount = 0; 910 int32_t result; 911 for (int i = 0; i < 100; i++) { 912 result = websocket_interface_->SendMessage(ws, message_var); 913 ASSERT_EQ(PP_OK, result); 914 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 915 // Buffered amount size 262144 is too big for the internal buffer size. 916 if (buffered_amount > 262144) 917 break; 918 } 919 920 // Close connection. 921 std::string reason_str = "close while busy"; 922 PP_Var reason = CreateVarString(reason_str.c_str()); 923 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 924 result = websocket_interface_->Close( 925 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 926 callback.GetCallback().pp_completion_callback()); 927 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 928 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, 929 websocket_interface_->GetReadyState(ws)); 930 931 callback.WaitForResult(result); 932 ASSERT_EQ(PP_OK, callback.result()); 933 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, 934 websocket_interface_->GetReadyState(ws)); 935 936 uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws); 937 938 // After connection closure, all sending requests fail and just increase 939 // the bufferedAmount property. 940 PP_Var empty_string = CreateVarString(std::string()); 941 result = websocket_interface_->SendMessage(ws, empty_string); 942 ASSERT_EQ(PP_ERROR_FAILED, result); 943 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 944 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount); 945 base_buffered_amount = buffered_amount; 946 947 result = websocket_interface_->SendMessage(ws, reason); 948 ASSERT_EQ(PP_ERROR_FAILED, result); 949 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 950 uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length(); 951 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount); 952 953 ReleaseVar(message_var); 954 ReleaseVar(reason); 955 ReleaseVar(empty_string); 956 core_interface_->ReleaseResource(ws); 957 958 PASS(); 959 } 960 961 // Test abort behaviors where a WebSocket PP_Resource is released while each 962 // function is in-flight on the WebSocket PP_Resource. 963 std::string TestWebSocket::TestAbortCallsWithCallback() { 964 // Following tests make sure the behavior for functions which require a 965 // callback. The callback must get a PP_ERROR_ABORTED. 966 967 // Test the behavior for Connect(). 968 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 969 ASSERT_TRUE(ws); 970 std::string url = GetFullURL(kEchoServerURL); 971 PP_Var url_var = CreateVarString(url); 972 TestCompletionCallback connect_callback( 973 instance_->pp_instance(), callback_type()); 974 int32_t result = websocket_interface_->Connect( 975 ws, url_var, NULL, 0, 976 connect_callback.GetCallback().pp_completion_callback()); 977 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 978 core_interface_->ReleaseResource(ws); 979 connect_callback.WaitForResult(result); 980 ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result()); 981 982 // Test the behavior for Close(). 983 ws = Connect(url, &result, std::string()); 984 ASSERT_TRUE(ws); 985 ASSERT_EQ(PP_OK, result); 986 PP_Var reason_var = CreateVarString("abort"); 987 TestCompletionCallback close_callback( 988 instance_->pp_instance(), callback_type()); 989 result = websocket_interface_->Close( 990 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var, 991 close_callback.GetCallback().pp_completion_callback()); 992 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 993 core_interface_->ReleaseResource(ws); 994 close_callback.WaitForResult(result); 995 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result()); 996 ReleaseVar(reason_var); 997 998 // Test the behavior for ReceiveMessage(). 999 // Make sure the simplest case to wait for data which never arrives, here. 1000 ws = Connect(url, &result, std::string()); 1001 ASSERT_TRUE(ws); 1002 ASSERT_EQ(PP_OK, result); 1003 PP_Var receive_var; 1004 TestCompletionCallback receive_callback( 1005 instance_->pp_instance(), callback_type()); 1006 result = websocket_interface_->ReceiveMessage( 1007 ws, &receive_var, 1008 receive_callback.GetCallback().pp_completion_callback()); 1009 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1010 core_interface_->ReleaseResource(ws); 1011 receive_callback.WaitForResult(result); 1012 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result()); 1013 1014 // Release the resource in the aborting receive completion callback which is 1015 // introduced by calling Close(). 1016 ws = Connect(url, &result, std::string()); 1017 ASSERT_TRUE(ws); 1018 ASSERT_EQ(PP_OK, result); 1019 result = websocket_interface_->ReceiveMessage( 1020 ws, &receive_var, 1021 receive_callback.GetCallback().pp_completion_callback()); 1022 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1023 ReleaseResourceDelegate receive_delegate(core_interface_, ws); 1024 receive_callback.SetDelegate(&receive_delegate); 1025 result = websocket_interface_->Close( 1026 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 1027 close_callback.GetCallback().pp_completion_callback()); 1028 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1029 receive_callback.WaitForResult(result); 1030 CHECK_CALLBACK_BEHAVIOR(receive_callback); 1031 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result()); 1032 close_callback.WaitForResult(result); 1033 CHECK_CALLBACK_BEHAVIOR(close_callback); 1034 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result()); 1035 1036 ReleaseVar(url_var); 1037 1038 PASS(); 1039 } 1040 1041 std::string TestWebSocket::TestAbortSendMessageCall() { 1042 // Test the behavior for SendMessage(). 1043 // This function doesn't require a callback, but operation will be done 1044 // asynchronously in WebKit and browser process. 1045 std::vector<uint8_t> large_binary(65 * 1024); 1046 PP_Var large_var = CreateVarBinary(large_binary); 1047 1048 int32_t result; 1049 std::string url = GetFullURL(kEchoServerURL); 1050 PP_Resource ws = Connect(url, &result, std::string()); 1051 ASSERT_TRUE(ws); 1052 ASSERT_EQ(PP_OK, result); 1053 result = websocket_interface_->SendMessage(ws, large_var); 1054 ASSERT_EQ(PP_OK, result); 1055 core_interface_->ReleaseResource(ws); 1056 ReleaseVar(large_var); 1057 1058 PASS(); 1059 } 1060 1061 std::string TestWebSocket::TestAbortCloseCall() { 1062 // Release the resource in the close completion callback. 1063 int32_t result; 1064 std::string url = GetFullURL(kEchoServerURL); 1065 PP_Resource ws = Connect(url, &result, std::string()); 1066 ASSERT_TRUE(ws); 1067 ASSERT_EQ(PP_OK, result); 1068 TestCompletionCallback close_callback( 1069 instance_->pp_instance(), callback_type()); 1070 result = websocket_interface_->Close( 1071 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 1072 close_callback.GetCallback().pp_completion_callback()); 1073 ReleaseResourceDelegate close_delegate(core_interface_, ws); 1074 close_callback.SetDelegate(&close_delegate); 1075 close_callback.WaitForResult(result); 1076 CHECK_CALLBACK_BEHAVIOR(close_callback); 1077 ASSERT_EQ(PP_OK, close_callback.result()); 1078 1079 PASS(); 1080 } 1081 1082 std::string TestWebSocket::TestAbortReceiveMessageCall() { 1083 // Test the behavior where receive process might be in-flight. 1084 std::vector<uint8_t> large_binary(65 * 1024); 1085 PP_Var large_var = CreateVarBinary(large_binary); 1086 const char* text = "yukarin"; 1087 PP_Var text_var = CreateVarString(text); 1088 1089 std::string url = GetFullURL(kEchoServerURL); 1090 int32_t result; 1091 PP_Resource ws; 1092 1093 // Each trial sends |trial_count| + 1 messages and receives just |trial| 1094 // number of message(s) before releasing the WebSocket. The WebSocket is 1095 // released while the next message is going to be received. 1096 const int trial_count = 8; 1097 for (int trial = 1; trial <= trial_count; trial++) { 1098 ws = Connect(url, &result, std::string()); 1099 ASSERT_TRUE(ws); 1100 ASSERT_EQ(PP_OK, result); 1101 for (int i = 0; i <= trial_count; ++i) { 1102 result = websocket_interface_->SendMessage(ws, text_var); 1103 ASSERT_EQ(PP_OK, result); 1104 } 1105 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1106 PP_Var var; 1107 for (int i = 0; i < trial; ++i) { 1108 callback.WaitForResult(websocket_interface_->ReceiveMessage( 1109 ws, &var, callback.GetCallback().pp_completion_callback())); 1110 ASSERT_EQ(PP_OK, callback.result()); 1111 ASSERT_TRUE(AreEqualWithString(var, text)); 1112 ReleaseVar(var); 1113 } 1114 result = websocket_interface_->ReceiveMessage( 1115 ws, &var, callback.GetCallback().pp_completion_callback()); 1116 core_interface_->ReleaseResource(ws); 1117 if (result != PP_OK) { 1118 callback.WaitForResult(result); 1119 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 1120 } 1121 } 1122 // Same test, but the last receiving message is large message over 64KiB. 1123 for (int trial = 1; trial <= trial_count; trial++) { 1124 ws = Connect(url, &result, std::string()); 1125 ASSERT_TRUE(ws); 1126 ASSERT_EQ(PP_OK, result); 1127 for (int i = 0; i <= trial_count; ++i) { 1128 if (i == trial) 1129 result = websocket_interface_->SendMessage(ws, large_var); 1130 else 1131 result = websocket_interface_->SendMessage(ws, text_var); 1132 ASSERT_EQ(PP_OK, result); 1133 } 1134 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1135 PP_Var var; 1136 for (int i = 0; i < trial; ++i) { 1137 callback.WaitForResult(websocket_interface_->ReceiveMessage( 1138 ws, &var, callback.GetCallback().pp_completion_callback())); 1139 ASSERT_EQ(PP_OK, callback.result()); 1140 ASSERT_TRUE(AreEqualWithString(var, text)); 1141 ReleaseVar(var); 1142 } 1143 result = websocket_interface_->ReceiveMessage( 1144 ws, &var, callback.GetCallback().pp_completion_callback()); 1145 core_interface_->ReleaseResource(ws); 1146 if (result != PP_OK) { 1147 callback.WaitForResult(result); 1148 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 1149 } 1150 } 1151 1152 ReleaseVar(large_var); 1153 ReleaseVar(text_var); 1154 1155 PASS(); 1156 } 1157 1158 std::string TestWebSocket::TestCcInterfaces() { 1159 // C++ bindings is simple straightforward, then just verifies interfaces work 1160 // as a interface bridge fine. 1161 pp::WebSocket ws(instance_); 1162 1163 // Check uninitialized properties access. 1164 ASSERT_EQ(0, ws.GetBufferedAmount()); 1165 ASSERT_EQ(0, ws.GetCloseCode()); 1166 ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), std::string())); 1167 ASSERT_EQ(false, ws.GetCloseWasClean()); 1168 ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), std::string())); 1169 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string())); 1170 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState()); 1171 ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), std::string())); 1172 1173 // Check communication interfaces (connect, send, receive, and close). 1174 TestCompletionCallback connect_callback( 1175 instance_->pp_instance(), callback_type()); 1176 connect_callback.WaitForResult(ws.Connect( 1177 pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U, 1178 connect_callback.GetCallback())); 1179 CHECK_CALLBACK_BEHAVIOR(connect_callback); 1180 ASSERT_EQ(PP_OK, connect_callback.result()); 1181 1182 std::string text_message("hello C++"); 1183 int32_t result = ws.SendMessage(pp::Var(text_message)); 1184 ASSERT_EQ(PP_OK, result); 1185 1186 std::vector<uint8_t> binary(256); 1187 for (uint32_t i = 0; i < binary.size(); ++i) 1188 binary[i] = i; 1189 result = ws.SendMessage( 1190 pp::Var(pp::PASS_REF, CreateVarBinary(binary))); 1191 ASSERT_EQ(PP_OK, result); 1192 1193 pp::Var text_receive_var; 1194 TestCompletionCallback text_receive_callback( 1195 instance_->pp_instance(), callback_type()); 1196 text_receive_callback.WaitForResult( 1197 ws.ReceiveMessage(&text_receive_var, 1198 text_receive_callback.GetCallback())); 1199 ASSERT_EQ(PP_OK, text_receive_callback.result()); 1200 ASSERT_TRUE( 1201 AreEqualWithString(text_receive_var.pp_var(), text_message.c_str())); 1202 1203 pp::Var binary_receive_var; 1204 TestCompletionCallback binary_receive_callback( 1205 instance_->pp_instance(), callback_type()); 1206 binary_receive_callback.WaitForResult( 1207 ws.ReceiveMessage(&binary_receive_var, 1208 binary_receive_callback.GetCallback())); 1209 ASSERT_EQ(PP_OK, binary_receive_callback.result()); 1210 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary)); 1211 1212 TestCompletionCallback close_callback( 1213 instance_->pp_instance(), callback_type()); 1214 std::string reason("bye"); 1215 close_callback.WaitForResult(ws.Close( 1216 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason), 1217 close_callback.GetCallback())); 1218 CHECK_CALLBACK_BEHAVIOR(close_callback); 1219 ASSERT_EQ(PP_OK, close_callback.result()); 1220 1221 // Check initialized properties access. 1222 ASSERT_EQ(0, ws.GetBufferedAmount()); 1223 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode()); 1224 ASSERT_TRUE( 1225 AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str())); 1226 ASSERT_EQ(true, ws.GetCloseWasClean()); 1227 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string())); 1228 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState()); 1229 ASSERT_TRUE(AreEqualWithString( 1230 ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str())); 1231 1232 PASS(); 1233 } 1234 1235 std::string TestWebSocket::TestUtilityInvalidConnect() { 1236 const pp::Var protocols[] = { pp::Var() }; 1237 1238 TestWebSocketAPI websocket(instance_); 1239 int32_t result = websocket.Connect(pp::Var(), protocols, 1U); 1240 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1241 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1242 1243 result = websocket.Connect(pp::Var(), protocols, 1U); 1244 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 1245 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1246 1247 for (int i = 0; kInvalidURLs[i]; ++i) { 1248 TestWebSocketAPI ws(instance_); 1249 result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); 1250 if (result == PP_OK_COMPLETIONPENDING) { 1251 ws.WaitForClosed(); 1252 const std::vector<WebSocketEvent>& events = ws.GetSeenEvents(); 1253 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1254 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1255 ASSERT_EQ(2U, ws.GetSeenEvents().size()); 1256 } else { 1257 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1258 ASSERT_EQ(0U, ws.GetSeenEvents().size()); 1259 } 1260 } 1261 1262 PASS(); 1263 } 1264 1265 std::string TestWebSocket::TestUtilityProtocols() { 1266 const pp::Var bad_protocols[] = { 1267 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) }; 1268 const pp::Var good_protocols[] = { 1269 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) }; 1270 1271 { 1272 TestWebSocketAPI websocket(instance_); 1273 int32_t result = websocket.Connect( 1274 pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U); 1275 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1276 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1277 } 1278 1279 { 1280 TestWebSocketAPI websocket(instance_); 1281 int32_t result = websocket.Connect( 1282 pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U); 1283 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1284 websocket.WaitForConnected(); 1285 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1286 // Protocol arguments are valid, but this test run without a WebSocket 1287 // server. As a result, OnError() and OnClose() are invoked because of 1288 // a connection establishment failure. 1289 ASSERT_EQ(2U, events.size()); 1290 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1291 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1292 ASSERT_FALSE(events[1].was_clean); 1293 } 1294 1295 PASS(); 1296 } 1297 1298 std::string TestWebSocket::TestUtilityGetURL() { 1299 const pp::Var protocols[] = { pp::Var() }; 1300 1301 for (int i = 0; kInvalidURLs[i]; ++i) { 1302 TestWebSocketAPI websocket(instance_); 1303 int32_t result = websocket.Connect( 1304 pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); 1305 if (result == PP_OK_COMPLETIONPENDING) { 1306 websocket.WaitForClosed(); 1307 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1308 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1309 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1310 ASSERT_EQ(2U, events.size()); 1311 } else { 1312 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1313 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1314 } 1315 pp::Var url = websocket.GetURL(); 1316 ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i])); 1317 } 1318 1319 PASS(); 1320 } 1321 1322 std::string TestWebSocket::TestUtilityValidConnect() { 1323 const pp::Var protocols[] = { pp::Var() }; 1324 TestWebSocketAPI websocket(instance_); 1325 int32_t result = websocket.Connect( 1326 pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1327 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1328 websocket.WaitForConnected(); 1329 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1330 ASSERT_EQ(1U, events.size()); 1331 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1332 ASSERT_TRUE( 1333 AreEqualWithString(websocket.GetExtensions().pp_var(), std::string())); 1334 1335 PASS(); 1336 } 1337 1338 std::string TestWebSocket::TestUtilityInvalidClose() { 1339 const pp::Var reason = pp::Var(std::string("close for test")); 1340 1341 // Close before connect. 1342 { 1343 TestWebSocketAPI websocket(instance_); 1344 int32_t result = websocket.Close( 1345 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason); 1346 ASSERT_EQ(PP_ERROR_FAILED, result); 1347 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1348 } 1349 1350 // Close with bad arguments. 1351 { 1352 TestWebSocketAPI websocket(instance_); 1353 int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), 1354 NULL, 0); 1355 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1356 websocket.WaitForConnected(); 1357 result = websocket.Close(1U, reason); 1358 ASSERT_EQ(PP_ERROR_NOACCESS, result); 1359 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1360 ASSERT_EQ(1U, events.size()); 1361 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1362 } 1363 1364 PASS(); 1365 } 1366 1367 std::string TestWebSocket::TestUtilityValidClose() { 1368 std::string reason("close for test"); 1369 pp::Var url = pp::Var(GetFullURL(kCloseServerURL)); 1370 1371 // Close. 1372 { 1373 TestWebSocketAPI websocket(instance_); 1374 int32_t result = websocket.Connect(url, NULL, 0U); 1375 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1376 websocket.WaitForConnected(); 1377 result = websocket.Close( 1378 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1379 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1380 websocket.WaitForClosed(); 1381 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1382 ASSERT_EQ(2U, events.size()); 1383 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1384 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1385 ASSERT_TRUE(events[1].was_clean); 1386 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code); 1387 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str())); 1388 } 1389 1390 // Close in connecting. 1391 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done 1392 // successfully. 1393 { 1394 TestWebSocketAPI websocket(instance_); 1395 int32_t result = websocket.Connect(url, NULL, 0U); 1396 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1397 result = websocket.Close( 1398 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1399 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1400 websocket.WaitForClosed(); 1401 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1402 ASSERT_TRUE(events.size() == 2 || events.size() == 3); 1403 int index = 0; 1404 if (events.size() == 3) 1405 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); 1406 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); 1407 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); 1408 ASSERT_FALSE(events[index].was_clean); 1409 } 1410 1411 // Close in closing. 1412 // The first close will be done successfully, then the second one failed with 1413 // with PP_ERROR_INPROGRESS immediately. 1414 { 1415 TestWebSocketAPI websocket(instance_); 1416 int32_t result = websocket.Connect(url, NULL, 0U); 1417 result = websocket.Close( 1418 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1419 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1420 result = websocket.Close( 1421 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1422 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 1423 websocket.WaitForClosed(); 1424 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1425 ASSERT_TRUE(events.size() == 2 || events.size() == 3); 1426 int index = 0; 1427 if (events.size() == 3) 1428 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); 1429 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); 1430 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); 1431 ASSERT_FALSE(events[index].was_clean); 1432 } 1433 1434 PASS(); 1435 } 1436 1437 std::string TestWebSocket::TestUtilityGetProtocol() { 1438 const std::string protocol("x-chat"); 1439 const pp::Var protocols[] = { pp::Var(protocol) }; 1440 std::string url(GetFullURL(kProtocolTestServerURL)); 1441 url += protocol; 1442 TestWebSocketAPI websocket(instance_); 1443 int32_t result = websocket.Connect(pp::Var(url), protocols, 1U); 1444 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1445 websocket.WaitForReceived(); 1446 ASSERT_TRUE(AreEqualWithString( 1447 websocket.GetProtocol().pp_var(), protocol.c_str())); 1448 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1449 // The server to which this test connect returns the decided protocol as a 1450 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event 1451 // after EVENT_OPEN event. 1452 ASSERT_EQ(2U, events.size()); 1453 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1454 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1455 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str())); 1456 1457 PASS(); 1458 } 1459 1460 std::string TestWebSocket::TestUtilityTextSendReceive() { 1461 const pp::Var protocols[] = { pp::Var() }; 1462 TestWebSocketAPI websocket(instance_); 1463 int32_t result = 1464 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1465 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1466 websocket.WaitForConnected(); 1467 1468 // Send 'hello pepper'. 1469 std::string message1("hello pepper"); 1470 result = websocket.Send(pp::Var(std::string(message1))); 1471 ASSERT_EQ(PP_OK, result); 1472 1473 // Receive echoed 'hello pepper'. 1474 websocket.WaitForReceived(); 1475 1476 // Send 'goodbye pepper'. 1477 std::string message2("goodbye pepper"); 1478 result = websocket.Send(pp::Var(std::string(message2))); 1479 1480 // Receive echoed 'goodbye pepper'. 1481 websocket.WaitForReceived(); 1482 1483 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1484 ASSERT_EQ(3U, events.size()); 1485 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1486 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1487 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str())); 1488 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type); 1489 ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str())); 1490 1491 PASS(); 1492 } 1493 1494 std::string TestWebSocket::TestUtilityBinarySendReceive() { 1495 const pp::Var protocols[] = { pp::Var() }; 1496 TestWebSocketAPI websocket(instance_); 1497 int32_t result = 1498 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1499 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1500 websocket.WaitForConnected(); 1501 1502 // Send binary message. 1503 uint32_t len = 256; 1504 std::vector<uint8_t> binary(len); 1505 for (uint32_t i = 0; i < len; ++i) 1506 binary[i] = i; 1507 pp::VarArrayBuffer message(len); 1508 uint8_t* var_data = static_cast<uint8_t*>(message.Map()); 1509 std::copy(binary.begin(), binary.end(), var_data); 1510 result = websocket.Send(message); 1511 ASSERT_EQ(PP_OK, result); 1512 1513 // Receive echoed binary message. 1514 websocket.WaitForReceived(); 1515 1516 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1517 ASSERT_EQ(2U, events.size()); 1518 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1519 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1520 ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary)); 1521 1522 PASS(); 1523 } 1524 1525 std::string TestWebSocket::TestUtilityBufferedAmount() { 1526 // Connect to test echo server. 1527 const pp::Var protocols[] = { pp::Var() }; 1528 TestWebSocketAPI websocket(instance_); 1529 int32_t result = 1530 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1531 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1532 websocket.WaitForConnected(); 1533 1534 // Prepare a large message that is not aligned with the internal buffer 1535 // sizes. 1536 std::string message(8193, 'x'); 1537 uint64_t buffered_amount = 0; 1538 uint32_t sent; 1539 for (sent = 0; sent < 100; sent++) { 1540 result = websocket.Send(pp::Var(message)); 1541 ASSERT_EQ(PP_OK, result); 1542 buffered_amount = websocket.GetBufferedAmount(); 1543 // Buffered amount size 262144 is too big for the internal buffer size. 1544 if (buffered_amount > 262144) 1545 break; 1546 } 1547 1548 // Close connection. 1549 std::string reason = "close while busy"; 1550 result = websocket.Close( 1551 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1552 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState()); 1553 websocket.WaitForClosed(); 1554 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState()); 1555 1556 uint64_t base_buffered_amount = websocket.GetBufferedAmount(); 1557 size_t events_on_closed = websocket.GetSeenEvents().size(); 1558 1559 // After connection closure, all sending requests fail and just increase 1560 // the bufferedAmount property. 1561 result = websocket.Send(pp::Var(std::string())); 1562 ASSERT_EQ(PP_ERROR_FAILED, result); 1563 buffered_amount = websocket.GetBufferedAmount(); 1564 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount); 1565 base_buffered_amount = buffered_amount; 1566 1567 result = websocket.Send(pp::Var(reason)); 1568 ASSERT_EQ(PP_ERROR_FAILED, result); 1569 buffered_amount = websocket.GetBufferedAmount(); 1570 uint64_t reason_frame_size = kMessageFrameOverhead + reason.length(); 1571 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount); 1572 1573 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1574 ASSERT_EQ(events_on_closed, events.size()); 1575 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1576 size_t last_event = events_on_closed - 1; 1577 for (uint32_t i = 1; i < last_event; ++i) { 1578 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type); 1579 ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message)); 1580 } 1581 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type); 1582 ASSERT_TRUE(events[last_event].was_clean); 1583 1584 PASS(); 1585 } 1586