OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <string> |
| 6 #include <vector> |
| 7 |
| 8 #include "base/bind.h" |
| 9 #include "base/compiler_specific.h" |
| 10 #include "base/location.h" |
| 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/message_loop.h" |
| 13 #include "base/message_loop_proxy.h" |
| 14 #include "base/run_loop.h" |
| 15 #include "base/single_thread_task_runner.h" |
| 16 #include "base/stringprintf.h" |
| 17 #include "base/time.h" |
| 18 #include "chrome/test/chromedriver/net/websocket.h" |
| 19 #include "googleurl/src/gurl.h" |
| 20 #include "net/base/ip_endpoint.h" |
| 21 #include "net/base/net_errors.h" |
| 22 #include "net/base/tcp_listen_socket.h" |
| 23 #include "net/server/http_server.h" |
| 24 #include "net/server/http_server_request_info.h" |
| 25 #include "net/url_request/url_request_context_getter.h" |
| 26 #include "net/url_request/url_request_test_util.h" |
| 27 #include "testing/gtest/include/gtest/gtest.h" |
| 28 |
| 29 namespace { |
| 30 |
| 31 void OnConnectFinished(int* save_error, int error) { |
| 32 MessageLoop::current()->Quit(); |
| 33 *save_error = error; |
| 34 } |
| 35 |
| 36 class Listener : public WebSocketListener { |
| 37 public: |
| 38 explicit Listener(const std::vector<std::string>& messages) |
| 39 : messages_(messages) {} |
| 40 |
| 41 virtual ~Listener() { |
| 42 EXPECT_TRUE(messages_.empty()); |
| 43 } |
| 44 |
| 45 virtual void OnMessageReceived(const std::string& message) OVERRIDE { |
| 46 ASSERT_TRUE(messages_.size()); |
| 47 EXPECT_EQ(messages_[0], message); |
| 48 messages_.erase(messages_.begin()); |
| 49 if (messages_.empty()) |
| 50 MessageLoop::current()->Quit(); |
| 51 } |
| 52 |
| 53 virtual void OnClose() OVERRIDE { |
| 54 EXPECT_TRUE(false); |
| 55 } |
| 56 |
| 57 private: |
| 58 std::vector<std::string> messages_; |
| 59 }; |
| 60 |
| 61 class CloseListener : public WebSocketListener { |
| 62 public: |
| 63 explicit CloseListener(bool expect_close) : expect_close_(expect_close) {} |
| 64 |
| 65 virtual ~CloseListener() { |
| 66 EXPECT_FALSE(expect_close_); |
| 67 } |
| 68 |
| 69 virtual void OnMessageReceived(const std::string& message) OVERRIDE {} |
| 70 |
| 71 virtual void OnClose() OVERRIDE { |
| 72 EXPECT_TRUE(expect_close_); |
| 73 if (expect_close_) |
| 74 MessageLoop::current()->Quit(); |
| 75 expect_close_ = false; |
| 76 } |
| 77 |
| 78 private: |
| 79 bool expect_close_; |
| 80 }; |
| 81 |
| 82 class WebSocketTest : public testing::Test, |
| 83 public net::HttpServer::Delegate { |
| 84 public: |
| 85 enum WebSocketRequestResponse { |
| 86 kAccept = 0, |
| 87 kNotFound, |
| 88 kClose |
| 89 }; |
| 90 |
| 91 WebSocketTest() |
| 92 : ALLOW_THIS_IN_INITIALIZER_LIST(server_(CreateServer())), |
| 93 context_getter_( |
| 94 new net::TestURLRequestContextGetter(loop_.message_loop_proxy())), |
| 95 ws_request_response_(kAccept), |
| 96 close_on_message_(false), |
| 97 quit_on_close_(false) { |
| 98 net::IPEndPoint address; |
| 99 CHECK_EQ(net::OK, server_->GetLocalAddress(&address)); |
| 100 server_url_ = GURL(base::StringPrintf("ws://127.0.0.1:%d", address.port())); |
| 101 } |
| 102 |
| 103 // Overridden from net::HttpServer::Delegate: |
| 104 virtual void OnHttpRequest(int connection_id, |
| 105 const net::HttpServerRequestInfo& info) {} |
| 106 |
| 107 virtual void OnWebSocketRequest(int connection_id, |
| 108 const net::HttpServerRequestInfo& info) { |
| 109 switch (ws_request_response_) { |
| 110 case kAccept: |
| 111 server_->AcceptWebSocket(connection_id, info); |
| 112 break; |
| 113 case kNotFound: |
| 114 server_->Send404(connection_id); |
| 115 break; |
| 116 case kClose: |
| 117 // net::HttpServer doesn't allow us to close connection during callback. |
| 118 MessageLoop::current()->PostTask( |
| 119 FROM_HERE, |
| 120 base::Bind(&net::HttpServer::Close, server_, connection_id)); |
| 121 break; |
| 122 } |
| 123 } |
| 124 |
| 125 virtual void OnWebSocketMessage(int connection_id, |
| 126 const std::string& data) { |
| 127 if (close_on_message_) { |
| 128 // net::HttpServer doesn't allow us to close connection during callback. |
| 129 MessageLoop::current()->PostTask( |
| 130 FROM_HERE, |
| 131 base::Bind(&net::HttpServer::Close, server_, connection_id)); |
| 132 } else { |
| 133 server_->SendOverWebSocket(connection_id, data); |
| 134 } |
| 135 } |
| 136 |
| 137 virtual void OnClose(int connection_id) { |
| 138 if (quit_on_close_) |
| 139 MessageLoop::current()->Quit(); |
| 140 } |
| 141 |
| 142 protected: |
| 143 net::HttpServer* CreateServer() { |
| 144 net::TCPListenSocketFactory factory("127.0.0.1", 0); |
| 145 return new net::HttpServer(factory, this); |
| 146 } |
| 147 |
| 148 scoped_ptr<WebSocket> CreateWebSocket(const GURL& url, |
| 149 WebSocketListener* listener) { |
| 150 int error; |
| 151 scoped_ptr<WebSocket> sock(new WebSocket( |
| 152 context_getter_, url, listener)); |
| 153 sock->Connect(base::Bind(&OnConnectFinished, &error)); |
| 154 loop_.PostDelayedTask( |
| 155 FROM_HERE, MessageLoop::QuitWhenIdleClosure(), |
| 156 base::TimeDelta::FromSeconds(10)); |
| 157 base::RunLoop().Run(); |
| 158 if (error == net::OK) |
| 159 return sock.Pass(); |
| 160 return scoped_ptr<WebSocket>(); |
| 161 } |
| 162 |
| 163 scoped_ptr<WebSocket> CreateConnectedWebSocket(WebSocketListener* listener) { |
| 164 return CreateWebSocket(server_url_, listener); |
| 165 } |
| 166 |
| 167 void ReadSend(const std::vector<std::string>& messages) { |
| 168 Listener listener(messages); |
| 169 scoped_ptr<WebSocket> sock(CreateConnectedWebSocket(&listener)); |
| 170 ASSERT_TRUE(sock); |
| 171 for (size_t i = 0; i < messages.size(); ++i) { |
| 172 ASSERT_TRUE(sock->Send(messages[i])); |
| 173 } |
| 174 base::RunLoop run_loop; |
| 175 loop_.PostDelayedTask( |
| 176 FROM_HERE, run_loop.QuitClosure(), |
| 177 base::TimeDelta::FromSeconds(10)); |
| 178 run_loop.Run(); |
| 179 } |
| 180 |
| 181 MessageLoopForIO loop_; |
| 182 scoped_refptr<net::HttpServer> server_; |
| 183 scoped_refptr<net::URLRequestContextGetter> context_getter_; |
| 184 GURL server_url_; |
| 185 WebSocketRequestResponse ws_request_response_; |
| 186 bool close_on_message_; |
| 187 bool quit_on_close_; |
| 188 }; |
| 189 |
| 190 } // namespace |
| 191 |
| 192 TEST_F(WebSocketTest, CreateDestroy) { |
| 193 CloseListener listener(false); |
| 194 WebSocket sock(context_getter_, GURL("http://ok"), &listener); |
| 195 } |
| 196 |
| 197 TEST_F(WebSocketTest, Connect) { |
| 198 CloseListener listener(false); |
| 199 ASSERT_TRUE(CreateWebSocket(server_url_, &listener)); |
| 200 quit_on_close_ = true; |
| 201 base::RunLoop run_loop; |
| 202 loop_.PostDelayedTask( |
| 203 FROM_HERE, run_loop.QuitClosure(), |
| 204 base::TimeDelta::FromSeconds(10)); |
| 205 run_loop.Run(); |
| 206 } |
| 207 |
| 208 TEST_F(WebSocketTest, ConnectNoServer) { |
| 209 CloseListener listener(false); |
| 210 ASSERT_FALSE(CreateWebSocket(GURL("ws://127.0.0.1:33333"), NULL)); |
| 211 } |
| 212 |
| 213 TEST_F(WebSocketTest, Connect404) { |
| 214 ws_request_response_ = kNotFound; |
| 215 CloseListener listener(false); |
| 216 ASSERT_FALSE(CreateWebSocket(server_url_, NULL)); |
| 217 quit_on_close_ = true; |
| 218 base::RunLoop run_loop; |
| 219 loop_.PostDelayedTask( |
| 220 FROM_HERE, run_loop.QuitClosure(), |
| 221 base::TimeDelta::FromSeconds(10)); |
| 222 run_loop.Run(); |
| 223 } |
| 224 |
| 225 TEST_F(WebSocketTest, ConnectServerClosesConn) { |
| 226 ws_request_response_ = kClose; |
| 227 CloseListener listener(false); |
| 228 ASSERT_FALSE(CreateWebSocket(server_url_, &listener)); |
| 229 } |
| 230 |
| 231 TEST_F(WebSocketTest, CloseOnRead) { |
| 232 close_on_message_ = true; |
| 233 CloseListener listener(true); |
| 234 scoped_ptr<WebSocket> sock(CreateConnectedWebSocket(&listener)); |
| 235 ASSERT_TRUE(sock); |
| 236 ASSERT_TRUE(sock->Send("hi")); |
| 237 base::RunLoop run_loop; |
| 238 loop_.PostDelayedTask( |
| 239 FROM_HERE, run_loop.QuitClosure(), |
| 240 base::TimeDelta::FromSeconds(10)); |
| 241 run_loop.Run(); |
| 242 } |
| 243 |
| 244 TEST_F(WebSocketTest, CloseOnSend) { |
| 245 CloseListener listener(true); |
| 246 scoped_ptr<WebSocket> sock(CreateConnectedWebSocket(&listener)); |
| 247 ASSERT_TRUE(sock); |
| 248 server_ = NULL; |
| 249 loop_.PostTask( |
| 250 FROM_HERE, |
| 251 base::Bind(base::IgnoreResult(&WebSocket::Send), |
| 252 base::Unretained(sock.get()), "hi")); |
| 253 base::RunLoop run_loop; |
| 254 loop_.PostDelayedTask( |
| 255 FROM_HERE, run_loop.QuitClosure(), |
| 256 base::TimeDelta::FromSeconds(10)); |
| 257 run_loop.Run(); |
| 258 } |
| 259 |
| 260 TEST_F(WebSocketTest, ReadSend) { |
| 261 std::vector<std::string> messages; |
| 262 messages.push_back("hello"); |
| 263 ReadSend(messages); |
| 264 } |
| 265 |
| 266 TEST_F(WebSocketTest, ReadSendLarge) { |
| 267 std::vector<std::string> messages; |
| 268 // Sends/reads 200kb. For some reason pushing this above 240kb on my |
| 269 // machine results in receiving no data back from the http server. |
| 270 messages.push_back(std::string(200 << 10, 'a')); |
| 271 ReadSend(messages); |
| 272 } |
| 273 |
| 274 TEST_F(WebSocketTest, ReadSendMultiple) { |
| 275 std::vector<std::string> messages; |
| 276 messages.push_back("1"); |
| 277 messages.push_back("2"); |
| 278 messages.push_back("3"); |
| 279 ReadSend(messages); |
| 280 } |
OLD | NEW |