summaryrefslogtreecommitdiffstats
path: root/ppapi/tests
diff options
context:
space:
mode:
authoryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 15:29:13 +0000
committeryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 15:29:13 +0000
commit92576792823018d937fc58e74267b0d30663e459 (patch)
treea80543169bea29b7fee7346387a1a0e1d6b34090 /ppapi/tests
parent5603a6cf5fb7197f509b894e45bdc733e720b28a (diff)
downloadchromium_src-92576792823018d937fc58e74267b0d30663e459.zip
chromium_src-92576792823018d937fc58e74267b0d30663e459.tar.gz
chromium_src-92576792823018d937fc58e74267b0d30663e459.tar.bz2
PPB_TCPSocket: add support for TCP server socket operations.
BUG=262601 TEST=new tests in test_tcp_socket. Review URL: https://chromiumcodereview.appspot.com/24195004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224383 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/tests')
-rw-r--r--ppapi/tests/test_tcp_socket.cc297
-rw-r--r--ppapi/tests/test_tcp_socket.h13
-rw-r--r--ppapi/tests/test_utils.cc47
-rw-r--r--ppapi/tests/test_utils.h5
4 files changed, 318 insertions, 44 deletions
diff --git a/ppapi/tests/test_tcp_socket.cc b/ppapi/tests/test_tcp_socket.cc
index a4c56eb..90f6913 100644
--- a/ppapi/tests/test_tcp_socket.cc
+++ b/ppapi/tests/test_tcp_socket.cc
@@ -4,6 +4,9 @@
#include "ppapi/tests/test_tcp_socket.h"
+#include <vector>
+
+#include "ppapi/cpp/message_loop.h"
#include "ppapi/cpp/tcp_socket.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"
@@ -49,25 +52,58 @@ void TestTCPSocket::RunTests(const std::string& filter) {
RUN_CALLBACK_TEST(TestTCPSocket, Connect, filter);
RUN_CALLBACK_TEST(TestTCPSocket, ReadWrite, filter);
RUN_CALLBACK_TEST(TestTCPSocket, SetOption, filter);
+ RUN_CALLBACK_TEST(TestTCPSocket, Listen, filter);
+ RUN_CALLBACK_TEST(TestTCPSocket, Backlog, filter);
}
std::string TestTCPSocket::TestConnect() {
- pp::TCPSocket socket(instance_);
- TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+ {
+ // The basic case.
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(cb);
- ASSERT_EQ(PP_OK, cb.result());
+ cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
+
+ pp::NetAddress local_addr, remote_addr;
+ local_addr = socket.GetLocalAddress();
+ remote_addr = socket.GetRemoteAddress();
+
+ ASSERT_NE(0, local_addr.pp_resource());
+ ASSERT_NE(0, remote_addr.pp_resource());
+ ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
- pp::NetAddress local_addr, remote_addr;
- local_addr = socket.GetLocalAddress();
- remote_addr = socket.GetRemoteAddress();
+ socket.Close();
+ }
+
+ {
+ // Connect a bound socket.
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+ pp::NetAddress any_port_address;
+ ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
+
+ cb.WaitForResult(socket.Bind(any_port_address, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
- ASSERT_NE(0, local_addr.pp_resource());
- ASSERT_NE(0, remote_addr.pp_resource());
- ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
+ cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
- socket.Close();
+ pp::NetAddress local_addr, remote_addr;
+ local_addr = socket.GetLocalAddress();
+ remote_addr = socket.GetRemoteAddress();
+
+ ASSERT_NE(0, local_addr.pp_resource());
+ ASSERT_NE(0, remote_addr.pp_resource());
+ ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
+ ASSERT_NE(0u, GetPort(local_addr));
+
+ socket.Close();
+ }
PASS();
}
@@ -80,11 +116,11 @@ std::string TestTCPSocket::TestReadWrite() {
CHECK_CALLBACK_BEHAVIOR(cb);
ASSERT_EQ(PP_OK, cb.result());
- ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
// Read up to the first \n and check that it looks like valid HTTP response.
std::string s;
- ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s));
+ ASSERT_SUBTEST_SUCCESS(ReadFirstLineFromSocket(&socket, &s));
ASSERT_TRUE(ValidateHttpResponse(s));
PASS();
@@ -95,6 +131,7 @@ std::string TestTCPSocket::TestSetOption() {
TestCompletionCallback cb_1(instance_->pp_instance(), callback_type());
TestCompletionCallback cb_2(instance_->pp_instance(), callback_type());
TestCompletionCallback cb_3(instance_->pp_instance(), callback_type());
+ TestCompletionCallback cb_4(instance_->pp_instance(), callback_type());
// These options cannot be set before the socket is connected.
int32_t result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY,
@@ -104,6 +141,10 @@ std::string TestTCPSocket::TestSetOption() {
int32_t result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
512, cb_3.GetCallback());
+ // This option can only be set before the socket is bound.
+ int32_t result_4 = socket.SetOption(PP_TCPSOCKET_OPTION_ADDRESS_REUSE,
+ true, cb_4.GetCallback());
+
cb_1.WaitForResult(result_1);
CHECK_CALLBACK_BEHAVIOR(cb_1);
ASSERT_EQ(PP_ERROR_FAILED, cb_1.result());
@@ -116,6 +157,10 @@ std::string TestTCPSocket::TestSetOption() {
CHECK_CALLBACK_BEHAVIOR(cb_3);
ASSERT_EQ(PP_ERROR_FAILED, cb_3.result());
+ cb_4.WaitForResult(result_4);
+ CHECK_CALLBACK_BEHAVIOR(cb_4);
+ ASSERT_EQ(PP_OK, cb_4.result());
+
cb_1.WaitForResult(socket.Connect(addr_, cb_1.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(cb_1);
ASSERT_EQ(PP_OK, cb_1.result());
@@ -126,6 +171,8 @@ std::string TestTCPSocket::TestSetOption() {
512, cb_2.GetCallback());
result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
1024, cb_3.GetCallback());
+ result_4 = socket.SetOption(PP_TCPSOCKET_OPTION_ADDRESS_REUSE,
+ false, cb_4.GetCallback());
cb_1.WaitForResult(result_1);
CHECK_CALLBACK_BEHAVIOR(cb_1);
@@ -139,53 +186,221 @@ std::string TestTCPSocket::TestSetOption() {
CHECK_CALLBACK_BEHAVIOR(cb_3);
ASSERT_EQ(PP_OK, cb_3.result());
+ cb_4.WaitForResult(result_4);
+ CHECK_CALLBACK_BEHAVIOR(cb_4);
+ ASSERT_EQ(PP_ERROR_FAILED, cb_4.result());
+
+ PASS();
+}
+
+std::string TestTCPSocket::TestListen() {
+ static const int kBacklog = 2;
+
+ pp::TCPSocket server_socket(instance_);
+ ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, kBacklog));
+
+ // We can't use a blocking callback for Accept, because it will wait forever
+ // for the client to connect, since the client connects after.
+ TestCompletionCallbackWithOutput<pp::TCPSocket>
+ accept_callback(instance_->pp_instance(), PP_REQUIRED);
+ // We need to make sure there's a message loop to run accept_callback on.
+ pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent());
+ if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) {
+ current_thread_loop = pp::MessageLoop(instance_);
+ current_thread_loop.AttachToCurrentThread();
+ }
+
+ int32_t accept_rv = server_socket.Accept(accept_callback.GetCallback());
+
+ pp::TCPSocket client_socket;
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ do {
+ client_socket = pp::TCPSocket(instance_);
+
+ callback.WaitForResult(client_socket.Connect(
+ server_socket.GetLocalAddress(), callback.GetCallback()));
+ } while (callback.result() != PP_OK);
+
+ pp::NetAddress client_local_addr = client_socket.GetLocalAddress();
+ pp::NetAddress client_remote_addr = client_socket.GetRemoteAddress();
+ ASSERT_FALSE(client_local_addr.is_null());
+ ASSERT_FALSE(client_remote_addr.is_null());
+
+ accept_callback.WaitForResult(accept_rv);
+ CHECK_CALLBACK_BEHAVIOR(accept_callback);
+ ASSERT_EQ(PP_OK, accept_callback.result());
+
+ pp::TCPSocket accepted_socket(accept_callback.output());
+ pp::NetAddress accepted_local_addr = accepted_socket.GetLocalAddress();
+ pp::NetAddress accepted_remote_addr = accepted_socket.GetRemoteAddress();
+ ASSERT_FALSE(accepted_local_addr.is_null());
+ ASSERT_FALSE(accepted_remote_addr.is_null());
+
+ ASSERT_TRUE(EqualNetAddress(client_local_addr, accepted_remote_addr));
+
+ const char kSentByte = 'a';
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(&client_socket,
+ std::string(1, kSentByte)));
+
+ char received_byte;
+ ASSERT_SUBTEST_SUCCESS(ReadFromSocket(&accepted_socket,
+ &received_byte,
+ sizeof(received_byte)));
+ ASSERT_EQ(kSentByte, received_byte);
+
+ accepted_socket.Close();
+ client_socket.Close();
+ server_socket.Close();
+
PASS();
}
-int32_t TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket,
- std::string* s) {
+std::string TestTCPSocket::TestBacklog() {
+ static const size_t kBacklog = 5;
+
+ pp::TCPSocket server_socket(instance_);
+ ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, 2 * kBacklog));
+
+ std::vector<pp::TCPSocket*> client_sockets(kBacklog);
+ std::vector<TestCompletionCallback*> connect_callbacks(kBacklog);
+ std::vector<int32_t> connect_rv(kBacklog);
+ pp::NetAddress address = server_socket.GetLocalAddress();
+ for (size_t i = 0; i < kBacklog; ++i) {
+ client_sockets[i] = new pp::TCPSocket(instance_);
+ connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(),
+ callback_type());
+ connect_rv[i] = client_sockets[i]->Connect(
+ address, connect_callbacks[i]->GetCallback());
+ }
+
+ std::vector<pp::TCPSocket*> accepted_sockets(kBacklog);
+ for (size_t i = 0; i < kBacklog; ++i) {
+ TestCompletionCallbackWithOutput<pp::TCPSocket> callback(
+ instance_->pp_instance(), callback_type());
+ callback.WaitForResult(server_socket.Accept(callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ accepted_sockets[i] = new pp::TCPSocket(callback.output());
+ ASSERT_FALSE(accepted_sockets[i]->is_null());
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ connect_callbacks[i]->WaitForResult(connect_rv[i]);
+ CHECK_CALLBACK_BEHAVIOR(*connect_callbacks[i]);
+ ASSERT_EQ(PP_OK, connect_callbacks[i]->result());
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ const char byte = 'a' + i;
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(client_sockets[i],
+ std::string(1, byte)));
+ }
+
+ bool byte_received[kBacklog] = {};
+ for (size_t i = 0; i < kBacklog; ++i) {
+ char byte;
+ ASSERT_SUBTEST_SUCCESS(ReadFromSocket(
+ accepted_sockets[i], &byte, sizeof(byte)));
+ const size_t index = byte - 'a';
+ ASSERT_GE(index, 0u);
+ ASSERT_LT(index, kBacklog);
+ ASSERT_FALSE(byte_received[index]);
+ byte_received[index] = true;
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ ASSERT_TRUE(byte_received[i]);
+
+ delete client_sockets[i];
+ delete connect_callbacks[i];
+ delete accepted_sockets[i];
+ }
+
+ PASS();
+}
+
+std::string TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket,
+ std::string* s) {
char buffer[1000];
s->clear();
// Make sure we don't just hang if |Read()| spews.
while (s->size() < 10000) {
TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- int32_t rv = socket->Read(buffer, sizeof(buffer), cb.GetCallback());
- if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
- return PP_ERROR_FAILED;
- cb.WaitForResult(rv);
- if (cb.result() < 0)
- return cb.result();
- if (cb.result() == 0)
- return PP_ERROR_FAILED; // Didn't get a \n-terminated line.
+ cb.WaitForResult(socket->Read(buffer, sizeof(buffer), cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_GT(cb.result(), 0);
s->reserve(s->size() + cb.result());
- for (int32_t i = 0; i < cb.result(); i++) {
+ for (int32_t i = 0; i < cb.result(); ++i) {
s->push_back(buffer[i]);
if (buffer[i] == '\n')
- return PP_OK;
+ PASS();
}
}
- return PP_ERROR_FAILED;
+ PASS();
+}
+
+std::string TestTCPSocket::ReadFromSocket(pp::TCPSocket* socket,
+ char* buffer,
+ size_t num_bytes) {
+ while (num_bytes > 0) {
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(
+ socket->Read(buffer, num_bytes, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_GT(callback.result(), 0);
+ buffer += callback.result();
+ num_bytes -= callback.result();
+ }
+ ASSERT_EQ(0u, num_bytes);
+ PASS();
}
-int32_t TestTCPSocket::WriteStringToSocket(pp::TCPSocket* socket,
- const std::string& s) {
+std::string TestTCPSocket::WriteToSocket(pp::TCPSocket* socket,
+ const std::string& s) {
const char* buffer = s.data();
size_t written = 0;
while (written < s.size()) {
TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- int32_t rv = socket->Write(buffer + written, s.size() - written,
- cb.GetCallback());
- if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
- return PP_ERROR_FAILED;
- cb.WaitForResult(rv);
- if (cb.result() < 0)
- return cb.result();
- if (cb.result() == 0)
- return PP_ERROR_FAILED;
+ cb.WaitForResult(
+ socket->Write(buffer + written, s.size() - written, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_GT(cb.result(), 0);
written += cb.result();
}
- if (written != s.size())
- return PP_ERROR_FAILED;
- return PP_OK;
+ ASSERT_EQ(written, s.size());
+ PASS();
}
+
+std::string TestTCPSocket::GetAddressToBind(pp::NetAddress* address) {
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(socket.Connect(addr_, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ ASSERT_TRUE(ReplacePort(instance_->pp_instance(), socket.GetLocalAddress(), 0,
+ address));
+ ASSERT_FALSE(address->is_null());
+ PASS();
+}
+
+std::string TestTCPSocket::StartListen(pp::TCPSocket* socket, int32_t backlog) {
+ pp::NetAddress any_port_address;
+ ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
+
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(
+ socket->Bind(any_port_address, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ callback.WaitForResult(
+ socket->Listen(backlog, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ PASS();
+}
+
diff --git a/ppapi/tests/test_tcp_socket.h b/ppapi/tests/test_tcp_socket.h
index 44c7321..136dc46 100644
--- a/ppapi/tests/test_tcp_socket.h
+++ b/ppapi/tests/test_tcp_socket.h
@@ -27,9 +27,16 @@ class TestTCPSocket: public TestCase {
std::string TestConnect();
std::string TestReadWrite();
std::string TestSetOption();
-
- int32_t ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s);
- int32_t WriteStringToSocket(pp::TCPSocket* socket, const std::string& s);
+ std::string TestListen();
+ std::string TestBacklog();
+
+ std::string ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s);
+ std::string ReadFromSocket(pp::TCPSocket* socket,
+ char* buffer,
+ size_t num_bytes);
+ std::string WriteToSocket(pp::TCPSocket* socket, const std::string& s);
+ std::string GetAddressToBind(pp::NetAddress* address);
+ std::string StartListen(pp::TCPSocket* socket, int32_t backlog);
pp::NetAddress addr_;
};
diff --git a/ppapi/tests/test_utils.cc b/ppapi/tests/test_utils.cc
index f9fd7b6..eecbe7a 100644
--- a/ppapi/tests/test_utils.cc
+++ b/ppapi/tests/test_utils.cc
@@ -179,6 +179,53 @@ bool ResolveHost(PP_Instance instance,
}
}
+bool ReplacePort(PP_Instance instance,
+ const pp::NetAddress& input_addr,
+ uint16_t port,
+ pp::NetAddress* output_addr) {
+ switch (input_addr.GetFamily()) {
+ case PP_NETADDRESS_FAMILY_IPV4: {
+ PP_NetAddress_IPv4 ipv4_addr;
+ if (!input_addr.DescribeAsIPv4Address(&ipv4_addr))
+ return false;
+ ipv4_addr.port = ConvertToNetEndian16(port);
+ *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv4_addr);
+ return true;
+ }
+ case PP_NETADDRESS_FAMILY_IPV6: {
+ PP_NetAddress_IPv6 ipv6_addr;
+ if (!input_addr.DescribeAsIPv6Address(&ipv6_addr))
+ return false;
+ ipv6_addr.port = ConvertToNetEndian16(port);
+ *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv6_addr);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+uint16_t GetPort(const pp::NetAddress& addr) {
+ switch (addr.GetFamily()) {
+ case PP_NETADDRESS_FAMILY_IPV4: {
+ PP_NetAddress_IPv4 ipv4_addr;
+ if (!addr.DescribeAsIPv4Address(&ipv4_addr))
+ return 0;
+ return ConvertFromNetEndian16(ipv4_addr.port);
+ }
+ case PP_NETADDRESS_FAMILY_IPV6: {
+ PP_NetAddress_IPv6 ipv6_addr;
+ if (!addr.DescribeAsIPv6Address(&ipv6_addr))
+ return 0;
+ return ConvertFromNetEndian16(ipv6_addr.port);
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
void NestedEvent::Wait() {
PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
// Don't allow nesting more than once; it doesn't work with the code as-is,
diff --git a/ppapi/tests/test_utils.h b/ppapi/tests/test_utils.h
index 357a1c6..4621c355 100644
--- a/ppapi/tests/test_utils.h
+++ b/ppapi/tests/test_utils.h
@@ -34,6 +34,11 @@ bool ResolveHost(PP_Instance instance,
const std::string& host,
uint16_t port,
pp::NetAddress* addr);
+bool ReplacePort(PP_Instance instance,
+ const pp::NetAddress& input_addr,
+ uint16_t port,
+ pp::NetAddress* output_addr);
+uint16_t GetPort(const pp::NetAddress& addr);
// NestedEvent allows you to run a nested MessageLoop and wait for a particular
// event to complete. For example, you can use it to wait for a callback on a