Index: webrtc/base/physicalsocketserver_unittest.cc |
diff --git a/webrtc/base/physicalsocketserver_unittest.cc b/webrtc/base/physicalsocketserver_unittest.cc |
index f2eabcd66cf15f6b0f2f23d6a2b3d1978aaaa876..073f6f20d708967c3fbe0429f0e47f86dc05ed25 100644 |
--- a/webrtc/base/physicalsocketserver_unittest.cc |
+++ b/webrtc/base/physicalsocketserver_unittest.cc |
@@ -22,9 +22,72 @@ |
namespace rtc { |
+class PhysicalSocketTest; |
+ |
+class MockSocketDispatcher : public SocketDispatcher { |
pthatcher1
2015/12/03 22:56:32
I think we would call these Fake, not Mock
|
+ public: |
+ explicit MockSocketDispatcher(PhysicalSocketServer* ss) |
+ : SocketDispatcher(ss) { |
+ } |
+ |
+ protected: |
+ SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override; |
+}; |
+ |
+class MockPhysicalSocketServer : public PhysicalSocketServer { |
+ public: |
+ explicit MockPhysicalSocketServer(PhysicalSocketTest* test) |
+ : test_(test) { |
+ } |
+ |
+ AsyncSocket* CreateAsyncSocket(int family, int type) override { |
+ SocketDispatcher* dispatcher = new MockSocketDispatcher(this); |
+ if (dispatcher->Create(family, type)) { |
+ return dispatcher; |
+ } else { |
+ delete dispatcher; |
+ return nullptr; |
+ } |
+ } |
+ |
+ PhysicalSocketTest* GetTest() const { return test_; } |
+ |
+ private: |
+ PhysicalSocketTest* test_; |
+}; |
+ |
class PhysicalSocketTest : public SocketTest { |
+ public: |
+ // Set flag to simluate failures when calling "::accept" on a AsyncSocket. |
+ void SetFailAccept(bool fail) { fail_accept_ = fail; } |
+ bool FailAccept() const { return fail_accept_; } |
+ |
+ protected: |
+ PhysicalSocketTest() |
+ : server_(new MockPhysicalSocketServer(this)), |
+ scope_(server_.get()), |
+ fail_accept_(false) { |
+ } |
+ |
+ void ConnectInternalAcceptError(const IPAddress& loopback); |
+ |
+ rtc::scoped_ptr<MockPhysicalSocketServer> server_; |
+ SocketServerScope scope_; |
+ bool fail_accept_; |
}; |
+SOCKET MockSocketDispatcher::DoAccept(SOCKET socket, |
+ sockaddr* addr, |
+ socklen_t* addrlen) { |
+ MockPhysicalSocketServer* ss = |
+ static_cast<MockPhysicalSocketServer*>(socketserver()); |
+ if (ss->GetTest()->FailAccept()) { |
+ return INVALID_SOCKET; |
+ } |
+ |
+ return SocketDispatcher::DoAccept(socket, addr, addrlen); |
+} |
+ |
TEST_F(PhysicalSocketTest, TestConnectIPv4) { |
SocketTest::TestConnectIPv4(); |
} |
@@ -51,6 +114,92 @@ TEST_F(PhysicalSocketTest, TestConnectFailIPv4) { |
SocketTest::TestConnectFailIPv4(); |
} |
+void PhysicalSocketTest::ConnectInternalAcceptError(const IPAddress& loopback) { |
+ testing::StreamSink sink; |
+ SocketAddress accept_addr; |
+ |
+ // Create two clients. |
+ scoped_ptr<AsyncSocket> client1(server_->CreateAsyncSocket(loopback.family(), |
+ SOCK_STREAM)); |
+ sink.Monitor(client1.get()); |
+ EXPECT_EQ(AsyncSocket::CS_CLOSED, client1->GetState()); |
+ EXPECT_PRED1(IsUnspecOrEmptyIP, client1->GetLocalAddress().ipaddr()); |
+ |
+ scoped_ptr<AsyncSocket> client2(server_->CreateAsyncSocket(loopback.family(), |
+ SOCK_STREAM)); |
+ sink.Monitor(client2.get()); |
+ EXPECT_EQ(AsyncSocket::CS_CLOSED, client2->GetState()); |
+ EXPECT_PRED1(IsUnspecOrEmptyIP, client2->GetLocalAddress().ipaddr()); |
+ |
+ // Create server and listen. |
+ scoped_ptr<AsyncSocket> server( |
+ server_->CreateAsyncSocket(loopback.family(), SOCK_STREAM)); |
+ sink.Monitor(server.get()); |
+ EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); |
+ EXPECT_EQ(0, server->Listen(5)); |
+ EXPECT_EQ(AsyncSocket::CS_CONNECTING, server->GetState()); |
+ |
+ // Ensure no pending server connections, since we haven't done anything yet. |
+ EXPECT_FALSE(sink.Check(server.get(), testing::SSE_READ)); |
+ EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); |
+ EXPECT_TRUE(accept_addr.IsNil()); |
+ |
+ // Attempt first connect to listening socket. |
+ EXPECT_EQ(0, client1->Connect(server->GetLocalAddress())); |
+ EXPECT_FALSE(client1->GetLocalAddress().IsNil()); |
+ EXPECT_NE(server->GetLocalAddress(), client1->GetLocalAddress()); |
+ |
+ // Client is connecting, outcome not yet determined. |
+ EXPECT_EQ(AsyncSocket::CS_CONNECTING, client1->GetState()); |
+ EXPECT_FALSE(sink.Check(client1.get(), testing::SSE_OPEN)); |
+ EXPECT_FALSE(sink.Check(client1.get(), testing::SSE_CLOSE)); |
+ |
+ // Server has pending connection, try to accept it (will fail). |
+ EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout); |
+ // Simulate "::accept" returning an error. |
+ SetFailAccept(true); |
+ scoped_ptr<AsyncSocket> accepted(server->Accept(&accept_addr)); |
+ EXPECT_FALSE(accepted); |
+ ASSERT_TRUE(accept_addr.IsNil()); |
+ |
+ // Ensure no more pending server connections. |
+ EXPECT_FALSE(sink.Check(server.get(), testing::SSE_READ)); |
+ EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); |
+ EXPECT_TRUE(accept_addr.IsNil()); |
+ |
+ // Attempt second connect to listening socket. |
+ EXPECT_EQ(0, client2->Connect(server->GetLocalAddress())); |
+ EXPECT_FALSE(client2->GetLocalAddress().IsNil()); |
+ EXPECT_NE(server->GetLocalAddress(), client2->GetLocalAddress()); |
+ |
+ // Client is connecting, outcome not yet determined. |
+ EXPECT_EQ(AsyncSocket::CS_CONNECTING, client2->GetState()); |
+ EXPECT_FALSE(sink.Check(client2.get(), testing::SSE_OPEN)); |
+ EXPECT_FALSE(sink.Check(client2.get(), testing::SSE_CLOSE)); |
+ |
+ // Server has pending connection, try to accept it (will succeed). |
+ EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout); |
+ SetFailAccept(false); |
+ scoped_ptr<AsyncSocket> accepted2(server->Accept(&accept_addr)); |
+ ASSERT_TRUE(accepted2); |
+ EXPECT_FALSE(accept_addr.IsNil()); |
+ EXPECT_EQ(accepted2->GetRemoteAddress(), accept_addr); |
+} |
+ |
+TEST_F(PhysicalSocketTest, TestConnectAcceptErrorIPv4) { |
+ ConnectInternalAcceptError(kIPv4Loopback); |
+} |
+ |
+// Crashes on Linux. See webrtc:4923. |
+#if defined(WEBRTC_LINUX) |
+#define MAYBE_TestConnectAcceptErrorIPv6 DISABLED_TestConnectAcceptErrorIPv6 |
+#else |
+#define MAYBE_TestConnectAcceptErrorIPv6 TestConnectAcceptErrorIPv6 |
+#endif |
+TEST_F(PhysicalSocketTest, MAYBE_TestConnectAcceptErrorIPv6) { |
+ ConnectInternalAcceptError(kIPv6Loopback); |
+} |
+ |
// Crashes on Linux. See webrtc:4923. |
#if defined(WEBRTC_LINUX) |
#define MAYBE_TestConnectFailIPv6 DISABLED_TestConnectFailIPv6 |