Chromium Code Reviews| Index: ppapi/tests/test_websocket.cc |
| diff --git a/ppapi/tests/test_websocket.cc b/ppapi/tests/test_websocket.cc |
| index c990113110e8f6e0a34fe63b6e7a98f17a466628..67511529303290902f25d410ae31894dd07d88e5 100644 |
| --- a/ppapi/tests/test_websocket.cc |
| +++ b/ppapi/tests/test_websocket.cc |
| @@ -13,6 +13,8 @@ |
| #include "ppapi/c/pp_completion_callback.h" |
| #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" |
| @@ -36,6 +38,117 @@ 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) |
|
dmichael (off chromium)
2011/12/15 17:50:54
style nit: We don't normally do the parameters thi
Takashi Toyoshima
2011/12/16 07:58:00
Done.
|
| + : 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 { |
|
dmichael (off chromium)
2011/12/15 17:50:54
I don't know how I feel about the "helper" namespa
Takashi Toyoshima
2011/12/16 07:58:00
Brett agreed with pp::helper namespace for helper
|
| + 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, |
|
dmichael (off chromium)
2011/12/15 17:50:54
style nit: I would put the WebSocketEvent creation
Takashi Toyoshima
2011/12/16 07:58:00
Done.
|
| + 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() { |
| @@ -62,6 +175,15 @@ void TestWebSocket::RunTests(const std::string& filter) { |
| RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter); |
| RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter); |
| RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, 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) { |
| @@ -414,3 +536,279 @@ std::string TestWebSocket::TestTextSendReceive() { |
| // TODO(toyoshim): Add tests for didReceiveMessageError(). |
| // TODO(toyoshim): Add other function tests. |
| + |
| +std::string TestWebSocket::TestCcInterfaces() { |
| + // C++ bindings is simple straightforward, then just verifies interfaces work |
|
dmichael (off chromium)
2011/12/15 17:50:54
nit: rephrase, maybe as:
The C++ bindings are stra
Takashi Toyoshima
2011/12/16 07:58:00
Thanks.
|
| + // as a interface bridge fine. |
| + pp::WebSocket_Dev ws(instance_); |
| + |
| + // Check uninitialized properties access. |
| + ASSERT_EQ(0, ws.GetBufferedAmount()); |
| + ASSERT_EQ(0, ws.GetCloseCode()); |
| + ASSERT_TRUE(AreEqual(ws.GetCloseReason().pp_var(), "")); |
| + ASSERT_EQ(false, ws.GetCloseWasClean()); |
| + ASSERT_TRUE(AreEqual(ws.GetExtensions().pp_var(), "")); |
| + ASSERT_TRUE(AreEqual(ws.GetProtocol().pp_var(), "")); |
| + ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID_DEV, ws.GetReadyState()); |
| + ASSERT_TRUE(AreEqual(ws.GetURL().pp_var(), "")); |
| + |
| + // 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); |
|
dmichael (off chromium)
2011/12/15 17:50:54
style nit: I'd break the line elsewhere, maybe aft
Takashi Toyoshima
2011/12/16 07:58:00
Thanks.
I break it after ws.Connect( because the c
|
| + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
| + result = connect_callback.WaitForResult(); |
| + ASSERT_EQ(PP_OK, result); |
| + |
| + std::string message("hello C++"); |
| + result = ws.SendMessage(pp::Var(message)); |
| + ASSERT_EQ(PP_OK, result); |
| + |
| + pp::Var receive_var; |
| + TestCompletionCallback receive_callback(instance_->pp_instance()); |
| + result = ws.ReceiveMessage(&receive_var, receive_callback); |
| + if (result == PP_OK_COMPLETIONPENDING) |
| + result = receive_callback.WaitForResult(); |
| + ASSERT_EQ(PP_OK, result); |
| + ASSERT_TRUE(AreEqual(receive_var.pp_var(), message.c_str())); |
| + |
| + TestCompletionCallback close_callback(instance_->pp_instance()); |
| + std::string reason("bye"); |
| + result = ws.Close(kCloseCodeNormalClosure, pp::Var(reason), close_callback); |
| + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
| + result = close_callback.WaitForResult(); |
| + ASSERT_EQ(PP_OK, result); |
| + |
| + // Check initialized properties access. |
| + ASSERT_EQ(0, ws.GetBufferedAmount()); |
| + ASSERT_EQ(kCloseCodeNormalClosure, ws.GetCloseCode()); |
| + ASSERT_TRUE(AreEqual(ws.GetCloseReason().pp_var(), reason.c_str())); |
| + ASSERT_EQ(true, ws.GetCloseWasClean()); |
| + ASSERT_TRUE(AreEqual(ws.GetExtensions().pp_var(), "")); |
| + ASSERT_TRUE(AreEqual(ws.GetProtocol().pp_var(), "")); |
| + ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED_DEV, ws.GetReadyState()); |
| + ASSERT_TRUE(AreEqual(ws.GetURL().pp_var(), kCloseServerURL)); |
| + |
| + 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(); |
| + ASSERT_EQ(2U, events.size()); |
| + ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); |
| + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); |
|
dmichael (off chromium)
2011/12/15 17:50:54
Can you add a comment to explain why you expect it
Takashi Toyoshima
2011/12/16 07:58:00
Done.
|
| + 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); |
| + |
|
dmichael (off chromium)
2011/12/15 17:50:54
Do you need to clean up by closing the socket?
Takashi Toyoshima
2011/12/16 07:58:00
In this test, I omit Close() because it's not veri
|
| + 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); |
| + } |
|
dmichael (off chromium)
2011/12/15 17:50:54
Ditto, do you need to clean up by really closing t
Takashi Toyoshima
2011/12/16 07:58:00
Also, I intend to omit it.
|
| + |
| + 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_EQ(2U, events.size()); |
| + ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); |
|
dmichael (off chromium)
2011/12/15 17:50:54
I think it's going to be possible when you impleme
Takashi Toyoshima
2011/12/16 07:58:00
Oh, I see.
Thank you for catching this.
|
| + ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); |
| + ASSERT_FALSE(events[1].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_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::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.WaitForConnected(); |
| + ASSERT_TRUE(AreEqual(websocket.GetProtocol().pp_var(), protocol.c_str())); |
| + 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::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(); |
| +} |