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