devtools_remote_listen_socket_unittest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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 "chrome/browser/debugger/devtools_remote_listen_socket_unittest.h" 6 7#include <fcntl.h> 8#if defined(OS_POSIX) 9#include <netinet/in.h> 10#endif 11 12#include "base/eintr_wrapper.h" 13#include "base/test/test_timeouts.h" 14#include "base/threading/platform_thread.h" 15#include "net/base/net_util.h" 16#include "testing/platform_test.h" 17 18const int DevToolsRemoteListenSocketTester::kTestPort = 9999; 19 20static const int kReadBufSize = 1024; 21static const char* kChromeDevToolsHandshake = "ChromeDevToolsHandshake\r\n"; 22static const char* kSimpleMessagePart1 = 23 "Tool:V8Debugger\r\n" 24 "Destination:2\r"; 25static const char* kSimpleMessagePart2 = 26 "\n" 27 "Content-Length:0\r\n" 28 "\r\n"; 29static const char* kTwoMessages = 30 "Tool:DevToolsService\r\n" 31 "Content-Length:300\r\n" 32 "\r\n" 33 "00000000000000000000000000000000000000000000000000" 34 "00000000000000000000000000000000000000000000000000" 35 "00000000000000000000000000000000000000000000000000" 36 "00000000000000000000000000000000000000000000000000" 37 "00000000000000000000000000000000000000000000000000" 38 "00000000000000000000000000000000000000000000000000" 39 "Tool:V8Debugger\r\n" 40 "Destination:1\r\n" 41 "Content-Length:0\r\n" 42 "\r\n"; 43 44static const int kMaxQueueSize = 20; 45static const char* kLoopback = "127.0.0.1"; 46#if defined(OS_POSIX) 47static const char* kSemaphoreName = "chromium.listen_socket"; 48#endif 49 50 51ListenSocket* DevToolsRemoteListenSocketTester::DoListen() { 52 return DevToolsRemoteListenSocket::Listen(kLoopback, kTestPort, this); 53} 54 55void DevToolsRemoteListenSocketTester::SetUp() { 56#if defined(OS_WIN) 57 InitializeCriticalSection(&lock_); 58 semaphore_ = CreateSemaphore(NULL, 0, kMaxQueueSize, NULL); 59 server_ = NULL; 60 net::EnsureWinsockInit(); 61#elif defined(OS_POSIX) 62 ASSERT_EQ(0, pthread_mutex_init(&lock_, NULL)); 63 sem_unlink(kSemaphoreName); 64 semaphore_ = sem_open(kSemaphoreName, O_CREAT, 0, 0); 65 ASSERT_NE(SEM_FAILED, semaphore_); 66#endif 67 base::Thread::Options options; 68 options.message_loop_type = MessageLoop::TYPE_IO; 69 thread_.reset(new base::Thread("socketio_test")); 70 thread_->StartWithOptions(options); 71 loop_ = static_cast<MessageLoopForIO*>(thread_->message_loop()); 72 73 loop_->PostTask(FROM_HERE, NewRunnableMethod( 74 this, &DevToolsRemoteListenSocketTester::Listen)); 75 76 // verify Listen succeeded 77 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 78 ASSERT_FALSE(server_ == NULL); 79 ASSERT_EQ(ACTION_LISTEN, last_action_.type()); 80 81 // verify the connect/accept and setup test_socket_ 82 test_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 83 ASSERT_NE(INVALID_SOCKET, test_socket_); 84 struct sockaddr_in client; 85 client.sin_family = AF_INET; 86 client.sin_addr.s_addr = inet_addr(kLoopback); 87 client.sin_port = htons(kTestPort); 88 int ret = HANDLE_EINTR(connect(test_socket_, 89 reinterpret_cast<sockaddr*>(&client), 90 sizeof(client))); 91 ASSERT_NE(ret, SOCKET_ERROR); 92 93 net::SetNonBlocking(test_socket_); 94 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 95 ASSERT_EQ(ACTION_ACCEPT, last_action_.type()); 96} 97 98void DevToolsRemoteListenSocketTester::TearDown() { 99 // verify close 100#if defined(OS_WIN) 101 closesocket(test_socket_); 102#elif defined(OS_POSIX) 103 int ret = HANDLE_EINTR(close(test_socket_)); 104 ASSERT_EQ(ret, 0); 105#endif 106 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 107 ASSERT_EQ(ACTION_CLOSE, last_action_.type()); 108 109 loop_->PostTask(FROM_HERE, NewRunnableMethod( 110 this, &DevToolsRemoteListenSocketTester::Shutdown)); 111 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 112 ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type()); 113 114#if defined(OS_WIN) 115 CloseHandle(semaphore_); 116 semaphore_ = 0; 117 DeleteCriticalSection(&lock_); 118#elif defined(OS_POSIX) 119 ASSERT_EQ(0, pthread_mutex_lock(&lock_)); 120 semaphore_ = NULL; 121 ASSERT_EQ(0, pthread_mutex_unlock(&lock_)); 122 ASSERT_EQ(0, sem_unlink(kSemaphoreName)); 123 ASSERT_EQ(0, pthread_mutex_destroy(&lock_)); 124#endif 125 126 thread_.reset(); 127 loop_ = NULL; 128} 129 130void DevToolsRemoteListenSocketTester::ReportAction( 131 const ListenSocketTestAction& action) { 132#if defined(OS_WIN) 133 EnterCriticalSection(&lock_); 134 queue_.push_back(action); 135 LeaveCriticalSection(&lock_); 136 ReleaseSemaphore(semaphore_, 1, NULL); 137#elif defined(OS_POSIX) 138 ASSERT_EQ(0, pthread_mutex_lock(&lock_)); 139 queue_.push_back(action); 140 ASSERT_EQ(0, pthread_mutex_unlock(&lock_)); 141 ASSERT_EQ(0, sem_post(semaphore_)); 142#endif 143} 144 145bool DevToolsRemoteListenSocketTester::NextAction(int timeout) { 146#if defined(OS_WIN) 147 DWORD ret = ::WaitForSingleObject(semaphore_, timeout); 148 if (ret != WAIT_OBJECT_0) 149 return false; 150 EnterCriticalSection(&lock_); 151 if (queue_.size() == 0) { 152 LeaveCriticalSection(&lock_); 153 return false; 154 } 155 last_action_ = queue_.front(); 156 queue_.pop_front(); 157 LeaveCriticalSection(&lock_); 158 return true; 159#elif defined(OS_POSIX) 160 if (semaphore_ == SEM_FAILED) 161 return false; 162 while (true) { 163 int result = sem_trywait(semaphore_); 164 base::PlatformThread::Sleep(1); // 1MS sleep 165 timeout--; 166 if (timeout <= 0) 167 return false; 168 if (result == 0) 169 break; 170 } 171 pthread_mutex_lock(&lock_); 172 if (queue_.size() == 0) { 173 pthread_mutex_unlock(&lock_); 174 return false; 175 } 176 last_action_ = queue_.front(); 177 queue_.pop_front(); 178 pthread_mutex_unlock(&lock_); 179 return true; 180#endif 181} 182 183int DevToolsRemoteListenSocketTester::ClearTestSocket() { 184 char buf[kReadBufSize]; 185 int len_ret = 0; 186 int time_out = 0; 187 do { 188 int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0)); 189#if defined(OS_WIN) 190 if (len == SOCKET_ERROR) { 191 int err = WSAGetLastError(); 192 if (err == WSAEWOULDBLOCK) { 193#elif defined(OS_POSIX) 194 if (len == SOCKET_ERROR) { 195 if (errno == EWOULDBLOCK || errno == EAGAIN) { 196#endif 197 base::PlatformThread::Sleep(1); 198 time_out++; 199 if (time_out > 10) 200 break; 201 continue; // still trying 202 } 203 } else if (len == 0) { 204 // socket closed 205 break; 206 } else { 207 time_out = 0; 208 len_ret += len; 209 } 210 } while (true); 211 return len_ret; 212} 213 214void DevToolsRemoteListenSocketTester::Shutdown() { 215 server_->Release(); 216 server_ = NULL; 217 ReportAction(ListenSocketTestAction(ACTION_SHUTDOWN)); 218} 219 220void DevToolsRemoteListenSocketTester::Listen() { 221 server_ = DoListen(); 222 server_->AddRef(); 223 ReportAction(ListenSocketTestAction(ACTION_LISTEN)); 224} 225 226void DevToolsRemoteListenSocketTester::SendFromTester() { 227 connection_->Send(kChromeDevToolsHandshake); 228 ReportAction(ListenSocketTestAction(ACTION_SEND)); 229} 230 231void DevToolsRemoteListenSocketTester::OnAcceptConnection( 232 ListenSocket* connection) { 233 connection_ = connection; 234 ReportAction(ListenSocketTestAction(ACTION_ACCEPT)); 235} 236 237void DevToolsRemoteListenSocketTester::OnConnectionLost() { 238 connection_ = NULL; 239 ReportAction(ListenSocketTestAction(ACTION_CLOSE)); 240} 241 242void DevToolsRemoteListenSocketTester::HandleMessage( 243 const DevToolsRemoteMessage& message) { 244 ReportAction(ListenSocketTestAction(ACTION_READ_MESSAGE, message)); 245} 246 247bool DevToolsRemoteListenSocketTester::Send(SOCKET sock, 248 const std::string& str) { 249 int len = static_cast<int>(str.length()); 250 int send_len = HANDLE_EINTR(send(sock, str.data(), len, 0)); 251 if (send_len == SOCKET_ERROR) { 252 LOG(ERROR) << "send failed: " << errno; 253 return false; 254 } else if (send_len != len) { 255 return false; 256 } 257 return true; 258} 259 260void DevToolsRemoteListenSocketTester::TestClientSend() { 261 ASSERT_TRUE(Send(test_socket_, kChromeDevToolsHandshake)); 262 { 263 ASSERT_TRUE(Send(test_socket_, kSimpleMessagePart1)); 264 // sleep for 10ms to test message split between \r and \n 265 base::PlatformThread::Sleep(10); 266 ASSERT_TRUE(Send(test_socket_, kSimpleMessagePart2)); 267 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 268 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 269 const DevToolsRemoteMessage& message = last_action_.message(); 270 ASSERT_STREQ("V8Debugger", message.GetHeaderWithEmptyDefault( 271 DevToolsRemoteMessageHeaders::kTool).c_str()); 272 ASSERT_STREQ("2", message.GetHeaderWithEmptyDefault( 273 DevToolsRemoteMessageHeaders::kDestination).c_str()); 274 ASSERT_STREQ("0", message.GetHeaderWithEmptyDefault( 275 DevToolsRemoteMessageHeaders::kContentLength).c_str()); 276 ASSERT_EQ(0, static_cast<int>(message.content().size())); 277 } 278 ASSERT_TRUE(Send(test_socket_, kTwoMessages)); 279 { 280 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 281 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 282 const DevToolsRemoteMessage& message = last_action_.message(); 283 ASSERT_STREQ("DevToolsService", message.tool().c_str()); 284 ASSERT_STREQ("", message.destination().c_str()); 285 ASSERT_EQ(300, message.content_length()); 286 const std::string& content = message.content(); 287 ASSERT_EQ(300, static_cast<int>(content.size())); 288 for (int i = 0; i < 300; ++i) { 289 ASSERT_EQ('0', content[i]); 290 } 291 } 292 { 293 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 294 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 295 const DevToolsRemoteMessage& message = last_action_.message(); 296 ASSERT_STREQ("V8Debugger", message.GetHeaderWithEmptyDefault( 297 DevToolsRemoteMessageHeaders::kTool).c_str()); 298 ASSERT_STREQ("1", message.GetHeaderWithEmptyDefault( 299 DevToolsRemoteMessageHeaders::kDestination).c_str()); 300 ASSERT_STREQ("0", message.GetHeaderWithEmptyDefault( 301 DevToolsRemoteMessageHeaders::kContentLength).c_str()); 302 const std::string& content = message.content(); 303 ASSERT_EQ(0, static_cast<int>(content.size())); 304 } 305} 306 307void DevToolsRemoteListenSocketTester::TestServerSend() { 308 loop_->PostTask(FROM_HERE, NewRunnableMethod( 309 this, &DevToolsRemoteListenSocketTester::SendFromTester)); 310 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 311 ASSERT_EQ(ACTION_SEND, last_action_.type()); 312 // TODO(erikkay): Without this sleep, the recv seems to fail a small amount 313 // of the time. I could fix this by making the socket blocking, but then 314 // this test might hang in the case of errors. It would be nice to do 315 // something that felt more reliable here. 316 base::PlatformThread::Sleep(10); // sleep for 10ms 317 const int buf_len = 200; 318 char buf[buf_len+1]; 319 int recv_len = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0)); 320 ASSERT_NE(recv_len, SOCKET_ERROR); 321 buf[recv_len] = 0; 322 ASSERT_STREQ(buf, kChromeDevToolsHandshake); 323} 324 325 326class DevToolsRemoteListenSocketTest: public PlatformTest { 327 public: 328 DevToolsRemoteListenSocketTest() { 329 tester_ = NULL; 330 } 331 332 virtual void SetUp() { 333 PlatformTest::SetUp(); 334 tester_ = new DevToolsRemoteListenSocketTester(); 335 tester_->SetUp(); 336 } 337 338 virtual void TearDown() { 339 PlatformTest::TearDown(); 340 tester_->TearDown(); 341 tester_ = NULL; 342 } 343 344 scoped_refptr<DevToolsRemoteListenSocketTester> tester_; 345}; 346 347// This test is flaky; see comment in ::TestServerSend. 348TEST_F(DevToolsRemoteListenSocketTest, ServerSend) { 349 tester_->TestServerSend(); 350} 351 352TEST_F(DevToolsRemoteListenSocketTest, ClientSend) { 353 tester_->TestClientSend(); 354} 355