Index: Source/modules/websockets/WebSocketTest.cpp |
diff --git a/Source/modules/websockets/WebSocketTest.cpp b/Source/modules/websockets/WebSocketTest.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ecb48346160d7535955a15a3efde46449881ded7 |
--- /dev/null |
+++ b/Source/modules/websockets/WebSocketTest.cpp |
@@ -0,0 +1,816 @@ |
+// Copyright 2014 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 "config.h" |
+ |
+#include "modules/websockets/WebSocket.h" |
+ |
+#include "bindings/v8/ExceptionState.h" |
+#include "bindings/v8/V8Binding.h" |
+#include "core/dom/ExceptionCode.h" |
+#include "core/fileapi/Blob.h" |
+#include "core/frame/ConsoleTypes.h" |
+#include "core/testing/DummyPageHolder.h" |
+#include "wtf/ArrayBuffer.h" |
+#include "wtf/OwnPtr.h" |
+#include "wtf/Uint8Array.h" |
+#include "wtf/Vector.h" |
+#include "wtf/testing/WTFTestHelpers.h" |
+ |
+#include <gmock/gmock.h> |
+#include <gtest/gtest.h> |
+ |
+using testing::_; |
+using testing::AnyNumber; |
+using testing::InSequence; |
+using testing::Ref; |
+using testing::Return; |
+ |
+namespace WebCore { |
+ |
+namespace { |
+ |
+typedef testing::StrictMock<testing::MockFunction<void(int)> > Checkpoint; // NOLINT |
+ |
+class MockWebSocketChannel : public WebSocketChannel { |
+public: |
+ static PassRefPtrWillBeRawPtr<MockWebSocketChannel> create() |
+ { |
+ return adoptRefWillBeRefCountedGarbageCollected(new testing::StrictMock<MockWebSocketChannel>()); |
+ } |
+ |
+ virtual ~MockWebSocketChannel() |
+ { |
+ } |
+ |
+ MOCK_METHOD2(connect, bool(const KURL&, const String&)); |
+ MOCK_METHOD0(subprotocol, String()); |
+ MOCK_METHOD0(extensions, String()); |
+ MOCK_METHOD1(send, SendResult(const String&)); |
+ MOCK_METHOD3(send, SendResult(const ArrayBuffer&, unsigned, unsigned)); |
+ MOCK_METHOD1(send, SendResult(PassRefPtr<BlobDataHandle>)); |
+ MOCK_METHOD1(send, SendResult(PassOwnPtr<Vector<char> >)); |
+ MOCK_CONST_METHOD0(bufferedAmount, unsigned long()); |
+ MOCK_METHOD2(close, void(int, const String&)); |
+ MOCK_METHOD4(fail, void(const String&, MessageLevel, const String&, unsigned)); |
+ MOCK_METHOD0(disconnect, void()); |
+ MOCK_METHOD0(suspend, void()); |
+ MOCK_METHOD0(resume, void()); |
+ MOCK_METHOD0(stop, void()); |
+ |
+ MockWebSocketChannel() |
+ { |
+ } |
+}; |
+ |
+class WebSocketWithMockChannel : public WebSocket { |
haraken
2014/05/27 04:35:08
Add FINAL.
yhirano
2014/05/27 05:03:02
Done.
|
+public: |
+ static PassRefPtrWillBeRawPtr<WebSocketWithMockChannel> create(ExecutionContext* context) |
+ { |
+ RefPtrWillBeRawPtr<WebSocketWithMockChannel> websocket = adoptRefWillBeRefCountedGarbageCollected(new WebSocketWithMockChannel(context)); |
+ websocket->suspendIfNeeded(); |
+ return websocket; |
+ } |
+ |
+ MockWebSocketChannel* channel() { return m_channel.get(); } |
+ |
+ virtual PassRefPtrWillBeRawPtr<WebSocketChannel> createChannel(ExecutionContext*, WebSocketChannelClient*) OVERRIDE |
+ { |
+ ASSERT(!m_hasCreatedChannel); |
+ m_hasCreatedChannel = true; |
+ return m_channel; |
zerny-chromium
2014/05/27 08:26:28
Unfortunately this needs a .get() to satisfy the c
yhirano
2014/05/29 02:27:12
Done.
|
+ } |
+ |
+ void trace(Visitor* visitor) |
haraken
2014/05/27 04:35:08
You need to make this virtual. Also add OVERRIDE.
yhirano
2014/05/27 05:03:02
Done.
|
+ { |
+ WebSocket::trace(visitor); |
haraken
2014/05/27 04:35:08
Nit: Would you make this a tail call?
yhirano
2014/05/27 05:03:02
Done.
|
+ visitor->trace(m_channel); |
+ } |
+ |
+private: |
+ WebSocketWithMockChannel(ExecutionContext* context) |
+ : WebSocket(context), m_channel(MockWebSocketChannel::create()), m_hasCreatedChannel(false) { } |
+ |
+ RefPtrWillBeMember<MockWebSocketChannel> m_channel; |
+ bool m_hasCreatedChannel; |
+}; |
+ |
+class WebSocketTestBase { |
+public: |
+ WebSocketTestBase() |
+ : m_pageHolder(DummyPageHolder::create()) |
+ , m_websocket(WebSocketWithMockChannel::create(&m_pageHolder->document())) |
+ , m_channel(m_websocket->channel()) |
+ , m_executionScope(V8ExecutionScope::create(v8::Isolate::GetCurrent())) |
+ , m_constructionExceptionState(ExceptionState::ConstructionContext, "property", "interface", m_executionScope->scriptState()->context()->Global(), m_executionScope->isolate()) |
+ { |
+ } |
+ |
+ virtual ~WebSocketTestBase() |
+ { |
+ if (!m_websocket) |
+ return; |
+ // These statements are needed to clear WebSocket::m_channel to |
+ // avoid ASSERTION failure on ~WebSocket. |
+ ASSERT(m_channel); |
+ ::testing::Mock::VerifyAndClear(m_channel.get()); |
+ EXPECT_CALL(*m_channel, disconnect()).Times(AnyNumber()); |
+ |
+ m_websocket->didClose(0, WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, ""); |
+ } |
+ |
+ OwnPtr<DummyPageHolder> m_pageHolder; |
+ RefPtrWillBePersistent<WebSocketWithMockChannel> m_websocket; |
+ RefPtrWillBePersistent<MockWebSocketChannel> m_channel; |
+ OwnPtr<V8ExecutionScope> m_executionScope; |
+ ExceptionState m_constructionExceptionState; |
+}; |
+ |
+class WebSocketTest : public WebSocketTestBase, public ::testing::Test { |
+public: |
+}; |
+ |
+TEST_F(WebSocketTest, connectToBadURL) |
+{ |
+ m_websocket->connect("xxx", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The URL 'xxx' is invalid.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, connectToNonWsURL) |
+{ |
+ m_websocket->connect("http://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The URL's scheme must be either 'ws' or 'wss'. 'http' is not allowed.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, connectToURLHavingFragmentIdentifier) |
+{ |
+ m_websocket->connect("ws://example.com/#fragment", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The URL contains a fragment identifier ('fragment'). Fragment identifiers are not allowed in WebSocket URLs.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, invalidPort) |
+{ |
+ m_websocket->connect("ws://example.com:7", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SecurityError, exceptionState.code()); |
+ EXPECT_EQ("The port 7 is not allowed.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+// FIXME: Add a test for Content Security Policy. |
+ |
+TEST_F(WebSocketTest, invalidSubprotocols) |
+{ |
+ Vector<String> subprotocols; |
+ subprotocols.append("@subprotocol-|'\"x\x01\x02\x03x"); |
+ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ } |
+ |
+ m_websocket->connect("ws://example.com/", subprotocols, m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The subprotocol '@subprotocol-|'\"x\\u0001\\u0002\\u0003x' is invalid.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, channelConnectSuccess) |
+{ |
+ Vector<String> subprotocols; |
+ subprotocols.append("aa"); |
+ subprotocols.append("bb"); |
+ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/hoge"), String("aa, bb"))).WillOnce(Return(true)); |
+ } |
+ |
+ m_websocket->connect("ws://example.com/hoge", Vector<String>(subprotocols), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ EXPECT_EQ(KURL(KURL(), "ws://example.com/hoge"), m_websocket->url()); |
+} |
+ |
+TEST_F(WebSocketTest, channelConnectFail) |
+{ |
+ Vector<String> subprotocols; |
+ subprotocols.append("aa"); |
+ subprotocols.append("bb"); |
+ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String("aa, bb"))).WillOnce(Return(false)); |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ } |
+ |
+ m_websocket->connect("ws://example.com/", Vector<String>(subprotocols), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SecurityError, exceptionState.code()); |
+ EXPECT_EQ("An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, isValidSubprotocolString) |
+{ |
+ EXPECT_TRUE(WebSocket::isValidSubprotocolString("Helloworld!!")); |
+ EXPECT_FALSE(WebSocket::isValidSubprotocolString("Hello, world!!")); |
+ EXPECT_FALSE(WebSocket::isValidSubprotocolString(String())); |
+ EXPECT_FALSE(WebSocket::isValidSubprotocolString("")); |
+ |
+ const char validCharacters[] = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"; |
+ size_t length = strlen(validCharacters); |
+ for (size_t i = 0; i < length; ++i) { |
+ String s; |
+ s.append(static_cast<UChar>(validCharacters[i])); |
+ EXPECT_TRUE(WebSocket::isValidSubprotocolString(s)); |
+ } |
+ for (size_t i = 0; i < 256; ++i) { |
+ if (std::find(validCharacters, validCharacters + length, static_cast<char>(i)) != validCharacters + length) { |
+ continue; |
+ } |
+ String s; |
+ s.append(static_cast<UChar>(i)); |
+ EXPECT_FALSE(WebSocket::isValidSubprotocolString(s)); |
+ } |
+} |
+ |
+TEST_F(WebSocketTest, connectSuccess) |
+{ |
+ Vector<String> subprotocols; |
+ subprotocols.append("aa"); |
+ subprotocols.append("bb"); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String("aa, bb"))).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String("bb"))); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String("cc"))); |
+ } |
+ m_websocket->connect("ws://example.com/", subprotocols, m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ EXPECT_EQ("bb", m_websocket->protocol()); |
+ EXPECT_EQ("cc", m_websocket->extensions()); |
+} |
+ |
+TEST_F(WebSocketTest, didClose) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didClose(0, WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, ""); |
+ |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, maximumReasonSize) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, fail(_, _, _, _)); |
+ } |
+ String reason; |
+ for (size_t i = 0; i < 123; ++i) |
+ reason.append("a"); |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->close(1000, reason, m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, reasonSizeExceeding) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ } |
+ String reason; |
+ for (size_t i = 0; i < 124; ++i) |
+ reason.append("a"); |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->close(1000, reason, m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The message must not be greater than 123 bytes.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, closeWhenConnecting) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, fail(String("WebSocket is closed before the connection is established."), WarningMessageLevel, String(), 0)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->close(1000, "bye", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, close) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, close(3005, String("bye"))); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ m_websocket->close(3005, "bye", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, closeWithoutReason) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, close(3005, String())); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ m_websocket->close(3005, m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, closeWithoutCodeAndReason) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, close(-1, String())); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ m_websocket->close(m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, closeWhenClosing) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, close(-1, String())); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ m_websocket->close(m_constructionExceptionState); |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+ |
+ m_websocket->close(m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, closeWhenClosed) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, close(-1, String())); |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->didConnect(); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+ m_websocket->close(m_constructionExceptionState); |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+ |
+ m_websocket->didClose(0, WebSocketChannelClient::ClosingHandshakeComplete, 1000, String()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+ m_websocket->close(m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringWhenConnecting) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(InvalidStateError, exceptionState.code()); |
+ EXPECT_EQ("Still in CONNECTING state.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringWhenClosing) |
+{ |
+ Checkpoint checkpoint; |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, fail(_, _, _, _)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->close(m_constructionExceptionState); |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringWhenClosed) |
+{ |
+ Checkpoint checkpoint; |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ EXPECT_CALL(checkpoint, Call(1)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didClose(0, WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, ""); |
+ checkpoint.Call(1); |
+ |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringSuccess) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(String("hello"))).WillOnce(Return(WebSocketChannel::SendSuccess)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringFail) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(String("hello"))).WillOnce(Return(WebSocketChannel::SendFail)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendStringInvalidMessage) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(String("hello"))).WillOnce(Return(WebSocketChannel::InvalidMessage)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send("hello", m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The message contains invalid characters.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferWhenConnecting) |
+{ |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(InvalidStateError, exceptionState.code()); |
+ EXPECT_EQ("Still in CONNECTING state.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferWhenClosing) |
+{ |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, fail(_, _, _, _)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->close(m_constructionExceptionState); |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferWhenClosed) |
+{ |
+ Checkpoint checkpoint; |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, disconnect()); |
+ EXPECT_CALL(checkpoint, Call(1)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didClose(0, WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, ""); |
+ checkpoint.Call(1); |
+ |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferSuccess) |
+{ |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::SendSuccess)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferFail) |
+{ |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::SendFail)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+TEST_F(WebSocketTest, sendArrayBufferInvalidMessage) |
+{ |
+ RefPtr<ArrayBufferView> view = Uint8Array::create(8); |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, subprotocol()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, extensions()).WillOnce(Return(String())); |
+ EXPECT_CALL(*m_channel, send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::InvalidMessage)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ |
+ m_websocket->didConnect(); |
+ m_websocket->send(view->buffer().get(), m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(SyntaxError, exceptionState.code()); |
+ EXPECT_EQ("The message contains invalid characters.", exceptionState.message()); |
+ EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState()); |
+} |
+ |
+// FIXME: We should have Blob tests here. |
+// We can't create a Blob because the blob registration cannot be mocked yet. |
+ |
+// FIXME: We should add tests for bufferedAmount. |
+ |
+// FIXME: We should add tests for data receiving. |
+ |
+TEST_F(WebSocketTest, binaryType) |
+{ |
+ EXPECT_EQ("blob", m_websocket->binaryType()); |
+ |
+ m_websocket->setBinaryType("hoge"); |
+ |
+ EXPECT_EQ("blob", m_websocket->binaryType()); |
+ |
+ m_websocket->setBinaryType("arraybuffer"); |
+ |
+ EXPECT_EQ("arraybuffer", m_websocket->binaryType()); |
+ |
+ m_websocket->setBinaryType("fuga"); |
+ |
+ EXPECT_EQ("arraybuffer", m_websocket->binaryType()); |
+ |
+ m_websocket->setBinaryType("blob"); |
+ |
+ EXPECT_EQ("blob", m_websocket->binaryType()); |
+} |
+ |
+// FIXME: We should add tests for suspend / resume. |
+ |
+class WebSocketValidClosingCodeTest : public WebSocketTestBase, public ::testing::TestWithParam<unsigned short> { |
+public: |
+}; |
+ |
+TEST_P(WebSocketValidClosingCodeTest, test) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ EXPECT_CALL(*m_channel, fail(_, _, _, _)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->close(GetParam(), "bye", m_constructionExceptionState); |
+ |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState()); |
+} |
+ |
+INSTANTIATE_TEST_CASE_P(WebSocketValidClosingCode, WebSocketValidClosingCodeTest, ::testing::Values(1000, 3000, 3001, 4998, 4999)); |
+ |
+class WebSocketInvalidClosingCodeTest : public WebSocketTestBase, public ::testing::TestWithParam<unsigned short> { |
+public: |
+}; |
+ |
+TEST_P(WebSocketInvalidClosingCodeTest, test) |
+{ |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*m_channel, connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true)); |
+ } |
+ m_websocket->connect("ws://example.com/", Vector<String>(), m_constructionExceptionState); |
+ const ExceptionState& exceptionState = m_constructionExceptionState; |
+ EXPECT_FALSE(exceptionState.hadException()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+ |
+ m_websocket->close(GetParam(), "bye", m_constructionExceptionState); |
+ |
+ EXPECT_TRUE(exceptionState.hadException()); |
+ EXPECT_EQ(InvalidAccessError, exceptionState.code()); |
+ EXPECT_EQ(String::format("The code must be either 1000, or between 3000 and 4999. %d is neither.", GetParam()), exceptionState.message()); |
+ EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState()); |
+} |
+ |
+INSTANTIATE_TEST_CASE_P(WebSocketInvalidClosingCode, WebSocketInvalidClosingCodeTest, ::testing::Values(0, 1, 998, 999, 1001, 2999, 5000, 9999, 65535)); |
+ |
+} // namespace |
+ |
+} // namespace WebCore |