diff options
author | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-20 07:19:28 +0000 |
---|---|---|
committer | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-20 07:19:28 +0000 |
commit | b86d7e1e12289a3cb5d626a91b33321d520a6653 (patch) | |
tree | c028d0d4f36af4708d8c374c7b25694847c0f08e /ppapi | |
parent | 3408c3d3ba458b47624404fc6fece42fab4d5641 (diff) | |
download | chromium_src-b86d7e1e12289a3cb5d626a91b33321d520a6653.zip chromium_src-b86d7e1e12289a3cb5d626a91b33321d520a6653.tar.gz chromium_src-b86d7e1e12289a3cb5d626a91b33321d520a6653.tar.bz2 |
WebSocket Pepper API: C++ helper class implementation.
This class privide JS binding like API to Pepper C++ developers.
BUG=87310
TEST=ui_tests --gtest_filter='PPAPITest.Websocket_Helper*'
Review URL: http://codereview.chromium.org/8956008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115093 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/cpp/helper/dev/websocket_api_dev.cc | 120 | ||||
-rw-r--r-- | ppapi/cpp/helper/dev/websocket_api_dev.h | 130 | ||||
-rw-r--r-- | ppapi/ppapi_sources.gypi | 4 | ||||
-rw-r--r-- | ppapi/tests/test_websocket.cc | 370 | ||||
-rw-r--r-- | ppapi/tests/test_websocket.h | 9 |
5 files changed, 629 insertions, 4 deletions
diff --git a/ppapi/cpp/helper/dev/websocket_api_dev.cc b/ppapi/cpp/helper/dev/websocket_api_dev.cc new file mode 100644 index 0000000..7bbe232 --- /dev/null +++ b/ppapi/cpp/helper/dev/websocket_api_dev.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/cpp/helper/dev/websocket_api_dev.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_macros.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/dev/websocket_dev.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/module_impl.h" +#include "ppapi/cpp/var.h" + +namespace pp { + +namespace helper { + +class WebSocketAPI_Dev::Implement : public WebSocket_Dev { + public: + Implement(Instance* instance, WebSocketAPI_Dev* api) + : WebSocket_Dev(instance), + api_(api), + callback_factory_(PP_ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + } + + ~Implement() {} + + int32_t Connect(const Var& url, const Var protocols[], + uint32_t protocol_count) { + return WebSocket_Dev::Connect(url, protocols, protocol_count, + callback_factory_.NewOptionalCallback(&Implement::DidConnect)); + } + + int32_t Close(uint16_t code, const Var& reason) { + return WebSocket_Dev::Close(code, reason, + callback_factory_.NewOptionalCallback(&Implement::DidClose)); + } + + void Receive() { + WebSocket_Dev::ReceiveMessage(&receive_message_var_, + callback_factory_.NewCallback(&Implement::DidReceive)); + } + + void DidConnect(int32_t result) { + if (result == PP_OK) { + api_->OnOpen(); + Receive(); + } else if (result != PP_ERROR_ABORTED) { + DidClose(result); + } + } + + void DidReceive(int32_t result) { + if (result == PP_OK) { + api_->OnMessage(receive_message_var_); + Receive(); + } else if (result != PP_ERROR_ABORTED) { + DidClose(result); + } + } + + void DidClose(int32_t result) { + bool was_clean = GetCloseWasClean() && result == PP_OK; + if (!was_clean) + api_->OnError(); + api_->OnClose(was_clean, GetCloseCode(), GetCloseReason()); + } + + private: + WebSocketAPI_Dev* api_; + CompletionCallbackFactory<Implement> callback_factory_; + Var receive_message_var_; +}; + +WebSocketAPI_Dev::WebSocketAPI_Dev(Instance* instance) + : impl_(new Implement(instance, PP_ALLOW_THIS_IN_INITIALIZER_LIST(this))) { +} + +WebSocketAPI_Dev::~WebSocketAPI_Dev() { + delete impl_; +} + +int32_t WebSocketAPI_Dev::Connect(const Var& url, const Var protocols[], + uint32_t protocol_count) { + return impl_->Connect(url, protocols, protocol_count); +} + +int32_t WebSocketAPI_Dev::Close(uint16_t code, const Var& reason) { + return impl_->Close(code, reason); +} + +int32_t WebSocketAPI_Dev::Send(const Var& data) { + return impl_->SendMessage(data); +} + +uint64_t WebSocketAPI_Dev::GetBufferedAmount() { + return impl_->GetBufferedAmount(); +} + +Var WebSocketAPI_Dev::GetExtensions() { + return impl_->GetExtensions(); +} + +Var WebSocketAPI_Dev::GetProtocol() { + return impl_->GetProtocol(); +} + +PP_WebSocketReadyState_Dev WebSocketAPI_Dev::GetReadyState() { + return impl_->GetReadyState(); +} + +Var WebSocketAPI_Dev::GetURL() { + return impl_->GetURL(); +} + +} // namespace helper + +} // namespace pp diff --git a/ppapi/cpp/helper/dev/websocket_api_dev.h b/ppapi/cpp/helper/dev/websocket_api_dev.h new file mode 100644 index 0000000..3cbd792 --- /dev/null +++ b/ppapi/cpp/helper/dev/websocket_api_dev.h @@ -0,0 +1,130 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_CPP_HELPER_DEV_WEBSOCKET_API_DEV_H_ +#define PPAPI_CPP_HELPER_DEV_WEBSOCKET_API_DEV_H_ + +#include "ppapi/c/dev/ppb_websocket_dev.h" + +/// @file +/// This file defines the helper::WebSocketAPI_Dev interface. + +namespace pp { + +class CompletionCallback; +class Instance; +class Var; + +namespace helper { + +/// The <code>WebSocketAPI_Dev</code> class +class WebSocketAPI_Dev { + public: + /// Constructs a WebSocketAPI_Dev object. + WebSocketAPI_Dev(Instance* instance); + + /// Destructs a WebSocketAPI_Dev object. + virtual ~WebSocketAPI_Dev(); + + /// Connect() connects to the specified WebSocket server. Caller can call + /// this method at most once. + /// + /// @param[in] url A <code>Var</code> of string type representing a WebSocket + /// server URL. + /// @param[in] protocols A pointer to an array of string type + /// <code>Var</code> specifying sub-protocols. Each <code>Var</code> + /// represents one sub-protocol and its <code>PP_VarType</code> must be + /// <code>PP_VARTYPE_STRING</code>. This argument can be null only if + /// <code>protocol_count</code> is 0. + /// @param[in] protocol_count The number of sub-protocols in + /// <code>protocols</code>. + /// + /// @return An int32_t containing an error code from + /// <code>pp_errors.h</code>. + /// See also <code>pp::WebSocket_Dev::Connect</code>. + int32_t Connect(const Var& url, const Var protocols[], + uint32_t protocol_count); + + /// Close() closes the specified WebSocket connection by specifying + /// <code>code</code> and <code>reason</code>. + /// + /// @param[in] code The WebSocket close code. Ignored if it is 0. + /// @param[in] reason A <code>Var</code> of string type which represents the + /// WebSocket close reason. Ignored if it is undefined type. + /// + /// @return An int32_t containing an error code from + /// <code>pp_errors.h</code>. + /// See also <code>pp::WebSocket_Dev::Close</code>. + int32_t Close(uint16_t code, const Var& reason); + + /// Send() sends a message to the WebSocket server. + /// + /// @param[in] data A message to send. The message is copied to internal + /// buffer. So caller can free <code>data</code> safely after returning + /// from the function. + /// + /// @return An int32_t containing an error code from + /// <code>pp_errors.h</code>. + /// See also <code>pp::WebSocket_Dev::SendMessage</code>. + int32_t Send(const Var& data); + + /// GetBufferedAmount() returns the number of bytes of text and binary + /// messages that have been queued for the WebSocket connection to send but + /// have not been transmitted to the network yet. + /// + /// @return Returns the number of bytes. + uint64_t GetBufferedAmount(); + + /// GetExtensions() returns the extensions selected by the server for the + /// specified WebSocket connection. + /// + /// @return Returns a <code>Var</code> of string type. If called before the + /// connection is established, its data is empty string. + /// Currently its data is always an empty string. + Var GetExtensions(); + + /// GetProtocol() returns the sub-protocol chosen by the server for the + /// specified WebSocket connection. + /// + /// @return Returns a <code>Var</code> of string type. If called before the + /// connection is established, it contains the empty string. + Var GetProtocol(); + + /// GetReadyState() returns the ready state of the specified WebSocket + /// connection. + /// + /// @return Returns <code>PP_WEBSOCKETREADYSTATE_INVALID_DEV</code> if called + /// before connect() is called. + PP_WebSocketReadyState_Dev GetReadyState(); + + /// GetURL() returns the URL associated with specified WebSocket connection. + /// + /// @return Returns a <code>Var</code> of string type. If called before the + /// connection is established, it contains the empty string. + Var GetURL(); + + /// OnOpen() is invoked when the connection is established by Connect(). + virtual void OnOpen() = 0; + + /// OnMessage() is invoked when a message is received. + virtual void OnMessage(const Var& message) = 0; + + /// OnError() is invoked if the user agent was required to fail the WebSocket + /// connection or the WebSocket connection is closed with prejudice. + /// OnClose() always follows OnError(). + virtual void OnError() = 0; + + /// OnClose() is invoked when the connection is closed by errors or Close(). + virtual void OnClose(bool wasClean, uint16_t code, const Var& reason) = 0; + + private: + class Implement; + Implement* impl_; +}; + +} // namespace helper + +} // namespace pp + +#endif // PPAPI_CPP_HELPER_DEV_WEBSOCKET_API_DEV_H_ diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index 5ebe710..85d5ed9 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -249,6 +249,10 @@ 'cpp/trusted/file_chooser_trusted.h', 'cpp/trusted/file_io_trusted.cc', 'cpp/trusted/file_io_trusted.h', + + # Helper interfaces. + 'cpp/helper/dev/websocket_api_dev.cc', + 'cpp/helper/dev/websocket_api_dev.h', ], # # Common Testing source for trusted and untrusted (NaCl) pugins. diff --git a/ppapi/tests/test_websocket.cc b/ppapi/tests/test_websocket.cc index ae1db54..1c84ddb 100644 --- a/ppapi/tests/test_websocket.cc +++ b/ppapi/tests/test_websocket.cc @@ -15,11 +15,15 @@ #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_var.h" #include "ppapi/cpp/dev/websocket_dev.h" +#include "ppapi/cpp/helper/dev/websocket_api_dev.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/module.h" #include "ppapi/tests/test_utils.h" #include "ppapi/tests/testing_instance.h" +// These servers are provided by pywebsocket server side handlers in +// LayoutTests/http/tests/websocket/tests/hybi/*_wsh. +// pywebsocket server itself is launched in ppapi_ui_test.cc. const char kEchoServerURL[] = "ws://localhost:8880/websocket/tests/hybi/echo"; @@ -41,6 +45,119 @@ const char* const kInvalidURLs[] = { // See section 7.4.1. of RFC 6455. const uint16_t kCloseCodeNormalClosure = 1000U; +namespace { + +struct WebSocketEvent { + enum EventType { + EVENT_OPEN, + EVENT_MESSAGE, + EVENT_ERROR, + EVENT_CLOSE + }; + + WebSocketEvent(EventType type, + bool was_clean, + uint16_t close_code, + const pp::Var& var) + : event_type(type), + was_clean(was_clean), + close_code(close_code), + var(var) {} + EventType event_type; + bool was_clean; + uint16_t close_code; + pp::Var var; +}; + +class TestWebSocketAPI : public pp::helper::WebSocketAPI_Dev { + public: + explicit TestWebSocketAPI(pp::Instance* instance) + : pp::helper::WebSocketAPI_Dev(instance), + connected_(false), + received_(false), + closed_(false), + wait_for_connected_(false), + wait_for_received_(false), + wait_for_closed_(false), + instance_(instance->pp_instance()) {} + + virtual void OnOpen() { + events_.push_back( + WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var())); + connected_ = true; + if (wait_for_connected_) { + GetTestingInterface()->QuitMessageLoop(instance_); + wait_for_connected_ = false; + } + } + + virtual void OnMessage(const pp::Var &message) { + events_.push_back( + WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message)); + received_ = true; + if (wait_for_received_) { + GetTestingInterface()->QuitMessageLoop(instance_); + wait_for_received_ = false; + received_ = false; + } + } + + virtual void OnError() { + events_.push_back( + WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var())); + } + + virtual void OnClose( + bool was_clean, uint16_t code, const pp::Var& reason) { + events_.push_back( + WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason)); + connected_ = true; + closed_ = true; + if (wait_for_connected_ || wait_for_closed_) { + GetTestingInterface()->QuitMessageLoop(instance_); + wait_for_connected_ = false; + wait_for_closed_ = false; + } + } + + void WaitForConnected() { + if (!connected_) { + wait_for_connected_ = true; + GetTestingInterface()->RunMessageLoop(instance_); + } + } + + void WaitForReceived() { + if (!received_) { + wait_for_received_ = true; + GetTestingInterface()->RunMessageLoop(instance_); + } + } + + void WaitForClosed() { + if (!closed_) { + wait_for_closed_ = true; + GetTestingInterface()->RunMessageLoop(instance_); + } + } + + const std::vector<WebSocketEvent>& GetSeenEvents() const { + return events_; + } + + private: + std::vector<WebSocketEvent> events_; + bool connected_; + bool received_; + bool closed_; + bool wait_for_connected_; + bool wait_for_received_; + bool wait_for_closed_; + PP_Instance instance_; +}; + +} // namespace + REGISTER_TEST_CASE(WebSocket); bool TestWebSocket::Init() { @@ -69,6 +186,15 @@ void TestWebSocket::RunTests(const std::string& filter) { RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter); RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter); + + RUN_TEST_WITH_REFERENCE_CHECK(HelperInvalidConnect, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperProtocols, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperGetURL, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperValidConnect, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperInvalidClose, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperValidClose, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperGetProtocol, filter); + RUN_TEST_WITH_REFERENCE_CHECK(HelperTextSendReceive, filter); } PP_Var TestWebSocket::CreateVar(const char* string) { @@ -423,8 +549,8 @@ std::string TestWebSocket::TestTextSendReceive() { // TODO(toyoshim): Add other function tests. std::string TestWebSocket::TestCcInterfaces() { - // C++ bindings is simple straightforward, then just verifies interfaces work - // as a interface bridge fine. + // The C++ bindings is simple straightforward. This just verifies that the + // bindings work fine as an interface bridge. pp::WebSocket_Dev ws(instance_); // Check uninitialized properties access. @@ -439,8 +565,8 @@ std::string TestWebSocket::TestCcInterfaces() { // Check communication interfaces (connect, send, receive, and close). TestCompletionCallback connect_callback(instance_->pp_instance()); - int32_t result = ws.Connect(pp::Var(std::string(kCloseServerURL)), NULL, 0U, - connect_callback); + int32_t result = ws.Connect( + pp::Var(std::string(kCloseServerURL)), NULL, 0U, connect_callback); ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); result = connect_callback.WaitForResult(); ASSERT_EQ(PP_OK, result); @@ -476,3 +602,239 @@ std::string TestWebSocket::TestCcInterfaces() { PASS(); } + +std::string TestWebSocket::TestHelperInvalidConnect() { + const pp::Var protocols[] = { pp::Var() }; + + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(pp::Var(), protocols, 1U); + ASSERT_EQ(PP_ERROR_BADARGUMENT, result); + ASSERT_EQ(0U, websocket.GetSeenEvents().size()); + + result = websocket.Connect(pp::Var(), protocols, 1U); + ASSERT_EQ(PP_ERROR_INPROGRESS, result); + ASSERT_EQ(0U, websocket.GetSeenEvents().size()); + + for (int i = 0; kInvalidURLs[i]; ++i) { + TestWebSocketAPI ws(instance_); + result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); + ASSERT_EQ(PP_ERROR_BADARGUMENT, result); + ASSERT_EQ(0U, ws.GetSeenEvents().size()); + } + + PASS(); +} + +std::string TestWebSocket::TestHelperProtocols() { + const pp::Var bad_protocols[] = { + pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) }; + const pp::Var good_protocols[] = { + pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) }; + + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect( + pp::Var(std::string(kEchoServerURL)), bad_protocols, 2U); + ASSERT_EQ(PP_ERROR_BADARGUMENT, result); + ASSERT_EQ(0U, websocket.GetSeenEvents().size()); + } + + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect( + pp::Var(std::string(kEchoServerURL)), good_protocols, 2U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForConnected(); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + // Protocol arguments are valid, but this test run without a WebSocket + // server. As a result, OnError() and OnClose() are invoked because of + // a connection establishment failure. + ASSERT_EQ(2U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); + ASSERT_FALSE(events[1].was_clean); + } + + PASS(); +} + +std::string TestWebSocket::TestHelperGetURL() { + const pp::Var protocols[] = { pp::Var() }; + + for (int i = 0; kInvalidURLs[i]; ++i) { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect( + pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); + ASSERT_EQ(PP_ERROR_BADARGUMENT, result); + pp::Var url = websocket.GetURL(); + ASSERT_TRUE(AreEqual(url.pp_var(), kInvalidURLs[i])); + ASSERT_EQ(0U, websocket.GetSeenEvents().size()); + } + + PASS(); +} + +std::string TestWebSocket::TestHelperValidConnect() { + const pp::Var protocols[] = { pp::Var() }; + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect( + pp::Var(std::string(kEchoServerURL)), protocols, 0U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForConnected(); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_EQ(1U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); + + PASS(); +} + +std::string TestWebSocket::TestHelperInvalidClose() { + const pp::Var reason = pp::Var(std::string("close for test")); + + // Close before connect. + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Close(kCloseCodeNormalClosure, reason); + ASSERT_EQ(PP_ERROR_FAILED, result); + ASSERT_EQ(0U, websocket.GetSeenEvents().size()); + } + + // Close with bad arguments. + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(pp::Var(std::string(kEchoServerURL)), + NULL, 0); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForConnected(); + result = websocket.Close(1U, reason); + ASSERT_EQ(PP_ERROR_NOACCESS, result); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_EQ(1U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); + } + + PASS(); +} + +std::string TestWebSocket::TestHelperValidClose() { + std::string reason("close for test"); + pp::Var url = pp::Var(std::string(kCloseServerURL)); + + // Close. + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(url, NULL, 0U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForConnected(); + result = websocket.Close(kCloseCodeNormalClosure, pp::Var(reason)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForClosed(); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_EQ(2U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); + ASSERT_TRUE(events[1].was_clean); + ASSERT_EQ(kCloseCodeNormalClosure, events[1].close_code); + ASSERT_TRUE(AreEqual(events[1].var.pp_var(), reason.c_str())); + } + + // Close in connecting. + // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done + // successfully. + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(url, NULL, 0U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + result = websocket.Close(kCloseCodeNormalClosure, pp::Var(reason)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForClosed(); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_TRUE(events.size() == 2 || events.size() == 3); + int index = 0; + if (events.size() == 3) + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); + ASSERT_FALSE(events[index].was_clean); + } + + // Close in closing. + // The first close will be done successfully, then the second one failed with + // with PP_ERROR_INPROGRESS immediately. + { + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(url, NULL, 0U); + result = websocket.Close(kCloseCodeNormalClosure, pp::Var(reason)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + result = websocket.Close(kCloseCodeNormalClosure, pp::Var(reason)); + ASSERT_EQ(PP_ERROR_INPROGRESS, result); + websocket.WaitForClosed(); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_TRUE(events.size() == 2 || events.size() == 3) + int index = 0; + if (events.size() == 3) + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); + ASSERT_FALSE(events[index].was_clean); + } + + PASS(); +} + +std::string TestWebSocket::TestHelperGetProtocol() { + const std::string protocol("x-chat"); + const pp::Var protocols[] = { pp::Var(protocol) }; + std::string url(kProtocolTestServerURL); + url += protocol; + TestWebSocketAPI websocket(instance_); + int32_t result = websocket.Connect(pp::Var(url), protocols, 1U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForReceived(); + ASSERT_TRUE(AreEqual(websocket.GetProtocol().pp_var(), protocol.c_str())); + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + // The server to which this test connect returns the decided protocol as a + // text frame message. So the WebSocketEvent records EVENT_MESSAGE event + // after EVENT_OPEN event. + ASSERT_EQ(2U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); + ASSERT_TRUE(AreEqual(events[1].var.pp_var(), protocol.c_str())); + ASSERT_TRUE(events[1].was_clean); + + PASS(); +} + +std::string TestWebSocket::TestHelperTextSendReceive() { + const pp::Var protocols[] = { pp::Var() }; + TestWebSocketAPI websocket(instance_); + int32_t result = + websocket.Connect(pp::Var(std::string(kEchoServerURL)), protocols, 0U); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + websocket.WaitForConnected(); + + // Send 'hello pepper'. + std::string message1("hello pepper"); + result = websocket.Send(pp::Var(std::string(message1))); + ASSERT_EQ(PP_OK, result); + + // Receive echoed 'hello pepper'. + websocket.WaitForReceived(); + + // Send 'goodbye pepper'. + std::string message2("goodbye pepper"); + result = websocket.Send(pp::Var(std::string(message2))); + + // Receive echoed 'goodbye pepper'. + websocket.WaitForReceived(); + + const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); + ASSERT_EQ(3U, events.size()); + ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); + ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); + ASSERT_TRUE(AreEqual(events[1].var.pp_var(), message1.c_str())); + ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type); + ASSERT_TRUE(AreEqual(events[2].var.pp_var(), message2.c_str())); + + PASS(); +} diff --git a/ppapi/tests/test_websocket.h b/ppapi/tests/test_websocket.h index 4048458..3e8da51f 100644 --- a/ppapi/tests/test_websocket.h +++ b/ppapi/tests/test_websocket.h @@ -41,6 +41,15 @@ class TestWebSocket : public TestCase { std::string TestCcInterfaces(); + std::string TestHelperInvalidConnect(); + std::string TestHelperProtocols(); + std::string TestHelperGetURL(); + std::string TestHelperValidConnect(); + std::string TestHelperInvalidClose(); + std::string TestHelperValidClose(); + std::string TestHelperGetProtocol(); + std::string TestHelperTextSendReceive(); + // Used by the tests that access the C API directly. const PPB_WebSocket_Dev* websocket_interface_; const PPB_Var* var_interface_; |