1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/tests/test_host_resolver.h"
6
7#include "ppapi/cpp/host_resolver.h"
8#include "ppapi/cpp/net_address.h"
9#include "ppapi/cpp/tcp_socket.h"
10#include "ppapi/cpp/var.h"
11#include "ppapi/tests/test_utils.h"
12#include "ppapi/tests/testing_instance.h"
13
14REGISTER_TEST_CASE(HostResolver);
15
16TestHostResolver::TestHostResolver(TestingInstance* instance)
17    : TestCase(instance) {
18}
19
20bool TestHostResolver::Init() {
21  bool host_resolver_is_available = pp::HostResolver::IsAvailable();
22  if (!host_resolver_is_available)
23    instance_->AppendError("PPB_HostResolver interface not available");
24
25  bool tcp_socket_is_available = pp::TCPSocket::IsAvailable();
26  if (!tcp_socket_is_available)
27    instance_->AppendError("PPB_TCPSocket interface not available");
28
29  bool init_host_port =
30      GetLocalHostPort(instance_->pp_instance(), &host_, &port_);
31  if (!init_host_port)
32    instance_->AppendError("Can't init host and port");
33
34  return host_resolver_is_available &&
35      tcp_socket_is_available &&
36      init_host_port &&
37      CheckTestingInterface() &&
38      EnsureRunningOverHTTP();
39}
40
41void TestHostResolver::RunTests(const std::string& filter) {
42  RUN_TEST(Empty, filter);
43  RUN_CALLBACK_TEST(TestHostResolver, Resolve, filter);
44  RUN_CALLBACK_TEST(TestHostResolver, ResolveIPv4, filter);
45}
46
47std::string TestHostResolver::SyncConnect(
48    pp::TCPSocket* socket,
49    const pp::NetAddress& address) {
50  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
51  callback.WaitForResult(socket->Connect(address, callback.GetCallback()));
52  CHECK_CALLBACK_BEHAVIOR(callback);
53  ASSERT_EQ(PP_OK, callback.result());
54  PASS();
55}
56
57std::string TestHostResolver::SyncRead(pp::TCPSocket* socket,
58                                       char* buffer,
59                                       int32_t num_bytes,
60                                       int32_t* bytes_read) {
61  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
62  callback.WaitForResult(
63      socket->Read(buffer, num_bytes, callback.GetCallback()));
64  CHECK_CALLBACK_BEHAVIOR(callback);
65  ASSERT_EQ(num_bytes, callback.result());
66  *bytes_read = callback.result();
67  PASS();
68}
69
70std::string TestHostResolver::SyncWrite(pp::TCPSocket* socket,
71                                        const char* buffer,
72                                        int32_t num_bytes,
73                                        int32_t* bytes_written) {
74  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
75  callback.WaitForResult(
76      socket->Write(buffer, num_bytes, callback.GetCallback()));
77  CHECK_CALLBACK_BEHAVIOR(callback);
78  ASSERT_EQ(num_bytes, callback.result());
79  *bytes_written = callback.result();
80  PASS();
81}
82
83std::string TestHostResolver::CheckHTTPResponse(pp::TCPSocket* socket,
84                                                const std::string& request,
85                                                const std::string& response) {
86  int32_t rv = 0;
87  ASSERT_SUBTEST_SUCCESS(
88      SyncWrite(socket, request.c_str(), request.size(), &rv));
89  std::vector<char> response_buffer(response.size());
90  ASSERT_SUBTEST_SUCCESS(
91      SyncRead(socket, &response_buffer[0], response.size(), &rv));
92  std::string actual_response(&response_buffer[0], rv);
93  if (response != actual_response) {
94    return "CheckHTTPResponse failed, expected: " + response +
95        ", actual: " + actual_response;
96  }
97  PASS();
98}
99
100std::string TestHostResolver::SyncResolve(
101    pp::HostResolver* host_resolver,
102    const std::string& host,
103    uint16_t port,
104    const PP_HostResolver_Hint& hint) {
105  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
106  callback.WaitForResult(
107      host_resolver->Resolve(host.c_str(), port, hint, callback.GetCallback()));
108  CHECK_CALLBACK_BEHAVIOR(callback);
109  ASSERT_EQ(PP_OK, callback.result());
110  PASS();
111}
112
113std::string TestHostResolver::ParameterizedTestResolve(
114    const PP_HostResolver_Hint& hint) {
115  pp::HostResolver host_resolver(instance_);
116
117  ASSERT_SUBTEST_SUCCESS(SyncResolve(&host_resolver, host_, port_, hint));
118
119  size_t size = host_resolver.GetNetAddressCount();
120  ASSERT_TRUE(size >= 1);
121
122  pp::NetAddress address;
123  for (size_t i = 0; i < size; ++i) {
124    address = host_resolver.GetNetAddress(i);
125    ASSERT_NE(0, address.pp_resource());
126
127    pp::TCPSocket socket(instance_);
128    ASSERT_SUBTEST_SUCCESS(SyncConnect(&socket, address));
129    ASSERT_SUBTEST_SUCCESS(CheckHTTPResponse(&socket,
130                                             "GET / HTTP/1.0\r\n\r\n",
131                                             "HTTP"));
132    socket.Close();
133  }
134
135  address = host_resolver.GetNetAddress(size);
136  ASSERT_EQ(0, address.pp_resource());
137  pp::Var canonical_name = host_resolver.GetCanonicalName();
138  ASSERT_TRUE(canonical_name.is_string());
139
140  ASSERT_SUBTEST_SUCCESS(SyncResolve(&host_resolver, canonical_name.AsString(),
141                                     port_, hint));
142  size = host_resolver.GetNetAddressCount();
143  ASSERT_TRUE(size >= 1);
144
145  PASS();
146}
147
148std::string TestHostResolver::TestEmpty() {
149  pp::HostResolver host_resolver(instance_);
150  ASSERT_EQ(0, host_resolver.GetNetAddressCount());
151  pp::NetAddress address = host_resolver.GetNetAddress(0);
152  ASSERT_EQ(0, address.pp_resource());
153
154  PASS();
155}
156
157std::string TestHostResolver::TestResolve() {
158  PP_HostResolver_Hint hint;
159  hint.family = PP_NETADDRESS_FAMILY_UNSPECIFIED;
160  hint.flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
161  return ParameterizedTestResolve(hint);
162}
163
164std::string TestHostResolver::TestResolveIPv4() {
165  PP_HostResolver_Hint hint;
166  hint.family = PP_NETADDRESS_FAMILY_IPV4;
167  hint.flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
168  return ParameterizedTestResolve(hint);
169}
170