summaryrefslogtreecommitdiffstats
path: root/ppapi/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/tests')
-rw-r--r--ppapi/tests/all_c_includes.h1
-rw-r--r--ppapi/tests/all_cpp_includes.h1
-rw-r--r--ppapi/tests/test_tcp_socket.cc160
-rw-r--r--ppapi/tests/test_tcp_socket.h37
-rw-r--r--ppapi/tests/test_utils.cc81
-rw-r--r--ppapi/tests/test_utils.h11
6 files changed, 291 insertions, 0 deletions
diff --git a/ppapi/tests/all_c_includes.h b/ppapi/tests/all_c_includes.h
index d550c21..4a8ae13 100644
--- a/ppapi/tests/all_c_includes.h
+++ b/ppapi/tests/all_c_includes.h
@@ -26,6 +26,7 @@
#include "ppapi/c/dev/ppb_printing_dev.h"
#include "ppapi/c/dev/ppb_resource_array_dev.h"
#include "ppapi/c/dev/ppb_scrollbar_dev.h"
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/dev/ppb_text_input_dev.h"
#include "ppapi/c/dev/ppb_trace_event_dev.h"
diff --git a/ppapi/tests/all_cpp_includes.h b/ppapi/tests/all_cpp_includes.h
index 45fddf2..37a4100 100644
--- a/ppapi/tests/all_cpp_includes.h
+++ b/ppapi/tests/all_cpp_includes.h
@@ -26,6 +26,7 @@
#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/dev/scrollbar_dev.h"
#include "ppapi/cpp/dev/selection_dev.h"
+#include "ppapi/cpp/dev/tcp_socket_dev.h"
#include "ppapi/cpp/dev/text_input_dev.h"
#include "ppapi/cpp/dev/url_util_dev.h"
#include "ppapi/cpp/dev/var_array_dev.h"
diff --git a/ppapi/tests/test_tcp_socket.cc b/ppapi/tests/test_tcp_socket.cc
new file mode 100644
index 0000000..7a14fe7
--- /dev/null
+++ b/ppapi/tests/test_tcp_socket.cc
@@ -0,0 +1,160 @@
+// 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 "ppapi/tests/test_tcp_socket.h"
+
+#include "ppapi/cpp/dev/tcp_socket_dev.h"
+#include "ppapi/tests/test_utils.h"
+#include "ppapi/tests/testing_instance.h"
+
+namespace {
+
+// Validates the first line of an HTTP response.
+bool ValidateHttpResponse(const std::string& s) {
+ // Just check that it begins with "HTTP/" and ends with a "\r\n".
+ return s.size() >= 5 &&
+ s.substr(0, 5) == "HTTP/" &&
+ s.substr(s.size() - 2) == "\r\n";
+}
+
+} // namespace
+
+REGISTER_TEST_CASE(TCPSocket);
+
+TestTCPSocket::TestTCPSocket(TestingInstance* instance) : TestCase(instance) {
+}
+
+bool TestTCPSocket::Init() {
+ if (!pp::TCPSocket_Dev::IsAvailable())
+ return false;
+
+ // We need something to connect to, so we connect to the HTTP server whence we
+ // came. Grab the host and port.
+ if (!EnsureRunningOverHTTP())
+ return false;
+
+ std::string host;
+ uint16_t port = 0;
+ if (!GetLocalHostPort(instance_->pp_instance(), &host, &port))
+ return false;
+
+ if (!ResolveHost(instance_->pp_instance(), host, port, &addr_))
+ return false;
+
+ return true;
+}
+
+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);
+}
+
+std::string TestTCPSocket::TestConnect() {
+ pp::TCPSocket_Dev 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());
+
+ pp::NetAddress_Dev 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));
+
+ socket.Close();
+
+ PASS();
+}
+
+std::string TestTCPSocket::TestReadWrite() {
+ pp::TCPSocket_Dev 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());
+
+ ASSERT_EQ(PP_OK, WriteStringToSocket(&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_TRUE(ValidateHttpResponse(s));
+
+ PASS();
+}
+
+std::string TestTCPSocket::TestSetOption() {
+ pp::TCPSocket_Dev socket(instance_);
+ TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+ cb.WaitForResult(
+ socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, true, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_ERROR_FAILED, cb.result());
+
+ cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
+
+ cb.WaitForResult(
+ socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, true, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
+
+ PASS();
+}
+
+int32_t TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket_Dev* 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.
+ s->reserve(s->size() + cb.result());
+ for (int32_t i = 0; i < cb.result(); i++) {
+ s->push_back(buffer[i]);
+ if (buffer[i] == '\n')
+ return PP_OK;
+ }
+ }
+ return PP_ERROR_FAILED;
+}
+
+int32_t TestTCPSocket::WriteStringToSocket(pp::TCPSocket_Dev* 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;
+ written += cb.result();
+ }
+ if (written != s.size())
+ return PP_ERROR_FAILED;
+ return PP_OK;
+}
diff --git a/ppapi/tests/test_tcp_socket.h b/ppapi/tests/test_tcp_socket.h
new file mode 100644
index 0000000..0ff7e33
--- /dev/null
+++ b/ppapi/tests/test_tcp_socket.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef PAPPI_TESTS_TEST_TCP_SOCKET_H_
+#define PAPPI_TESTS_TEST_TCP_SOCKET_H_
+
+#include <string>
+
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/cpp/dev/net_address_dev.h"
+#include "ppapi/tests/test_case.h"
+
+namespace pp {
+class TCPSocket_Dev;
+}
+
+class TestTCPSocket: public TestCase {
+ public:
+ explicit TestTCPSocket(TestingInstance* instance);
+
+ // TestCase implementation.
+ virtual bool Init();
+ virtual void RunTests(const std::string& filter);
+
+ private:
+ std::string TestConnect();
+ std::string TestReadWrite();
+ std::string TestSetOption();
+
+ int32_t ReadFirstLineFromSocket(pp::TCPSocket_Dev* socket, std::string* s);
+ int32_t WriteStringToSocket(pp::TCPSocket_Dev* socket, const std::string& s);
+
+ pp::NetAddress_Dev addr_;
+};
+
+#endif // PAPPI_TESTS_TEST_TCP_SOCKET_H_
diff --git a/ppapi/tests/test_utils.cc b/ppapi/tests/test_utils.cc
index 86a9bc1..509d6ff 100644
--- a/ppapi/tests/test_utils.cc
+++ b/ppapi/tests/test_utils.cc
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#if defined(_MSC_VER)
#include <windows.h>
#else
@@ -13,7 +14,11 @@
#endif
#include "ppapi/c/pp_errors.h"
+#include "ppapi/cpp/dev/net_address_dev.h"
+#include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/private/host_resolver_private.h"
+#include "ppapi/cpp/private/net_address_private.h"
#include "ppapi/cpp/var.h"
namespace {
@@ -98,6 +103,82 @@ uint16_t ConvertToNetEndian16(uint16_t x) {
return (x << 8) | (x >> 8);
}
+bool EqualNetAddress(const pp::NetAddress_Dev& addr1,
+ const pp::NetAddress_Dev& addr2) {
+ if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED ||
+ addr2.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED) {
+ return false;
+ }
+
+ if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_IPV4) {
+ PP_NetAddress_IPv4_Dev ipv4_addr1, ipv4_addr2;
+ if (!addr1.DescribeAsIPv4Address(&ipv4_addr1) ||
+ !addr2.DescribeAsIPv4Address(&ipv4_addr2)) {
+ return false;
+ }
+
+ return ipv4_addr1.port == ipv4_addr2.port &&
+ !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
+ } else {
+ PP_NetAddress_IPv6_Dev ipv6_addr1, ipv6_addr2;
+ if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
+ !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
+ return false;
+ }
+
+ return ipv6_addr1.port == ipv6_addr2.port &&
+ !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
+ }
+}
+
+bool ResolveHost(PP_Instance instance,
+ const std::string& host,
+ uint16_t port,
+ pp::NetAddress_Dev* addr) {
+ // TODO(yzshen): Change to use the public host resolver once it is supported.
+ pp::InstanceHandle instance_handle(instance);
+ pp::HostResolverPrivate host_resolver(instance_handle);
+ PP_HostResolver_Private_Hint hint = { PP_NETADDRESSFAMILY_UNSPECIFIED, 0 };
+
+ TestCompletionCallback callback(instance);
+ callback.WaitForResult(
+ host_resolver.Resolve(host, port, hint, callback.GetCallback()));
+
+ PP_NetAddress_Private addr_private;
+ if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
+ !host_resolver.GetNetAddress(0, &addr_private)) {
+ return false;
+ }
+
+ switch (pp::NetAddressPrivate::GetFamily(addr_private)) {
+ case PP_NETADDRESSFAMILY_IPV4: {
+ PP_NetAddress_IPv4_Dev ipv4_addr;
+ ipv4_addr.port = ConvertToNetEndian16(
+ pp::NetAddressPrivate::GetPort(addr_private));
+ if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv4_addr.addr,
+ sizeof(ipv4_addr.addr))) {
+ return false;
+ }
+ *addr = pp::NetAddress_Dev(instance_handle, ipv4_addr);
+ return true;
+ }
+ case PP_NETADDRESSFAMILY_IPV6: {
+ PP_NetAddress_IPv6_Dev ipv6_addr;
+ ipv6_addr.port = ConvertToNetEndian16(
+ pp::NetAddressPrivate::GetPort(addr_private));
+ if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv6_addr.addr,
+ sizeof(ipv6_addr.addr))) {
+ return false;
+ }
+ *addr = pp::NetAddress_Dev(instance_handle, ipv6_addr);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
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 0410018..04aa452 100644
--- a/ppapi/tests/test_utils.h
+++ b/ppapi/tests/test_utils.h
@@ -14,6 +14,10 @@
#include "ppapi/cpp/message_loop.h"
#include "ppapi/utility/completion_callback_factory.h"
+namespace pp {
+class NetAddress_Dev;
+}
+
// Timeout to wait for some action to complete.
extern const int kActionTimeoutMs;
@@ -24,6 +28,13 @@ bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port);
uint16_t ConvertFromNetEndian16(uint16_t x);
uint16_t ConvertToNetEndian16(uint16_t x);
+bool EqualNetAddress(const pp::NetAddress_Dev& addr1,
+ const pp::NetAddress_Dev& addr2);
+// Only returns the first address if there are more than one available.
+bool ResolveHost(PP_Instance instance,
+ const std::string& host,
+ uint16_t port,
+ pp::NetAddress_Dev* 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