| OLD | NEW |
| (Empty) |
| 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/remote_test_server.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/base_paths.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/files/file_path.h" | |
| 12 #include "base/json/json_writer.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/string_number_conversions.h" | |
| 16 #include "base/strings/string_split.h" | |
| 17 #include "base/values.h" | |
| 18 #include "googleurl/src/gurl.h" | |
| 19 #include "net/base/host_port_pair.h" | |
| 20 #include "net/base/net_errors.h" | |
| 21 #include "net/test/spawner_communicator.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 (!file_util::ReadFileToString(GetTestServerPortInfoFile(), | |
| 173 &port_info) || | |
| 174 port_info.empty()) { | |
| 175 return false; | |
| 176 } | |
| 177 | |
| 178 std::vector<std::string> ports; | |
| 179 base::SplitString(port_info, ':', &ports); | |
| 180 if (ports.size() != 2u) | |
| 181 return false; | |
| 182 | |
| 183 // Verify the ports information. | |
| 184 base::StringToInt(ports[0], &spawner_server_port_); | |
| 185 if (!spawner_server_port_ || | |
| 186 static_cast<uint32>(spawner_server_port_) >= kuint16max) | |
| 187 return false; | |
| 188 | |
| 189 // Allow the test_server_port to be 0, which means the test server spawner | |
| 190 // will pick up a random port to run the test server. | |
| 191 base::StringToInt(ports[1], &test_server_port); | |
| 192 if (static_cast<uint32>(test_server_port) >= kuint16max) | |
| 193 return false; | |
| 194 SetPort(test_server_port); | |
| 195 | |
| 196 SetResourcePath(document_root, base::FilePath().AppendASCII("net") | |
| 197 .AppendASCII("data") | |
| 198 .AppendASCII("ssl") | |
| 199 .AppendASCII("certificates")); | |
| 200 return true; | |
| 201 } | |
| 202 | |
| 203 } // namespace net | |
| 204 | |
| OLD | NEW |