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.
5 #include "net/test/spawned_test_server/remote_test_server.h"
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"
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");
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");
44 // Please keep it sync with dictionary SERVER_TYPES in testserver.py
45 std::string
GetServerTypeString(BaseTestServer::Type type
) {
47 case BaseTestServer::TYPE_FTP
:
49 case BaseTestServer::TYPE_HTTP
:
50 case BaseTestServer::TYPE_HTTPS
:
52 case BaseTestServer::TYPE_WS
:
53 case BaseTestServer::TYPE_WSS
:
55 case BaseTestServer::TYPE_TCP_ECHO
:
57 case BaseTestServer::TYPE_UDP_ECHO
:
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
))
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
))
85 RemoteTestServer::~RemoteTestServer() {
89 bool RemoteTestServer::Start() {
90 if (spawner_communicator_
.get())
92 spawner_communicator_
.reset(new SpawnerCommunicator(spawner_server_port_
));
94 base::DictionaryValue arguments_dict
;
95 if (!GenerateArguments(&arguments_dict
))
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()));
102 // Generate JSON-formatted argument string.
103 std::string arguments_string
;
104 base::JSONWriter::Write(&arguments_dict
, &arguments_string
);
105 if (arguments_string
.empty())
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
)) {
114 if (0 == test_server_port
)
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
;
130 return SetupWhenServerStarted();
133 bool RemoteTestServer::StartInBackground() {
138 bool RemoteTestServer::BlockUntilStarted() {
143 bool RemoteTestServer::Stop() {
144 if (!spawner_communicator_
.get())
146 CleanUpWhenStoppingServer();
147 bool stopped
= spawner_communicator_
->StopServer();
148 // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one.
149 spawner_communicator_
.reset(NULL
);
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
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());
163 bool RemoteTestServer::Init(const base::FilePath
& document_root
) {
164 if (document_root
.IsAbsolute())
167 // Gets ports information used by test server spawner and Python test server.
168 int test_server_port
= 0;
170 // Parse file to extract the ports information.
171 std::string port_info
;
172 if (!base::ReadFileToString(GetTestServerPortInfoFile(), &port_info
) ||
177 std::vector
<std::string
> ports
;
178 base::SplitString(port_info
, ':', &ports
);
179 if (ports
.size() != 2u)
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
)
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
)
193 SetPort(test_server_port
);
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")
203 .AppendASCII("certificates"));