Make certificate viewer a tab-modal dialog.
[chromium-blink-merge.git] / ppapi / tests / test_websocket.cc
blob61a8e199947111947aac12a0b446a4f61f0728b0
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/tests/test_websocket.h"
7 #include <stdio.h>
8 #include <string.h>
10 #include <algorithm>
11 #include <memory>
12 #include <string>
13 #include <vector>
15 #include "ppapi/c/dev/ppb_testing_dev.h"
16 #include "ppapi/c/pp_bool.h"
17 #include "ppapi/c/pp_completion_callback.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/c/pp_instance.h"
20 #include "ppapi/c/pp_resource.h"
21 #include "ppapi/c/pp_var.h"
22 #include "ppapi/c/ppb_core.h"
23 #include "ppapi/c/ppb_var.h"
24 #include "ppapi/c/ppb_var_array_buffer.h"
25 #include "ppapi/c/ppb_websocket.h"
26 #include "ppapi/cpp/instance.h"
27 #include "ppapi/cpp/module.h"
28 #include "ppapi/cpp/var_array_buffer.h"
29 #include "ppapi/cpp/websocket.h"
30 #include "ppapi/tests/test_utils.h"
31 #include "ppapi/tests/testing_instance.h"
32 #include "ppapi/utility/websocket/websocket_api.h"
34 // net::TestServer serves WebSocket service for testing.
35 // Following URLs are handled by pywebsocket handlers in
36 // net/data/websocket/*_wsh.py.
37 const char kEchoServerURL[] = "echo-with-no-extension";
38 const char kCloseServerURL[] = "close";
39 const char kCloseWithCodeAndReasonServerURL[] = "close-code-and-reason";
40 const char kProtocolTestServerURL[] = "protocol-test?protocol=";
42 const char* const kInvalidURLs[] = {
43 "http://www.google.com/invalid_scheme",
44 "ws://www.google.com/invalid#fragment",
45 "ws://www.google.com:65535/invalid_port",
46 NULL
49 // Internal packet sizes.
50 const uint64_t kCloseFrameSize = 6;
51 const uint64_t kMessageFrameOverhead = 6;
53 namespace {
55 struct WebSocketEvent {
56 enum EventType {
57 EVENT_OPEN,
58 EVENT_MESSAGE,
59 EVENT_ERROR,
60 EVENT_CLOSE
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) {
72 EventType event_type;
73 bool was_clean;
74 uint16_t close_code;
75 pp::Var var;
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) {
86 // TestCompletionCallback::Delegate implementation.
87 virtual void OnCallback(void* user_data, int32_t result) {
88 if (resource_)
89 core_interface_->ReleaseResource(resource_);
92 private:
93 const PPB_Core* core_interface_;
94 PP_Resource resource_;
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()) {
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;
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;
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;
144 virtual void HandleWebSocketError() {
145 events_.push_back(
146 WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var()));
149 void WaitForConnected() {
150 if (!connected_) {
151 wait_for_connected_ = true;
152 GetTestingInterface()->RunMessageLoop(instance_);
156 void WaitForReceived() {
157 if (!received_) {
158 wait_for_received_ = true;
159 GetTestingInterface()->RunMessageLoop(instance_);
163 void WaitForClosed() {
164 if (!closed_) {
165 wait_for_closed_ = true;
166 GetTestingInterface()->RunMessageLoop(instance_);
170 const std::vector<WebSocketEvent>& GetSeenEvents() const {
171 return events_;
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_;
185 } // namespace
187 REGISTER_TEST_CASE(WebSocket);
189 bool TestWebSocket::Init() {
190 websocket_interface_ = static_cast<const PPB_WebSocket*>(
191 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE));
192 var_interface_ = static_cast<const PPB_Var*>(
193 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
194 arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>(
195 pp::Module::Get()->GetBrowserInterface(
196 PPB_VAR_ARRAY_BUFFER_INTERFACE));
197 core_interface_ = static_cast<const PPB_Core*>(
198 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
199 if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ ||
200 !core_interface_)
201 return false;
203 return CheckTestingInterface();
206 void TestWebSocket::RunTests(const std::string& filter) {
207 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter);
208 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter);
209 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter);
210 RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter);
211 RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter);
212 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter);
213 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter);
214 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter);
215 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter);
216 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter);
217 RUN_TEST_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);
228 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter);
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);
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);
255 rv += "/";
256 rv += url;
257 return rv;
260 PP_Var TestWebSocket::CreateVarString(const std::string& string) {
261 return var_interface_->VarFromUtf8(string.c_str(), string.size());
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;
271 void TestWebSocket::ReleaseVar(const PP_Var& var) {
272 var_interface_->Release(var);
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;
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;
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;
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;
324 std::string TestWebSocket::TestIsWebSocket() {
325 // Test that a NULL resource isn't a websocket.
326 pp::Resource null_resource;
327 PP_Bool result =
328 websocket_interface_->IsWebSocket(null_resource.pp_resource());
329 ASSERT_FALSE(result);
331 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
332 ASSERT_TRUE(ws);
334 result = websocket_interface_->IsWebSocket(ws);
335 ASSERT_TRUE(result);
337 core_interface_->ReleaseResource(ws);
339 PASS();
342 std::string TestWebSocket::TestUninitializedPropertiesAccess() {
343 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
344 ASSERT_TRUE(ws);
346 uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws);
347 ASSERT_EQ(0U, bufferedAmount);
349 uint16_t close_code = websocket_interface_->GetCloseCode(ws);
350 ASSERT_EQ(0U, close_code);
352 PP_Var close_reason = websocket_interface_->GetCloseReason(ws);
353 ASSERT_TRUE(AreEqualWithString(close_reason, std::string()));
354 ReleaseVar(close_reason);
356 PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws);
357 ASSERT_EQ(PP_FALSE, close_was_clean);
359 PP_Var extensions = websocket_interface_->GetExtensions(ws);
360 ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
361 ReleaseVar(extensions);
363 PP_Var protocol = websocket_interface_->GetProtocol(ws);
364 ASSERT_TRUE(AreEqualWithString(protocol, std::string()));
365 ReleaseVar(protocol);
367 PP_WebSocketReadyState ready_state =
368 websocket_interface_->GetReadyState(ws);
369 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state);
371 PP_Var url = websocket_interface_->GetURL(ws);
372 ASSERT_TRUE(AreEqualWithString(url, std::string()));
373 ReleaseVar(url);
375 core_interface_->ReleaseResource(ws);
377 PASS();
380 std::string TestWebSocket::TestInvalidConnect() {
381 PP_Var protocols[] = { PP_MakeUndefined() };
383 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
384 ASSERT_TRUE(ws);
386 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
387 callback.WaitForResult(websocket_interface_->Connect(
388 ws, PP_MakeUndefined(), protocols, 1U,
389 callback.GetCallback().pp_completion_callback()));
390 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
392 callback.WaitForResult(websocket_interface_->Connect(
393 ws, PP_MakeUndefined(), protocols, 1U,
394 callback.GetCallback().pp_completion_callback()));
395 ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result());
397 core_interface_->ReleaseResource(ws);
399 for (int i = 0; kInvalidURLs[i]; ++i) {
400 int32_t result;
401 ws = Connect(kInvalidURLs[i], &result, std::string());
402 ASSERT_TRUE(ws);
403 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
405 core_interface_->ReleaseResource(ws);
408 PASS();
411 std::string TestWebSocket::TestProtocols() {
412 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
413 PP_Var bad_protocols[] = {
414 CreateVarString("x-test"),
415 CreateVarString("x-test")
417 PP_Var good_protocols[] = {
418 CreateVarString("x-test"),
419 CreateVarString("x-yatest")
422 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
423 ASSERT_TRUE(ws);
424 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
425 callback.WaitForResult(websocket_interface_->Connect(
426 ws, url, bad_protocols, 2U,
427 callback.GetCallback().pp_completion_callback()));
428 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
429 core_interface_->ReleaseResource(ws);
431 ws = websocket_interface_->Create(instance_->pp_instance());
432 ASSERT_TRUE(ws);
433 int32_t result = websocket_interface_->Connect(
434 ws, url, good_protocols, 2U, PP_BlockUntilComplete());
435 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result);
436 core_interface_->ReleaseResource(ws);
438 ReleaseVar(url);
439 for (int i = 0; i < 2; ++i) {
440 ReleaseVar(bad_protocols[i]);
441 ReleaseVar(good_protocols[i]);
443 core_interface_->ReleaseResource(ws);
445 PASS();
448 std::string TestWebSocket::TestGetURL() {
449 for (int i = 0; kInvalidURLs[i]; ++i) {
450 int32_t result;
451 PP_Resource ws = Connect(kInvalidURLs[i], &result, std::string());
452 ASSERT_TRUE(ws);
453 PP_Var url = websocket_interface_->GetURL(ws);
454 ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i]));
455 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
457 ReleaseVar(url);
458 core_interface_->ReleaseResource(ws);
461 PASS();
464 std::string TestWebSocket::TestValidConnect() {
465 int32_t result;
466 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
467 ASSERT_TRUE(ws);
468 ASSERT_EQ(PP_OK, result);
469 PP_Var extensions = websocket_interface_->GetExtensions(ws);
470 ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
471 core_interface_->ReleaseResource(ws);
472 ReleaseVar(extensions);
474 PASS();
477 std::string TestWebSocket::TestInvalidClose() {
478 PP_Var reason = CreateVarString("close for test");
479 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
480 TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED);
482 // Close before connect.
483 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
484 callback.WaitForResult(websocket_interface_->Close(
485 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
486 callback.GetCallback().pp_completion_callback()));
487 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
488 core_interface_->ReleaseResource(ws);
490 // Close with bad arguments.
491 int32_t result;
492 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
493 ASSERT_TRUE(ws);
494 ASSERT_EQ(PP_OK, result);
495 callback.WaitForResult(websocket_interface_->Close(
496 ws, 1U, reason, callback.GetCallback().pp_completion_callback()));
497 ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
498 core_interface_->ReleaseResource(ws);
500 // Close with PP_VARTYPE_NULL.
501 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
502 ASSERT_TRUE(ws);
503 ASSERT_EQ(PP_OK, result);
504 callback.WaitForResult(websocket_interface_->Close(
505 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
506 callback.GetCallback().pp_completion_callback()));
507 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
508 core_interface_->ReleaseResource(ws);
510 // Close with PP_VARTYPE_NULL and ongoing receive message.
511 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
512 ASSERT_TRUE(ws);
513 ASSERT_EQ(PP_OK, result);
514 PP_Var receive_message_var;
515 result = websocket_interface_->ReceiveMessage(
516 ws, &receive_message_var,
517 async_callback.GetCallback().pp_completion_callback());
518 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
519 callback.WaitForResult(websocket_interface_->Close(
520 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
521 callback.GetCallback().pp_completion_callback()));
522 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
523 const char* send_message = "hi";
524 PP_Var send_message_var = CreateVarString(send_message);
525 result = websocket_interface_->SendMessage(ws, send_message_var);
526 ReleaseVar(send_message_var);
527 ASSERT_EQ(PP_OK, result);
528 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
529 ASSERT_EQ(PP_OK, async_callback.result());
530 ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message));
531 ReleaseVar(receive_message_var);
532 core_interface_->ReleaseResource(ws);
534 // Close twice.
535 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
536 ASSERT_TRUE(ws);
537 ASSERT_EQ(PP_OK, result);
538 result = websocket_interface_->Close(
539 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
540 async_callback.GetCallback().pp_completion_callback());
541 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
542 // Call another Close() before previous one is in progress.
543 result = websocket_interface_->Close(
544 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
545 callback.GetCallback().pp_completion_callback());
546 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
547 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
548 ASSERT_EQ(PP_OK, async_callback.result());
549 // Call another Close() after previous one is completed.
550 // This Close() must do nothing and reports no error.
551 callback.WaitForResult(websocket_interface_->Close(
552 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
553 callback.GetCallback().pp_completion_callback()));
554 ASSERT_EQ(PP_OK, callback.result());
555 core_interface_->ReleaseResource(ws);
557 ReleaseVar(reason);
559 PASS();
562 std::string TestWebSocket::TestValidClose() {
563 PP_Var reason = CreateVarString("close for test");
564 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
565 PP_Var protocols[] = { PP_MakeUndefined() };
566 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
567 TestCompletionCallback another_callback(
568 instance_->pp_instance(), callback_type());
570 // Close.
571 int32_t result;
572 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
573 ASSERT_TRUE(ws);
574 ASSERT_EQ(PP_OK, result);
575 callback.WaitForResult(websocket_interface_->Close(
576 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
577 callback.GetCallback().pp_completion_callback()));
578 CHECK_CALLBACK_BEHAVIOR(callback);
579 ASSERT_EQ(PP_OK, callback.result());
580 core_interface_->ReleaseResource(ws);
582 // Close without code and reason.
583 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
584 ASSERT_TRUE(ws);
585 ASSERT_EQ(PP_OK, result);
586 callback.WaitForResult(websocket_interface_->Close(
587 ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason,
588 callback.GetCallback().pp_completion_callback()));
589 ASSERT_EQ(PP_OK, callback.result());
590 core_interface_->ReleaseResource(ws);
592 // Close with PP_VARTYPE_UNDEFINED.
593 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
594 ASSERT_TRUE(ws);
595 ASSERT_EQ(PP_OK, result);
596 callback.WaitForResult(websocket_interface_->Close(
597 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
598 callback.GetCallback().pp_completion_callback()));
599 CHECK_CALLBACK_BEHAVIOR(callback);
600 ASSERT_EQ(PP_OK, callback.result());
601 core_interface_->ReleaseResource(ws);
603 // Close in connecting.
604 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
605 // successfully.
606 ws = websocket_interface_->Create(instance_->pp_instance());
607 result = websocket_interface_->Connect(
608 ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback());
609 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
610 result = websocket_interface_->Close(
611 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
612 another_callback.GetCallback().pp_completion_callback());
613 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
614 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
615 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
616 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
617 ASSERT_EQ(PP_OK, another_callback.result());
618 core_interface_->ReleaseResource(ws);
620 // Close in closing.
621 // The first close will be done successfully, then the second one failed with
622 // with PP_ERROR_INPROGRESS immediately.
623 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
624 ASSERT_TRUE(ws);
625 ASSERT_EQ(PP_OK, result);
626 result = websocket_interface_->Close(
627 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
628 callback.GetCallback().pp_completion_callback());
629 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
630 result = websocket_interface_->Close(
631 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
632 another_callback.GetCallback().pp_completion_callback());
633 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
634 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
635 ASSERT_EQ(PP_OK, callback.result());
636 core_interface_->ReleaseResource(ws);
638 // Close with ongoing receive message.
639 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
640 ASSERT_TRUE(ws);
641 ASSERT_EQ(PP_OK, result);
642 PP_Var receive_message_var;
643 result = websocket_interface_->ReceiveMessage(
644 ws, &receive_message_var,
645 callback.GetCallback().pp_completion_callback());
646 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
647 result = websocket_interface_->Close(
648 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
649 another_callback.GetCallback().pp_completion_callback());
650 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
651 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
652 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
653 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
654 ASSERT_EQ(PP_OK, another_callback.result());
655 core_interface_->ReleaseResource(ws);
657 // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
658 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
659 ASSERT_TRUE(ws);
660 ASSERT_EQ(PP_OK, result);
661 result = websocket_interface_->ReceiveMessage(
662 ws, &receive_message_var,
663 callback.GetCallback().pp_completion_callback());
664 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
665 result = websocket_interface_->Close(
666 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
667 another_callback.GetCallback().pp_completion_callback());
668 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
669 callback.WaitForResult(PP_OK_COMPLETIONPENDING);
670 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
671 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
672 ASSERT_EQ(PP_OK, another_callback.result());
673 core_interface_->ReleaseResource(ws);
675 // Server initiated closing handshake.
676 ws = Connect(
677 GetFullURL(kCloseWithCodeAndReasonServerURL), &result, std::string());
678 ASSERT_TRUE(ws);
679 ASSERT_EQ(PP_OK, result);
680 // Text messsage "1000 bye" requests the server to initiate closing handshake
681 // with code being 1000 and reason being "bye".
682 PP_Var close_request_var = CreateVarString("1000 bye");
683 result = websocket_interface_->SendMessage(ws, close_request_var);
684 ReleaseVar(close_request_var);
685 callback.WaitForResult(websocket_interface_->ReceiveMessage(
686 ws, &receive_message_var,
687 callback.GetCallback().pp_completion_callback()));
688 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
689 core_interface_->ReleaseResource(ws);
691 ReleaseVar(reason);
692 ReleaseVar(url);
694 PASS();
697 std::string TestWebSocket::TestGetProtocol() {
698 const char* expected_protocols[] = {
699 "x-chat",
700 "hoehoe",
701 NULL
703 for (int i = 0; expected_protocols[i]; ++i) {
704 std::string url(GetFullURL(kProtocolTestServerURL));
705 url += expected_protocols[i];
706 int32_t result;
707 PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]);
708 ASSERT_TRUE(ws);
709 ASSERT_EQ(PP_OK, result);
711 PP_Var protocol = websocket_interface_->GetProtocol(ws);
712 ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i]));
714 ReleaseVar(protocol);
715 core_interface_->ReleaseResource(ws);
718 PASS();
721 std::string TestWebSocket::TestTextSendReceive() {
722 // Connect to test echo server.
723 int32_t connect_result;
724 PP_Resource ws =
725 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
726 ASSERT_TRUE(ws);
727 ASSERT_EQ(PP_OK, connect_result);
729 // Send 'hello pepper' text message.
730 const char* message = "hello pepper";
731 PP_Var message_var = CreateVarString(message);
732 int32_t result = websocket_interface_->SendMessage(ws, message_var);
733 ReleaseVar(message_var);
734 ASSERT_EQ(PP_OK, result);
736 // Receive echoed 'hello pepper'.
737 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
738 PP_Var received_message;
739 callback.WaitForResult(websocket_interface_->ReceiveMessage(
740 ws, &received_message, callback.GetCallback().pp_completion_callback()));
741 ASSERT_EQ(PP_OK, callback.result());
742 ASSERT_TRUE(AreEqualWithString(received_message, message));
743 ReleaseVar(received_message);
744 core_interface_->ReleaseResource(ws);
746 PASS();
749 std::string TestWebSocket::TestBinarySendReceive() {
750 // Connect to test echo server.
751 int32_t connect_result;
752 PP_Resource ws =
753 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
754 ASSERT_TRUE(ws);
755 ASSERT_EQ(PP_OK, connect_result);
757 // Send binary message.
758 std::vector<uint8_t> binary(256);
759 for (uint32_t i = 0; i < binary.size(); ++i)
760 binary[i] = i;
761 PP_Var message_var = CreateVarBinary(binary);
762 int32_t result = websocket_interface_->SendMessage(ws, message_var);
763 ReleaseVar(message_var);
764 ASSERT_EQ(PP_OK, result);
766 // Receive echoed binary.
767 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
768 PP_Var received_message;
769 callback.WaitForResult(websocket_interface_->ReceiveMessage(
770 ws, &received_message, callback.GetCallback().pp_completion_callback()));
771 ASSERT_EQ(PP_OK, callback.result());
772 ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
773 ReleaseVar(received_message);
774 core_interface_->ReleaseResource(ws);
776 PASS();
779 std::string TestWebSocket::TestStressedSendReceive() {
780 // Connect to test echo server.
781 int32_t connect_result;
782 PP_Resource ws =
783 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
784 ASSERT_TRUE(ws);
785 ASSERT_EQ(PP_OK, connect_result);
787 // Prepare PP_Var objects to send.
788 const char* text = "hello pepper";
789 PP_Var text_var = CreateVarString(text);
790 std::vector<uint8_t> binary(256);
791 for (uint32_t i = 0; i < binary.size(); ++i)
792 binary[i] = i;
793 PP_Var binary_var = CreateVarBinary(binary);
794 // Prepare very large binary data over 64KiB. Object serializer in
795 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
796 // to SRPC. In case received data over 64KiB exists, a specific code handles
797 // this large data via asynchronous callback from main thread. This data
798 // intends to test the code.
799 std::vector<uint8_t> large_binary(65 * 1024);
800 for (uint32_t i = 0; i < large_binary.size(); ++i)
801 large_binary[i] = i & 0xff;
802 PP_Var large_binary_var = CreateVarBinary(large_binary);
804 // Send many messages.
805 int32_t result;
806 for (int i = 0; i < 256; ++i) {
807 result = websocket_interface_->SendMessage(ws, text_var);
808 ASSERT_EQ(PP_OK, result);
809 result = websocket_interface_->SendMessage(ws, binary_var);
810 ASSERT_EQ(PP_OK, result);
812 result = websocket_interface_->SendMessage(ws, large_binary_var);
813 ASSERT_EQ(PP_OK, result);
814 ReleaseVar(text_var);
815 ReleaseVar(binary_var);
816 ReleaseVar(large_binary_var);
818 // Receive echoed data.
819 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
820 for (int i = 0; i <= 512; ++i) {
821 PP_Var received_message;
822 callback.WaitForResult(websocket_interface_->ReceiveMessage(
823 ws, &received_message,
824 callback.GetCallback().pp_completion_callback()));
825 ASSERT_EQ(PP_OK, callback.result());
826 if (i == 512) {
827 ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary));
828 } else if (i & 1) {
829 ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
830 } else {
831 ASSERT_TRUE(AreEqualWithString(received_message, text));
833 ReleaseVar(received_message);
835 core_interface_->ReleaseResource(ws);
837 PASS();
840 std::string TestWebSocket::TestBufferedAmount() {
841 // Connect to test echo server.
842 int32_t connect_result;
843 PP_Resource ws =
844 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
845 ASSERT_TRUE(ws);
846 ASSERT_EQ(PP_OK, connect_result);
848 // Prepare a large message that is not aligned with the internal buffer
849 // sizes.
850 std::string message(8193, 'x');
851 PP_Var message_var = CreateVarString(message);
853 uint64_t buffered_amount = 0;
854 int32_t result;
855 for (int i = 0; i < 100; i++) {
856 result = websocket_interface_->SendMessage(ws, message_var);
857 ASSERT_EQ(PP_OK, result);
858 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
859 // Buffered amount size 262144 is too big for the internal buffer size.
860 if (buffered_amount > 262144)
861 break;
864 // Close connection.
865 std::string reason_str = "close while busy";
866 PP_Var reason = CreateVarString(reason_str.c_str());
867 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
868 result = websocket_interface_->Close(
869 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
870 callback.GetCallback().pp_completion_callback());
871 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
872 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING,
873 websocket_interface_->GetReadyState(ws));
875 callback.WaitForResult(result);
876 ASSERT_EQ(PP_OK, callback.result());
877 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED,
878 websocket_interface_->GetReadyState(ws));
880 uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws);
882 // After connection closure, all sending requests fail and just increase
883 // the bufferedAmount property.
884 PP_Var empty_string = CreateVarString(std::string());
885 result = websocket_interface_->SendMessage(ws, empty_string);
886 ASSERT_EQ(PP_ERROR_FAILED, result);
887 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
888 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
889 base_buffered_amount = buffered_amount;
891 result = websocket_interface_->SendMessage(ws, reason);
892 ASSERT_EQ(PP_ERROR_FAILED, result);
893 buffered_amount = websocket_interface_->GetBufferedAmount(ws);
894 uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length();
895 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
897 ReleaseVar(message_var);
898 ReleaseVar(reason);
899 ReleaseVar(empty_string);
900 core_interface_->ReleaseResource(ws);
902 PASS();
905 // Test abort behaviors where a WebSocket PP_Resource is released while each
906 // function is in-flight on the WebSocket PP_Resource.
907 std::string TestWebSocket::TestAbortCallsWithCallback() {
908 // Following tests make sure the behavior for functions which require a
909 // callback. The callback must get a PP_ERROR_ABORTED.
911 // Test the behavior for Connect().
912 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
913 ASSERT_TRUE(ws);
914 std::string url = GetFullURL(kEchoServerURL);
915 PP_Var url_var = CreateVarString(url);
916 TestCompletionCallback connect_callback(
917 instance_->pp_instance(), callback_type());
918 int32_t result = websocket_interface_->Connect(
919 ws, url_var, NULL, 0,
920 connect_callback.GetCallback().pp_completion_callback());
921 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
922 core_interface_->ReleaseResource(ws);
923 connect_callback.WaitForResult(result);
924 ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result());
926 // Test the behavior for Close().
927 ws = Connect(url, &result, std::string());
928 ASSERT_TRUE(ws);
929 ASSERT_EQ(PP_OK, result);
930 PP_Var reason_var = CreateVarString("abort");
931 TestCompletionCallback close_callback(
932 instance_->pp_instance(), callback_type());
933 result = websocket_interface_->Close(
934 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var,
935 close_callback.GetCallback().pp_completion_callback());
936 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
937 core_interface_->ReleaseResource(ws);
938 close_callback.WaitForResult(result);
939 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
940 ReleaseVar(reason_var);
942 // Test the behavior for ReceiveMessage().
943 // Make sure the simplest case to wait for data which never arrives, here.
944 ws = Connect(url, &result, std::string());
945 ASSERT_TRUE(ws);
946 ASSERT_EQ(PP_OK, result);
947 PP_Var receive_var;
948 TestCompletionCallback receive_callback(
949 instance_->pp_instance(), callback_type());
950 result = websocket_interface_->ReceiveMessage(
951 ws, &receive_var,
952 receive_callback.GetCallback().pp_completion_callback());
953 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
954 core_interface_->ReleaseResource(ws);
955 receive_callback.WaitForResult(result);
956 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
958 // Release the resource in the aborting receive completion callback which is
959 // introduced by calling Close().
960 ws = Connect(url, &result, std::string());
961 ASSERT_TRUE(ws);
962 ASSERT_EQ(PP_OK, result);
963 result = websocket_interface_->ReceiveMessage(
964 ws, &receive_var,
965 receive_callback.GetCallback().pp_completion_callback());
966 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
967 ReleaseResourceDelegate receive_delegate(core_interface_, ws);
968 receive_callback.SetDelegate(&receive_delegate);
969 result = websocket_interface_->Close(
970 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
971 close_callback.GetCallback().pp_completion_callback());
972 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
973 receive_callback.WaitForResult(result);
974 CHECK_CALLBACK_BEHAVIOR(receive_callback);
975 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
976 close_callback.WaitForResult(result);
977 CHECK_CALLBACK_BEHAVIOR(close_callback);
978 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
980 ReleaseVar(url_var);
982 PASS();
985 std::string TestWebSocket::TestAbortSendMessageCall() {
986 // Test the behavior for SendMessage().
987 // This function doesn't require a callback, but operation will be done
988 // asynchronously in WebKit and browser process.
989 std::vector<uint8_t> large_binary(65 * 1024);
990 PP_Var large_var = CreateVarBinary(large_binary);
992 int32_t result;
993 std::string url = GetFullURL(kEchoServerURL);
994 PP_Resource ws = Connect(url, &result, std::string());
995 ASSERT_TRUE(ws);
996 ASSERT_EQ(PP_OK, result);
997 result = websocket_interface_->SendMessage(ws, large_var);
998 ASSERT_EQ(PP_OK, result);
999 core_interface_->ReleaseResource(ws);
1000 ReleaseVar(large_var);
1002 PASS();
1005 std::string TestWebSocket::TestAbortCloseCall() {
1006 // Release the resource in the close completion callback.
1007 int32_t result;
1008 std::string url = GetFullURL(kEchoServerURL);
1009 PP_Resource ws = Connect(url, &result, std::string());
1010 ASSERT_TRUE(ws);
1011 ASSERT_EQ(PP_OK, result);
1012 TestCompletionCallback close_callback(
1013 instance_->pp_instance(), callback_type());
1014 result = websocket_interface_->Close(
1015 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
1016 close_callback.GetCallback().pp_completion_callback());
1017 ReleaseResourceDelegate close_delegate(core_interface_, ws);
1018 close_callback.SetDelegate(&close_delegate);
1019 close_callback.WaitForResult(result);
1020 CHECK_CALLBACK_BEHAVIOR(close_callback);
1021 ASSERT_EQ(PP_OK, close_callback.result());
1023 PASS();
1026 std::string TestWebSocket::TestAbortReceiveMessageCall() {
1027 // Test the behavior where receive process might be in-flight.
1028 std::vector<uint8_t> large_binary(65 * 1024);
1029 PP_Var large_var = CreateVarBinary(large_binary);
1030 const char* text = "yukarin";
1031 PP_Var text_var = CreateVarString(text);
1033 std::string url = GetFullURL(kEchoServerURL);
1034 int32_t result;
1035 PP_Resource ws;
1037 // Each trial sends |trial_count| + 1 messages and receives just |trial|
1038 // number of message(s) before releasing the WebSocket. The WebSocket is
1039 // released while the next message is going to be received.
1040 const int trial_count = 8;
1041 for (int trial = 1; trial <= trial_count; trial++) {
1042 ws = Connect(url, &result, std::string());
1043 ASSERT_TRUE(ws);
1044 ASSERT_EQ(PP_OK, result);
1045 for (int i = 0; i <= trial_count; ++i) {
1046 result = websocket_interface_->SendMessage(ws, text_var);
1047 ASSERT_EQ(PP_OK, result);
1049 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1050 PP_Var var;
1051 for (int i = 0; i < trial; ++i) {
1052 callback.WaitForResult(websocket_interface_->ReceiveMessage(
1053 ws, &var, callback.GetCallback().pp_completion_callback()));
1054 ASSERT_EQ(PP_OK, callback.result());
1055 ASSERT_TRUE(AreEqualWithString(var, text));
1056 ReleaseVar(var);
1058 result = websocket_interface_->ReceiveMessage(
1059 ws, &var, callback.GetCallback().pp_completion_callback());
1060 core_interface_->ReleaseResource(ws);
1061 if (result != PP_OK) {
1062 callback.WaitForResult(result);
1063 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1066 // Same test, but the last receiving message is large message over 64KiB.
1067 for (int trial = 1; trial <= trial_count; trial++) {
1068 ws = Connect(url, &result, std::string());
1069 ASSERT_TRUE(ws);
1070 ASSERT_EQ(PP_OK, result);
1071 for (int i = 0; i <= trial_count; ++i) {
1072 if (i == trial)
1073 result = websocket_interface_->SendMessage(ws, large_var);
1074 else
1075 result = websocket_interface_->SendMessage(ws, text_var);
1076 ASSERT_EQ(PP_OK, result);
1078 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1079 PP_Var var;
1080 for (int i = 0; i < trial; ++i) {
1081 callback.WaitForResult(websocket_interface_->ReceiveMessage(
1082 ws, &var, callback.GetCallback().pp_completion_callback()));
1083 ASSERT_EQ(PP_OK, callback.result());
1084 ASSERT_TRUE(AreEqualWithString(var, text));
1085 ReleaseVar(var);
1087 result = websocket_interface_->ReceiveMessage(
1088 ws, &var, callback.GetCallback().pp_completion_callback());
1089 core_interface_->ReleaseResource(ws);
1090 if (result != PP_OK) {
1091 callback.WaitForResult(result);
1092 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1096 ReleaseVar(large_var);
1097 ReleaseVar(text_var);
1099 PASS();
1102 std::string TestWebSocket::TestCcInterfaces() {
1103 // C++ bindings is simple straightforward, then just verifies interfaces work
1104 // as a interface bridge fine.
1105 pp::WebSocket ws(instance_);
1107 // Check uninitialized properties access.
1108 ASSERT_EQ(0, ws.GetBufferedAmount());
1109 ASSERT_EQ(0, ws.GetCloseCode());
1110 ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), std::string()));
1111 ASSERT_EQ(false, ws.GetCloseWasClean());
1112 ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), std::string()));
1113 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1114 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState());
1115 ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), std::string()));
1117 // Check communication interfaces (connect, send, receive, and close).
1118 TestCompletionCallback connect_callback(
1119 instance_->pp_instance(), callback_type());
1120 connect_callback.WaitForResult(ws.Connect(
1121 pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U,
1122 connect_callback.GetCallback()));
1123 CHECK_CALLBACK_BEHAVIOR(connect_callback);
1124 ASSERT_EQ(PP_OK, connect_callback.result());
1126 std::string text_message("hello C++");
1127 int32_t result = ws.SendMessage(pp::Var(text_message));
1128 ASSERT_EQ(PP_OK, result);
1130 std::vector<uint8_t> binary(256);
1131 for (uint32_t i = 0; i < binary.size(); ++i)
1132 binary[i] = i;
1133 result = ws.SendMessage(
1134 pp::Var(pp::PASS_REF, CreateVarBinary(binary)));
1135 ASSERT_EQ(PP_OK, result);
1137 pp::Var text_receive_var;
1138 TestCompletionCallback text_receive_callback(
1139 instance_->pp_instance(), callback_type());
1140 text_receive_callback.WaitForResult(
1141 ws.ReceiveMessage(&text_receive_var,
1142 text_receive_callback.GetCallback()));
1143 ASSERT_EQ(PP_OK, text_receive_callback.result());
1144 ASSERT_TRUE(
1145 AreEqualWithString(text_receive_var.pp_var(), text_message.c_str()));
1147 pp::Var binary_receive_var;
1148 TestCompletionCallback binary_receive_callback(
1149 instance_->pp_instance(), callback_type());
1150 binary_receive_callback.WaitForResult(
1151 ws.ReceiveMessage(&binary_receive_var,
1152 binary_receive_callback.GetCallback()));
1153 ASSERT_EQ(PP_OK, binary_receive_callback.result());
1154 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary));
1156 TestCompletionCallback close_callback(
1157 instance_->pp_instance(), callback_type());
1158 std::string reason("bye");
1159 close_callback.WaitForResult(ws.Close(
1160 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason),
1161 close_callback.GetCallback()));
1162 CHECK_CALLBACK_BEHAVIOR(close_callback);
1163 ASSERT_EQ(PP_OK, close_callback.result());
1165 // Check initialized properties access.
1166 ASSERT_EQ(0, ws.GetBufferedAmount());
1167 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode());
1168 ASSERT_TRUE(
1169 AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str()));
1170 ASSERT_EQ(true, ws.GetCloseWasClean());
1171 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1172 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState());
1173 ASSERT_TRUE(AreEqualWithString(
1174 ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str()));
1176 PASS();
1179 std::string TestWebSocket::TestUtilityInvalidConnect() {
1180 const pp::Var protocols[] = { pp::Var() };
1182 TestWebSocketAPI websocket(instance_);
1183 int32_t result = websocket.Connect(pp::Var(), protocols, 1U);
1184 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1185 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1187 result = websocket.Connect(pp::Var(), protocols, 1U);
1188 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1189 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1191 for (int i = 0; kInvalidURLs[i]; ++i) {
1192 TestWebSocketAPI ws(instance_);
1193 result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1194 if (result == PP_OK_COMPLETIONPENDING) {
1195 ws.WaitForClosed();
1196 const std::vector<WebSocketEvent>& events = ws.GetSeenEvents();
1197 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1198 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1199 ASSERT_EQ(2U, ws.GetSeenEvents().size());
1200 } else {
1201 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1202 ASSERT_EQ(0U, ws.GetSeenEvents().size());
1206 PASS();
1209 std::string TestWebSocket::TestUtilityProtocols() {
1210 const pp::Var bad_protocols[] = {
1211 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1212 const pp::Var good_protocols[] = {
1213 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1216 TestWebSocketAPI websocket(instance_);
1217 int32_t result = websocket.Connect(
1218 pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U);
1219 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1220 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1224 TestWebSocketAPI websocket(instance_);
1225 int32_t result = websocket.Connect(
1226 pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U);
1227 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1228 websocket.WaitForConnected();
1229 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1230 // Protocol arguments are valid, but this test run without a WebSocket
1231 // server. As a result, OnError() and OnClose() are invoked because of
1232 // a connection establishment failure.
1233 ASSERT_EQ(2U, events.size());
1234 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1235 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1236 ASSERT_FALSE(events[1].was_clean);
1239 PASS();
1242 std::string TestWebSocket::TestUtilityGetURL() {
1243 const pp::Var protocols[] = { pp::Var() };
1245 for (int i = 0; kInvalidURLs[i]; ++i) {
1246 TestWebSocketAPI websocket(instance_);
1247 int32_t result = websocket.Connect(
1248 pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1249 if (result == PP_OK_COMPLETIONPENDING) {
1250 websocket.WaitForClosed();
1251 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1252 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1253 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1254 ASSERT_EQ(2U, events.size());
1255 } else {
1256 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1257 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1259 pp::Var url = websocket.GetURL();
1260 ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i]));
1263 PASS();
1266 std::string TestWebSocket::TestUtilityValidConnect() {
1267 const pp::Var protocols[] = { pp::Var() };
1268 TestWebSocketAPI websocket(instance_);
1269 int32_t result = websocket.Connect(
1270 pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1271 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1272 websocket.WaitForConnected();
1273 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1274 ASSERT_EQ(1U, events.size());
1275 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1276 ASSERT_TRUE(
1277 AreEqualWithString(websocket.GetExtensions().pp_var(), std::string()));
1279 PASS();
1282 std::string TestWebSocket::TestUtilityInvalidClose() {
1283 const pp::Var reason = pp::Var(std::string("close for test"));
1285 // Close before connect.
1287 TestWebSocketAPI websocket(instance_);
1288 int32_t result = websocket.Close(
1289 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason);
1290 ASSERT_EQ(PP_ERROR_FAILED, result);
1291 ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1294 // Close with bad arguments.
1296 TestWebSocketAPI websocket(instance_);
1297 int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)),
1298 NULL, 0);
1299 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1300 websocket.WaitForConnected();
1301 result = websocket.Close(1U, reason);
1302 ASSERT_EQ(PP_ERROR_NOACCESS, result);
1303 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1304 ASSERT_EQ(1U, events.size());
1305 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1308 PASS();
1311 std::string TestWebSocket::TestUtilityValidClose() {
1312 std::string reason("close for test");
1313 pp::Var url = pp::Var(GetFullURL(kCloseServerURL));
1315 // Close.
1317 TestWebSocketAPI websocket(instance_);
1318 int32_t result = websocket.Connect(url, NULL, 0U);
1319 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1320 websocket.WaitForConnected();
1321 result = websocket.Close(
1322 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1323 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1324 websocket.WaitForClosed();
1325 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1326 ASSERT_EQ(2U, events.size());
1327 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1328 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1329 ASSERT_TRUE(events[1].was_clean);
1330 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code);
1331 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str()));
1334 // Close in connecting.
1335 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1336 // successfully.
1338 TestWebSocketAPI websocket(instance_);
1339 int32_t result = websocket.Connect(url, NULL, 0U);
1340 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1341 result = websocket.Close(
1342 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1343 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1344 websocket.WaitForClosed();
1345 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1346 ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1347 int index = 0;
1348 if (events.size() == 3)
1349 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1350 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1351 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1352 ASSERT_FALSE(events[index].was_clean);
1355 // Close in closing.
1356 // The first close will be done successfully, then the second one failed with
1357 // with PP_ERROR_INPROGRESS immediately.
1359 TestWebSocketAPI websocket(instance_);
1360 int32_t result = websocket.Connect(url, NULL, 0U);
1361 result = websocket.Close(
1362 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1363 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1364 result = websocket.Close(
1365 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1366 ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1367 websocket.WaitForClosed();
1368 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1369 ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1370 int index = 0;
1371 if (events.size() == 3)
1372 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1373 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1374 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1375 ASSERT_FALSE(events[index].was_clean);
1378 PASS();
1381 std::string TestWebSocket::TestUtilityGetProtocol() {
1382 const std::string protocol("x-chat");
1383 const pp::Var protocols[] = { pp::Var(protocol) };
1384 std::string url(GetFullURL(kProtocolTestServerURL));
1385 url += protocol;
1386 TestWebSocketAPI websocket(instance_);
1387 int32_t result = websocket.Connect(pp::Var(url), protocols, 1U);
1388 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1389 websocket.WaitForReceived();
1390 ASSERT_TRUE(AreEqualWithString(
1391 websocket.GetProtocol().pp_var(), protocol.c_str()));
1392 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1393 // The server to which this test connect returns the decided protocol as a
1394 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1395 // after EVENT_OPEN event.
1396 ASSERT_EQ(2U, events.size());
1397 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1398 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1399 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str()));
1401 PASS();
1404 std::string TestWebSocket::TestUtilityTextSendReceive() {
1405 const pp::Var protocols[] = { pp::Var() };
1406 TestWebSocketAPI websocket(instance_);
1407 int32_t result =
1408 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1409 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1410 websocket.WaitForConnected();
1412 // Send 'hello pepper'.
1413 std::string message1("hello pepper");
1414 result = websocket.Send(pp::Var(std::string(message1)));
1415 ASSERT_EQ(PP_OK, result);
1417 // Receive echoed 'hello pepper'.
1418 websocket.WaitForReceived();
1420 // Send 'goodbye pepper'.
1421 std::string message2("goodbye pepper");
1422 result = websocket.Send(pp::Var(std::string(message2)));
1424 // Receive echoed 'goodbye pepper'.
1425 websocket.WaitForReceived();
1427 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1428 ASSERT_EQ(3U, events.size());
1429 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1430 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1431 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str()));
1432 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type);
1433 ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str()));
1435 PASS();
1438 std::string TestWebSocket::TestUtilityBinarySendReceive() {
1439 const pp::Var protocols[] = { pp::Var() };
1440 TestWebSocketAPI websocket(instance_);
1441 int32_t result =
1442 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1443 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1444 websocket.WaitForConnected();
1446 // Send binary message.
1447 uint32_t len = 256;
1448 std::vector<uint8_t> binary(len);
1449 for (uint32_t i = 0; i < len; ++i)
1450 binary[i] = i;
1451 pp::VarArrayBuffer message(len);
1452 uint8_t* var_data = static_cast<uint8_t*>(message.Map());
1453 std::copy(binary.begin(), binary.end(), var_data);
1454 result = websocket.Send(message);
1455 ASSERT_EQ(PP_OK, result);
1457 // Receive echoed binary message.
1458 websocket.WaitForReceived();
1460 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1461 ASSERT_EQ(2U, events.size());
1462 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1463 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1464 ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary));
1466 PASS();
1469 std::string TestWebSocket::TestUtilityBufferedAmount() {
1470 // Connect to test echo server.
1471 const pp::Var protocols[] = { pp::Var() };
1472 TestWebSocketAPI websocket(instance_);
1473 int32_t result =
1474 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1475 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1476 websocket.WaitForConnected();
1478 // Prepare a large message that is not aligned with the internal buffer
1479 // sizes.
1480 std::string message(8193, 'x');
1481 uint64_t buffered_amount = 0;
1482 uint32_t sent;
1483 for (sent = 0; sent < 100; sent++) {
1484 result = websocket.Send(pp::Var(message));
1485 ASSERT_EQ(PP_OK, result);
1486 buffered_amount = websocket.GetBufferedAmount();
1487 // Buffered amount size 262144 is too big for the internal buffer size.
1488 if (buffered_amount > 262144)
1489 break;
1492 // Close connection.
1493 std::string reason = "close while busy";
1494 result = websocket.Close(
1495 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1496 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState());
1497 websocket.WaitForClosed();
1498 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState());
1500 uint64_t base_buffered_amount = websocket.GetBufferedAmount();
1501 size_t events_on_closed = websocket.GetSeenEvents().size();
1503 // After connection closure, all sending requests fail and just increase
1504 // the bufferedAmount property.
1505 result = websocket.Send(pp::Var(std::string()));
1506 ASSERT_EQ(PP_ERROR_FAILED, result);
1507 buffered_amount = websocket.GetBufferedAmount();
1508 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
1509 base_buffered_amount = buffered_amount;
1511 result = websocket.Send(pp::Var(reason));
1512 ASSERT_EQ(PP_ERROR_FAILED, result);
1513 buffered_amount = websocket.GetBufferedAmount();
1514 uint64_t reason_frame_size = kMessageFrameOverhead + reason.length();
1515 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
1517 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1518 ASSERT_EQ(events_on_closed, events.size());
1519 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1520 size_t last_event = events_on_closed - 1;
1521 for (uint32_t i = 1; i < last_event; ++i) {
1522 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type);
1523 ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message));
1525 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type);
1526 ASSERT_TRUE(events[last_event].was_clean);
1528 PASS();