1// Copyright (c) 2012 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#ifndef NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
6#define NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
7
8#include <string>
9
10#include "base/basictypes.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/weak_ptr.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/threading/thread.h"
15#include "net/url_request/url_request.h"
16
17namespace net {
18
19class ScopedPortException;
20
21// SpawnerCommunicator communicates with a spawner server that runs on a
22// remote system.
23//
24// The test server used by unit tests is written in Python. However, Android
25// does not support running Python code, so the test server cannot run on the
26// same device running unit tests.
27//
28// The actual test server is executed on the host machine, while the unit tests
29// themselves continue running on the device. To control the test server on the
30// host machine, a second HTTP server is started, the spawner server, which
31// controls the life cycle of remote test servers. Calls to start/kill the
32// net::SpawnedTestServer are then redirected to the spawner server via
33// this spawner communicator.
34//
35// Currently only three commands are supported by spawner.
36//
37// (1) Start Python test server, format is:
38// Path: "/start".
39// Method: "POST".
40// Data to server: all arguments needed to launch the Python test server, in
41//   JSON format.
42// Data from server: a JSON dict includes the following two field if success,
43//   "port": the port the Python test server actually listen on that.
44//   "message": must be "started".
45//
46// (2) Kill Python test server, format is:
47// Path: "/kill".
48// Method: "GET".
49// Data to server: None.
50// Data from server: String "killed" returned if success.
51//
52// (3) Ping Python test server to see whether it is alive, format is:
53// Path: "/ping".
54// Method: "GET".
55// Data to server: None.
56// Data from server: String "ready" returned if success.
57//
58// The internal I/O thread is required by net stack to perform net I/O.
59// The Start/StopServer methods block the caller thread until result is
60// fetched from spawner server or timed-out.
61class SpawnerCommunicator : public net::URLRequest::Delegate {
62 public:
63  explicit SpawnerCommunicator(uint16 port);
64  virtual ~SpawnerCommunicator();
65
66  // Starts an instance of the Python test server on the host/ machine.
67  // If successfully started, returns true, setting |*port| to the port
68  // on the local machine that can be used to communicate with the remote
69  // test server.
70  bool StartServer(const std::string& arguments,
71                   uint16* port) WARN_UNUSED_RESULT;
72
73  bool StopServer() WARN_UNUSED_RESULT;
74
75 private:
76  // Starts the IO thread. Called on the user thread.
77  void StartIOThread();
78
79  // Shuts down the remote test server spawner. Called on the user thread.
80  void Shutdown();
81
82  // Waits for the server response on IO thread. Called on the user thread.
83  void WaitForResponse();
84
85  // Sends a command to the test server over HTTP, returning the result code
86  // |*result_code| and response data in |*data_received|, those two arguments
87  // must be not NULL, otherwise the method returns immediately without sending
88  // the |command|. If |post_data| is empty, HTTP GET will be used to send
89  // |command|. If |post_data| is non-empty, performs an HTTP POST.
90  // This method is called on the user thread.
91  void SendCommandAndWaitForResult(const std::string& command,
92                                   const std::string& post_data,
93                                   int* result_code,
94                                   std::string* data_received);
95
96  // Performs the command sending on the IO thread. Called on the IO thread.
97  void SendCommandAndWaitForResultOnIOThread(const std::string& command,
98                                             const std::string& post_data,
99                                             int* result_code,
100                                             std::string* data_received);
101
102  // URLRequest::Delegate methods. Called on the IO thread.
103  virtual void OnResponseStarted(URLRequest* request) OVERRIDE;
104  virtual void OnReadCompleted(URLRequest* request, int num_bytes) OVERRIDE;
105
106  // Reads Result from the response. Called on the IO thread.
107  void ReadResult(URLRequest* request);
108
109  // Called on the IO thread upon completion of the spawner command.
110  void OnSpawnerCommandCompleted(URLRequest* request);
111
112  // Callback on the IO thread for time-out task of request with id |id|.
113  void OnTimeout(int id);
114
115  // A thread to communicate with test_spawner server.
116  base::Thread io_thread_;
117
118  // WaitableEvent to notify whether the communication is done.
119  base::WaitableEvent event_;
120
121  // The local port used to communicate with the TestServer spawner. This is
122  // used to control the startup and shutdown of the Python TestServer running
123  // on the remote machine. On Android, this port will be redirected to the
124  // same port on the host machine.
125  const uint16 port_;
126
127  // Helper to add |port_| to the list of the globally explicitly allowed ports.
128  scoped_ptr<ScopedPortException> allowed_port_;
129
130  // The next ID to use for |cur_request_| (monotonically increasing).
131  int next_id_;
132
133  // Request context used by |cur_request_|.
134  scoped_ptr<URLRequestContext> context_;
135
136  // The current (in progress) request, or NULL.
137  scoped_ptr<URLRequest> cur_request_;
138
139  // Only gets/sets |is_running_| on user's thread to avoid race-condition.
140  bool is_running_;
141
142  // Factory for creating the time-out task. This takes care of revoking
143  // outstanding tasks when |this| is deleted.
144  base::WeakPtrFactory<SpawnerCommunicator> weak_factory_;
145
146  DISALLOW_COPY_AND_ASSIGN(SpawnerCommunicator);
147};
148
149}  // namespace net
150
151#endif  // NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
152