From cfff9eb8c2dad715a8d4a7be088d82a9e0fada22 Mon Sep 17 00:00:00 2001 From: "viettrungluu@chromium.org" Date: Tue, 15 Nov 2011 03:17:10 +0000 Subject: Pepper: Add a test for PPB_TCPSocket_Private. Actually, the interface is currently known as PPB_Flash_TCPSocket. BUG=103993 TEST=ui_tests OutOfProcessPPAPITest.TCPSocketPrivate TBR=dmichael@chromium.org Review URL: http://codereview.chromium.org/8564034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110026 0039d316-1c4b-4281-b951-d872f2087c98 --- ppapi/cpp/private/flash_tcp_socket.cc | 7 +- ppapi/cpp/private/flash_tcp_socket.h | 7 +- ppapi/ppapi_cpp.gypi | 2 + ppapi/ppapi_tests.gypi | 2 + ppapi/tests/test_tcp_socket_private.cc | 217 +++++++++++++++++++++++++++++++++ ppapi/tests/test_tcp_socket_private.h | 42 +++++++ 6 files changed, 271 insertions(+), 6 deletions(-) create mode 100644 ppapi/tests/test_tcp_socket_private.cc create mode 100644 ppapi/tests/test_tcp_socket_private.h (limited to 'ppapi') diff --git a/ppapi/cpp/private/flash_tcp_socket.cc b/ppapi/cpp/private/flash_tcp_socket.cc index 0dec218..18c865f 100644 --- a/ppapi/cpp/private/flash_tcp_socket.cc +++ b/ppapi/cpp/private/flash_tcp_socket.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(yzshen): See the comment in corresponding .h file. - #include "ppapi/cpp/private/flash_tcp_socket.h" #include "ppapi/c/pp_bool.h" @@ -32,6 +30,11 @@ TCPSocket::TCPSocket(Instance* instance) { } } +// static +bool TCPSocket::IsAvailable() { + return has_interface(); +} + int32_t TCPSocket::Connect(const char* host, uint16_t port, const CompletionCallback& callback) { diff --git a/ppapi/cpp/private/flash_tcp_socket.h b/ppapi/cpp/private/flash_tcp_socket.h index 41d21c0..7d68abb 100644 --- a/ppapi/cpp/private/flash_tcp_socket.h +++ b/ppapi/cpp/private/flash_tcp_socket.h @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(yzshen): This (and the .cc file) contain C++ wrappers for things -// in ppapi/c/private/ppb_flash_tcp_socket.h. This is currently not used in -// (or even compiled with) Chromium. - #ifndef PPAPI_CPP_PRIVATE_FLASH_TCP_SOCKET_H_ #define PPAPI_CPP_PRIVATE_FLASH_TCP_SOCKET_H_ @@ -24,6 +20,9 @@ class TCPSocket : public Resource { public: explicit TCPSocket(Instance* instance); + // Returns true if the required interface is available. + static bool IsAvailable(); + int32_t Connect(const char* host, uint16_t port, const CompletionCallback& callback); diff --git a/ppapi/ppapi_cpp.gypi b/ppapi/ppapi_cpp.gypi index 918c659..0f0a88d 100644 --- a/ppapi/ppapi_cpp.gypi +++ b/ppapi/ppapi_cpp.gypi @@ -249,6 +249,8 @@ # Private interfaces. 'cpp/private/flash_fullscreen.cc', 'cpp/private/flash_fullscreen.h', + 'cpp/private/flash_tcp_socket.cc', + 'cpp/private/flash_tcp_socket.h', 'cpp/private/instance_private.cc', 'cpp/private/instance_private.h', 'cpp/private/net_address_private.cc', diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index 9b17c5d..48f6745 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi @@ -121,6 +121,8 @@ 'tests/test_scrollbar.cc', 'tests/test_scrollbar.h', 'tests/test_struct_sizes.c', + 'tests/test_tcp_socket_private.cc', + 'tests/test_tcp_socket_private.h', 'tests/test_uma.cc', 'tests/test_uma.h', 'tests/test_url_loader.cc', diff --git a/ppapi/tests/test_tcp_socket_private.cc b/ppapi/tests/test_tcp_socket_private.cc new file mode 100644 index 0000000..c2ef676 --- /dev/null +++ b/ppapi/tests/test_tcp_socket_private.cc @@ -0,0 +1,217 @@ +// Copyright (c) 2011 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_private.h" + +#include + +#include "base/string_split.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/cpp/dev/url_util_dev.h" +#include "ppapi/cpp/private/flash_tcp_socket.h" +#include "ppapi/cpp/var.h" +#include "ppapi/tests/testing_instance.h" +#include "ppapi/tests/test_utils.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(TCPSocketPrivate); + +TestTCPSocketPrivate::TestTCPSocketPrivate(TestingInstance* instance) + : TestCase(instance) { +} + +bool TestTCPSocketPrivate::Init() { + if (!TCPSocketPrivate::IsAvailable()) + return false; + + // This test currently only works out-of-process (since the API is really only + // implemented in that case). + const PPB_Testing_Dev* testing = GetTestingInterface(); + if (!testing) + return false; + if (!testing->IsOutOfProcess()) + 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; + + PP_URLComponents_Dev components; + pp::Var pp_url = pp::URLUtil_Dev::Get()->GetDocumentURL(*instance_, + &components); + if (!pp_url.is_string()) + return false; + std::string url = pp_url.AsString(); + + // Double-check that we're running on HTTP. + if (components.scheme.len < 0) + return false; + if (url.substr(components.scheme.begin, components.scheme.len) != "http") + return false; + + // Get host. + if (components.host.len < 0) + return false; + host_ = url.substr(components.host.begin, components.host.len); + + // Get port (it's optional). + port_ = 80; // Default value. + if (components.port.len > 0) { + int i = atoi(url.substr(components.port.begin, + components.port.len).c_str()); + if (i < 0 || i > 65535) + return false; + port_ = static_cast(i); + } + + return true; +} + +void TestTCPSocketPrivate::RunTest() { + RUN_TEST_FORCEASYNC_AND_NOT(Basic); + RUN_TEST_FORCEASYNC_AND_NOT(ReadWrite); + RUN_TEST_FORCEASYNC_AND_NOT(ConnectAddress); +} + +std::string TestTCPSocketPrivate::TestBasic() { + TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + + int32_t rv = socket.Connect(host_.c_str(), port_, cb); + ASSERT_TRUE(!force_async_ || rv == PP_OK_COMPLETIONPENDING); + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + ASSERT_EQ(PP_OK, rv); + + PP_NetAddress_Private unused; + // TODO(viettrungluu): check the values somehow. + ASSERT_TRUE(socket.GetLocalAddress(&unused)); + ASSERT_TRUE(socket.GetRemoteAddress(&unused)); + + socket.Disconnect(); + + PASS(); +} + +std::string TestTCPSocketPrivate::TestReadWrite() { + TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + + int32_t rv = socket.Connect(host_.c_str(), port_, cb); + ASSERT_TRUE(!force_async_ || rv == PP_OK_COMPLETIONPENDING); + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + ASSERT_EQ(PP_OK, rv); + + 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)); + + socket.Disconnect(); + + PASS(); +} + +std::string TestTCPSocketPrivate::TestConnectAddress() { + PP_NetAddress_Private address; + + // First, bring up a connection and grab the address. + { + TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + int32_t rv = socket.Connect(host_.c_str(), port_, cb); + ASSERT_TRUE(!force_async_ || rv == PP_OK_COMPLETIONPENDING); + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + ASSERT_EQ(PP_OK, rv); + ASSERT_TRUE(socket.GetRemoteAddress(&address)); + // Omit the |Disconnect()| here to make sure we don't crash if we just let + // the resource be destroyed. + } + + // Connect to that address. + TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + int32_t rv = socket.ConnectWithNetAddress(&address, cb); + ASSERT_TRUE(!force_async_ || rv == PP_OK_COMPLETIONPENDING); + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + ASSERT_EQ(PP_OK, rv); + + // Make sure we can read/write to it properly (see |TestReadWrite()|). + ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); + std::string s; + ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s)); + ASSERT_TRUE(ValidateHttpResponse(s)); + + socket.Disconnect(); + + PASS(); +} + +// TODO(viettrungluu): Try testing SSL somehow. + +int32_t TestTCPSocketPrivate::ReadFirstLineFromSocket(TCPSocketPrivate* socket, + std::string* s) { + char buffer[10000]; + + s->clear(); + // Make sure we don't just hang if |Read()| spews. + while (s->size() < 1000000) { + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + int32_t rv = socket->Read(buffer, sizeof(buffer), cb); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return PP_ERROR_FAILED; + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + if (rv < 0) + return rv; + if (rv == 0) + return PP_ERROR_FAILED; // Didn't get a \n-terminated line. + s->reserve(s->size() + rv); + for (int32_t i = 0; i < rv; i++) { + s->push_back(buffer[i]); + if (buffer[i] == '\n') + return PP_OK; + } + } + return PP_ERROR_FAILED; +} + +int32_t TestTCPSocketPrivate::WriteStringToSocket(TCPSocketPrivate* socket, + const std::string& s) { + const char* buffer = s.data(); + size_t written = 0; + while (written < s.size()) { + TestCompletionCallback cb(instance_->pp_instance(), force_async_); + int32_t rv = socket->Write(buffer + written, s.size() - written, cb); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return PP_ERROR_FAILED; + if (rv == PP_OK_COMPLETIONPENDING) + rv = cb.WaitForResult(); + if (rv < 0) + return rv; + if (rv == 0) + return PP_ERROR_FAILED; + written += rv; + } + if (written != s.size()) + return PP_ERROR_FAILED; + return PP_OK; +} diff --git a/ppapi/tests/test_tcp_socket_private.h b/ppapi/tests/test_tcp_socket_private.h new file mode 100644 index 0000000..8cc8448 --- /dev/null +++ b/ppapi/tests/test_tcp_socket_private.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 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_PRIVATE_H_ +#define PAPPI_TESTS_TEST_TCP_SOCKET_PRIVATE_H_ + +#include + +#include "ppapi/c/pp_stdint.h" +#include "ppapi/tests/test_case.h" + +// TODO(viettrungluu): A rename is in progress and this reduces the amount of +// code that'll have to be changed. +namespace pp { +namespace flash { +class TCPSocket; +} +} +typedef pp::flash::TCPSocket TCPSocketPrivate; + +class TestTCPSocketPrivate : public TestCase { + public: + explicit TestTCPSocketPrivate(TestingInstance* instance); + + // TestCase implementation. + virtual bool Init(); + virtual void RunTest(); + + private: + std::string TestBasic(); + std::string TestReadWrite(); + std::string TestConnectAddress(); + + int32_t ReadFirstLineFromSocket(TCPSocketPrivate* socket, std::string* s); + int32_t WriteStringToSocket(TCPSocketPrivate* socket, const std::string& s); + + std::string host_; + uint16_t port_; +}; + +#endif // PAPPI_TESTS_TEST_TCP_SOCKET_PRIVATE_H_ -- cgit v1.1