Chromium Code Reviews| Index: ipc/unix_domain_socket_util_unittest.cc |
| diff --git a/ipc/unix_domain_socket_util_unittest.cc b/ipc/unix_domain_socket_util_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..82aa03c69d445608042059dea2fd376cf61c0476 |
| --- /dev/null |
| +++ b/ipc/unix_domain_socket_util_unittest.cc |
| @@ -0,0 +1,156 @@ |
| +// Copyright 2013 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 <sys/socket.h> |
| + |
| +#include "base/bind.h" |
| +#include "base/file_util.h" |
| +#include "base/files/file_path.h" |
| +#include "base/synchronization/waitable_event.h" |
| +#include "base/threading/thread.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "ipc/unix_domain_socket_util.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace { |
| + |
| +class SocketAcceptor : public MessageLoopForIO::Watcher { |
| + public: |
| + SocketAcceptor(int fd, base::MessageLoopProxy* target_thread) |
| + : server_fd_(-1), |
| + started_watching_event_(false, false), |
| + accepted_event_(false, false) { |
| + target_thread->PostTask(FROM_HERE, |
| + base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd)); |
| + } |
| + |
| + virtual ~SocketAcceptor() { |
| + watcher_.StopWatchingFileDescriptor(); |
| + } |
| + |
| + int server_fd() { return server_fd_; } |
|
Mark Mentovai
2013/03/05 20:08:03
This method can be const, just for kicks.
jeremya
2013/03/06 05:03:18
Done.
|
| + |
| + void WaitUntilReady() { |
| + started_watching_event_.Wait(); |
| + } |
| + void WaitForAccept() { |
| + accepted_event_.Wait(); |
| + } |
| + |
| + private: |
| + void StartWatching(int fd) { |
| + MessageLoopForIO::current()->WatchFileDescriptor( |
| + fd, |
| + true, |
| + MessageLoopForIO::WATCH_READ, |
| + &watcher_, |
| + this); |
| + started_watching_event_.Signal(); |
| + } |
| + virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { |
| + ASSERT_EQ(-1, server_fd_); |
| + IPC::ServerAcceptConnection(fd, &server_fd_); |
| + watcher_.StopWatchingFileDescriptor(); |
| + accepted_event_.Signal(); |
| + } |
| + virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} |
| + |
| + int server_fd_; |
| + MessageLoopForIO::FileDescriptorWatcher watcher_; |
| + base::WaitableEvent started_watching_event_; |
| + base::WaitableEvent accepted_event_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SocketAcceptor); |
| +}; |
| + |
| +base::FilePath GetChannelDir() { |
| + return base::FilePath("/var/tmp"); |
| +} |
| + |
| +class TestUnixSocketConnection { |
| + public: |
| + TestUnixSocketConnection() |
| + : worker_("WorkerThread"), |
| + server_listen_fd_(-1), |
| + server_fd_(-1), |
| + client_fd_(-1), |
| + acceptor_(NULL) { |
| + socket_name_ = GetChannelDir().Append("TestSocket"); |
| + base::Thread::Options options; |
| + options.message_loop_type = MessageLoop::TYPE_IO; |
| + worker_.StartWithOptions(options); |
| + } |
| + |
| + bool CreateServerSocket() { |
| + IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_); |
| + if (server_listen_fd_ < 0) |
| + return false; |
| + // TODO stat socket_name and check that there's a socket present |
|
Mark Mentovai
2013/03/05 20:08:03
OK, so do this.
jeremya
2013/03/06 05:03:18
Done.
|
| + acceptor_ = new SocketAcceptor(server_listen_fd_, |
| + worker_.message_loop_proxy()); |
| + acceptor_->WaitUntilReady(); |
| + return true; |
| + } |
| + |
| + bool CreateClientSocket() { |
| + DCHECK(server_listen_fd_ >= 0); |
| + IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_); |
| + if (client_fd_ < 0) |
| + return false; |
| + acceptor_->WaitForAccept(); |
| + server_fd_ = acceptor_->server_fd(); |
| + return server_fd_ >= 0; |
| + } |
| + |
| + virtual ~TestUnixSocketConnection() { |
| + if (acceptor_) |
| + delete acceptor_; |
| + if (client_fd_) |
| + close(client_fd_); |
| + if (server_fd_) |
| + close(server_fd_); |
| + if (server_listen_fd_) { |
| + close(server_listen_fd_); |
| + unlink(socket_name_.value().c_str()); |
| + } |
| + } |
| + |
| + int client_fd() { return client_fd_; } |
| + int server_fd() { return server_fd_; } |
| + |
| + private: |
| + base::Thread worker_; |
| + base::FilePath socket_name_; |
| + int server_listen_fd_; |
| + int server_fd_; |
| + int client_fd_; |
| + SocketAcceptor* acceptor_; |
| +}; |
| + |
| +// Ensure that IPC::CreateServerUnixDomainSocket creates a socket that |
| +// IPC::CreateClientUnixDomainSocket can successfully connect to. |
| +TEST(UnixDomainSocketUtil, Connect) { |
| + TestUnixSocketConnection connection; |
| + ASSERT_TRUE(connection.CreateServerSocket()); |
| + ASSERT_TRUE(connection.CreateClientSocket()); |
| +} |
| + |
| +// Ensure that messages can be sent across the resulting socket. |
| +TEST(UnixDomainSocketUtil, SendReceive) { |
| + TestUnixSocketConnection connection; |
| + ASSERT_TRUE(connection.CreateServerSocket()); |
| + ASSERT_TRUE(connection.CreateClientSocket()); |
| + |
| + const char buffer[] = "Hello, server!"; |
| + size_t buf_len = strlen(buffer) + 1; |
|
Mark Mentovai
2013/03/05 20:08:03
You could just use sizeof(buffer).
jeremya
2013/03/06 05:03:18
Done.
|
| + size_t sent_bytes = send(connection.client_fd(), buffer, buf_len, 0); |
|
Mark Mentovai
2013/03/05 20:08:03
HANDLE_EINTR here and on line 151.
jeremya
2013/03/06 05:03:18
Done.
|
| + ASSERT_EQ(buf_len, sent_bytes); |
| + scoped_array<char> recv_buf(new char[buf_len]); |
|
Mark Mentovai
2013/03/05 20:08:03
You could just have a char recv_buf[sizeof(buffer)
jeremya
2013/03/06 05:03:18
Done.
|
| + size_t received_bytes = |
| + recv(connection.server_fd(), recv_buf.get(), buf_len, 0); |
| + ASSERT_EQ(buf_len, received_bytes); |
| + ASSERT_EQ(0, strncmp(recv_buf.get(), buffer, buf_len)); |
|
Mark Mentovai
2013/03/05 20:08:03
Use memcmp. You have sizes in hand and you want to
jeremya
2013/03/06 05:03:18
Done.
|
| +} |
| + |
| +} |
|
Mark Mentovai
2013/03/05 20:08:03
} // namespace
jeremya
2013/03/06 05:03:18
Done.
|