Home | History | Annotate | Download | only in pyautolib
      1 #!/usr/bin/env python
      2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import cStringIO
      7 import os
      8 import pickle
      9 import socket
     10 import sys
     11 
     12 import pyauto
     13 
     14 class RemoteHost(object):
     15   """Class used as a host for tests that use the PyAuto RemoteProxy.
     16 
     17   This class fires up a listener which waits for a connection from a RemoteProxy
     18   and receives method call requests. Run python remote_host.py
     19   remote_host.RemoteHost.RunHost to start up a PyAuto remote instance that you
     20   can connect to and automate using pyauto.RemoteProxy.
     21   """
     22   def __init__(self, host, *args, **kwargs):
     23     self.StartSocketServer(host)
     24 
     25   def StartSocketServer(self, host):
     26     listening_socket = socket.socket()
     27     listening_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     28     listening_socket.bind(host)
     29     listening_socket.listen(1)
     30     print 'Listening for incoming connections on port %d.' % host[1]
     31     self._socket, address = listening_socket.accept()
     32     print 'Accepted connection from %s:%d.' % address
     33 
     34     while self.Connected():
     35       self._HandleRPC()
     36 
     37   def StopSocketServer(self):
     38     if self._socket:
     39       try:
     40         self._socket.shutdown(socket.SHUT_RDWR)
     41         self._socket.close()
     42       except socket.error:
     43         pass
     44       self._socket = None
     45 
     46   def Connected(self):
     47     return self._socket
     48 
     49   def CreateTarget(self, target_class):
     50     """Creates an instance of the specified class to serve as the RPC target.
     51 
     52     RPC calls can be made on the target.
     53     """
     54     self.target = target_class()
     55 
     56   def _HandleRPC(self):
     57     """Receives a method call request over the socket and executes the method.
     58 
     59     This method captures stdout and stderr for the duration of the method call,
     60     and sends those, the return value, and any thrown exceptions back to the
     61     RemoteProxy.
     62     """
     63     # Receive request.
     64     request = self._socket.recv(4096)
     65     if not request:
     66       self.StopSocketServer()
     67       return
     68     request = pickle.loads(request)
     69 
     70     # Redirect output to strings.
     71     old_stdout = sys.stdout
     72     old_stderr = sys.stderr
     73     sys.stdout = stdout = cStringIO.StringIO()
     74     sys.stderr = stderr = cStringIO.StringIO()
     75 
     76     # Make requested method call.
     77     result = None
     78     exception = None
     79     try:
     80       if getattr(self, request[0], None):
     81         result = getattr(self, request[0])(*request[1], **request[2])
     82       else:
     83         result = getattr(self.target, request[0])(*request[1], **request[2])
     84     except BaseException, e:
     85       exception = (e.__class__.__name__, str(e))
     86 
     87     # Put output back to the way it was before.
     88     sys.stdout = old_stdout
     89     sys.stderr = old_stderr
     90 
     91     # Package up and send the result of the method call.
     92     response = pickle.dumps((result, stdout.getvalue(), stderr.getvalue(),
     93                              exception))
     94     if self._socket.send(response) != len(response):
     95       self.StopSocketServer()
     96 
     97 
     98 if __name__ == '__main__':
     99   pyauto_suite = pyauto.PyUITestSuite(sys.argv)
    100   RemoteHost(('', 7410))
    101   del pyauto_suite
    102