Home | History | Annotate | Download | only in feedback
      1 # Copyright 2016 The Chromium OS 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 """Feedback client implementation for interacting with a human tester."""
      6 
      7 import xmlrpclib
      8 
      9 import common
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.client.common_lib.feedback import client
     12 
     13 
     14 # Query return codes.
     15 #
     16 QUERY_RET_SUCCESS = 0
     17 QUERY_RET_FAIL = 1
     18 QUERY_RET_ERROR = 2
     19 
     20 
     21 class Client(client.Client):
     22     """Human tester feedback implementation."""
     23 
     24     def __init__(self, test_name, dut_name, remote_addr):
     25         """Constructs the client object.
     26 
     27         @param test_name: The name of the test.
     28         @param dut_name: The name of the DUT.
     29         @param remote_addr: The 'name:port' of the remote feedback service host.
     30         """
     31         super(Client, self).__init__()
     32         self._client_id = '%s:%s' % (test_name, dut_name)
     33         self._remote_addr = remote_addr
     34         self._query_num = 0
     35         self._rpc_proxy = None
     36         self.tmp_dir = None
     37         self.dut_tmp_dir = None
     38 
     39 
     40     def _make_query_call(self, query_num, query_method, **kwargs):
     41         """Make an RPC query call (used by query objects).
     42 
     43         @param query_num: The unique query identifying number.
     44         @param query_method: The query method being called.
     45 
     46         @raise xmlrpclib.Error: An error during RPC call processing.
     47         """
     48         # XML-RPC does not support kwargs, so we just pass it as a dictionary.
     49         return self._rpc_proxy.query_call(self._client_id, query_num,
     50                                           query_method, kwargs)
     51 
     52 
     53     # Interface overrides.
     54     #
     55     def _initialize_impl(self, test, host):
     56         """Initializes the feedback object.
     57 
     58         Initializes an XML-RPC proxy and registers the client at the remote end.
     59 
     60         @param test: An object representing the test case.
     61         @param host: An object representing the DUT.
     62         """
     63         self._rpc_proxy = xmlrpclib.ServerProxy('http://%s' % self._remote_addr)
     64         try:
     65             self._rpc_proxy.new_client(self._client_id)
     66         except xmlrpclib.Error as e:
     67             raise error.TestError('Feedback client registration error: %s' % e)
     68         self.tmp_dir = test.tmpdir
     69         self.dut_tmp_dir = host.get_tmp_dir()
     70 
     71 
     72     def _new_query_impl(self, query_id):
     73         """Instantiates a new query.
     74 
     75         @param query_id: A query identifier.
     76 
     77         @return A query object.
     78         """
     79         if query_id in client.INPUT_QUERIES:
     80             query_cls = InputQuery
     81         elif query_id in client.OUTPUT_QUERIES:
     82             query_cls = OutputQuery
     83         else:
     84             raise error.TestError('Unknown query (%s)' % query_id)
     85 
     86         # Create, register and return a new query.
     87         self._query_num += 1
     88         try:
     89             self._rpc_proxy.new_query(self._client_id, query_id, self._query_num)
     90         except xmlrpclib.Error as e:
     91             raise error.TestError('Feedback query registration error: %s' % e)
     92         return query_cls(self, self._query_num)
     93 
     94 
     95     def _finalize_impl(self):
     96         """Finalizes the feedback object."""
     97         try:
     98             self._rpc_proxy.delete_client(self._client_id)
     99         except xmlrpclib.Error as e:
    100             raise error.TestError(
    101                     'Feedback client deregistration error: %s' % e)
    102 
    103 
    104 class _Query(object):
    105     """Human tester feedback query base class."""
    106 
    107     def __init__(self, client, query_num):
    108         super(_Query, self).__init__()
    109         self.client = client
    110         self.query_num = query_num
    111 
    112 
    113     def _make_query_call(self, query_method, **kwargs):
    114         try:
    115             ret, desc = self.client._make_query_call(self.query_num,
    116                                                      query_method, **kwargs)
    117         except xmlrpclib.Error as e:
    118             ret, desc = QUERY_RET_ERROR, str(e)
    119 
    120         if ret == QUERY_RET_SUCCESS:
    121             return
    122         if ret == QUERY_RET_FAIL:
    123             raise error.TestFail('Tester feedback request failed: %s' % desc)
    124         if ret == QUERY_RET_ERROR:
    125             raise error.TestError('Tester feedback request error: %s' % desc)
    126         raise error.TestError('Unknown feedback call return code (%s)' % ret)
    127 
    128 
    129     # Interface overrides.
    130     #
    131     def _prepare_impl(self, **kwargs):
    132         self._make_query_call('prepare', **kwargs)
    133 
    134 
    135     def _validate_impl(self, **kwargs):
    136         self._make_query_call('validate', **kwargs)
    137 
    138 
    139 class OutputQuery(_Query, client.OutputQuery):
    140     """Human tester feedback output query."""
    141 
    142     def __init__(self, client, query_num):
    143         super(OutputQuery, self).__init__(client, query_num)
    144 
    145 
    146 class InputQuery(_Query, client.InputQuery):
    147     """Human tester feedback input query."""
    148 
    149     def __init__(self, client, query_num):
    150         super(InputQuery, self).__init__(client, query_num)
    151 
    152 
    153     # Interface override.
    154     #
    155     def _emit_impl(self):
    156         self._make_query_call('emit')
    157