Home | History | Annotate | Download | only in spawned_test_server
      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 
     17 namespace net {
     18 
     19 class 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.
     61 class 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   // Factory for creating the time-out task. This takes care of revoking
    134   // outstanding tasks when |this| is deleted.
    135   base::WeakPtrFactory<SpawnerCommunicator> weak_factory_;
    136 
    137   // Request context used by |cur_request_|.
    138   scoped_ptr<URLRequestContext> context_;
    139 
    140   // The current (in progress) request, or NULL.
    141   scoped_ptr<URLRequest> cur_request_;
    142 
    143   // Only gets/sets |is_running_| on user's thread to avoid race-condition.
    144   bool is_running_;
    145 
    146   DISALLOW_COPY_AND_ASSIGN(SpawnerCommunicator);
    147 };
    148 
    149 }  // namespace net
    150 
    151 #endif  // NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
    152