Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / test / spawned_test_server / remote_test_server.cc
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 "net/test/spawned_test_server/remote_test_server.h"
6
7 #include <vector>
8
9 #include "base/base_paths.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/values.h"
18 #include "net/base/host_port_pair.h"
19 #include "net/base/net_errors.h"
20 #include "net/test/spawned_test_server/spawner_communicator.h"
21 #include "url/gurl.h"
22
23 namespace net {
24
25 namespace {
26
27 // To reduce the running time of tests, tests may be sharded across several
28 // devices. This means that it may be necessary to support multiple instances
29 // of the test server spawner and the Python test server simultaneously on the
30 // same host. Each pair of (test server spawner, Python test server) correspond
31 // to a single testing device.
32 // The mapping between the test server spawner and the individual Python test
33 // servers is written to a file on the device prior to executing any tests.
34 base::FilePath GetTestServerPortInfoFile() {
35 #if !defined(OS_ANDROID)
36   return base::FilePath("/tmp/net-test-server-ports");
37 #else
38   base::FilePath test_data_dir;
39   PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE, &test_data_dir);
40   return test_data_dir.Append("net-test-server-ports");
41 #endif
42 }
43
44 // Please keep it sync with dictionary SERVER_TYPES in testserver.py
45 std::string GetServerTypeString(BaseTestServer::Type type) {
46   switch (type) {
47     case BaseTestServer::TYPE_FTP:
48       return "ftp";
49     case BaseTestServer::TYPE_HTTP:
50     case BaseTestServer::TYPE_HTTPS:
51       return "http";
52     case BaseTestServer::TYPE_WS:
53     case BaseTestServer::TYPE_WSS:
54       return "ws";
55     case BaseTestServer::TYPE_TCP_ECHO:
56       return "tcpecho";
57     case BaseTestServer::TYPE_UDP_ECHO:
58       return "udpecho";
59     default:
60       NOTREACHED();
61   }
62   return std::string();
63 }
64
65 }  // namespace
66
67 RemoteTestServer::RemoteTestServer(Type type,
68                                    const std::string& host,
69                                    const base::FilePath& document_root)
70     : BaseTestServer(type, host),
71       spawner_server_port_(0) {
72   if (!Init(document_root))
73     NOTREACHED();
74 }
75
76 RemoteTestServer::RemoteTestServer(Type type,
77                                    const SSLOptions& ssl_options,
78                                    const base::FilePath& document_root)
79     : BaseTestServer(type, ssl_options),
80       spawner_server_port_(0) {
81   if (!Init(document_root))
82     NOTREACHED();
83 }
84
85 RemoteTestServer::~RemoteTestServer() {
86   Stop();
87 }
88
89 bool RemoteTestServer::Start() {
90   if (spawner_communicator_.get())
91     return true;
92   spawner_communicator_.reset(new SpawnerCommunicator(spawner_server_port_));
93
94   base::DictionaryValue arguments_dict;
95   if (!GenerateArguments(&arguments_dict))
96     return false;
97
98   // Append the 'server-type' argument which is used by spawner server to
99   // pass right server type to Python test server.
100   arguments_dict.SetString("server-type", GetServerTypeString(type()));
101
102   // Generate JSON-formatted argument string.
103   std::string arguments_string;
104   base::JSONWriter::Write(&arguments_dict, &arguments_string);
105   if (arguments_string.empty())
106     return false;
107
108   // Start the Python test server on the remote machine.
109   uint16 test_server_port;
110   if (!spawner_communicator_->StartServer(arguments_string,
111                                           &test_server_port)) {
112     return false;
113   }
114   if (0 == test_server_port)
115     return false;
116
117   // Construct server data to initialize BaseTestServer::server_data_.
118   base::DictionaryValue server_data_dict;
119   // At this point, the test server should be spawned on the host. Update the
120   // local port to real port of Python test server, which will be forwarded to
121   // the remote server.
122   server_data_dict.SetInteger("port", test_server_port);
123   std::string server_data;
124   base::JSONWriter::Write(&server_data_dict, &server_data);
125   if (server_data.empty() || !ParseServerData(server_data)) {
126     LOG(ERROR) << "Could not parse server_data: " << server_data;
127     return false;
128   }
129
130   return SetupWhenServerStarted();
131 }
132
133 bool RemoteTestServer::StartInBackground() {
134   NOTIMPLEMENTED();
135   return false;
136 }
137
138 bool RemoteTestServer::BlockUntilStarted() {
139   NOTIMPLEMENTED();
140   return false;
141 }
142
143 bool RemoteTestServer::Stop() {
144   if (!spawner_communicator_.get())
145     return true;
146   CleanUpWhenStoppingServer();
147   bool stopped = spawner_communicator_->StopServer();
148   // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one.
149   spawner_communicator_.reset(NULL);
150   return stopped;
151 }
152
153 // On Android, the document root in the device is not the same as the document
154 // root in the host machine where the test server is launched. So prepend
155 // DIR_SOURCE_ROOT here to get the actual path of document root on the Android
156 // device.
157 base::FilePath RemoteTestServer::GetDocumentRoot() const {
158   base::FilePath src_dir;
159   PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
160   return src_dir.Append(document_root());
161 }
162
163 bool RemoteTestServer::Init(const base::FilePath& document_root) {
164   if (document_root.IsAbsolute())
165     return false;
166
167   // Gets ports information used by test server spawner and Python test server.
168   int test_server_port = 0;
169
170   // Parse file to extract the ports information.
171   std::string port_info;
172   if (!base::ReadFileToString(GetTestServerPortInfoFile(), &port_info) ||
173       port_info.empty()) {
174     return false;
175   }
176
177   std::vector<std::string> ports;
178   base::SplitString(port_info, ':', &ports);
179   if (ports.size() != 2u)
180     return false;
181
182   // Verify the ports information.
183   base::StringToInt(ports[0], &spawner_server_port_);
184   if (!spawner_server_port_ ||
185       static_cast<uint32>(spawner_server_port_) >= kuint16max)
186     return false;
187
188   // Allow the test_server_port to be 0, which means the test server spawner
189   // will pick up a random port to run the test server.
190   base::StringToInt(ports[1], &test_server_port);
191   if (static_cast<uint32>(test_server_port) >= kuint16max)
192     return false;
193   SetPort(test_server_port);
194
195   // Unlike LocalTestServer, RemoteTestServer passes relative paths to the test
196   // server. The test server fails on empty strings in some configurations.
197   base::FilePath fixed_root = document_root;
198   if (fixed_root.empty())
199     fixed_root = base::FilePath(base::FilePath::kCurrentDirectory);
200   SetResourcePath(fixed_root, base::FilePath().AppendASCII("net")
201                                            .AppendASCII("data")
202                                            .AppendASCII("ssl")
203                                            .AppendASCII("certificates"));
204   return true;
205 }
206
207 }  // namespace net
208