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 
     37 
     38     def _make_query_call(self, query_num, query_method, **kwargs):
     39         """Make an RPC query call (used by query objects).
     40 
     41         @param query_num: The unique query identifying number.
     42         @param query_method: The query method being called.
     43 
     44         @raise xmlrpclib.Error: An error during RPC call processing.
     45         """
     46         # XML-RPC does not support kwargs, so we just pass it as a dictionary.
     47         return self._rpc_proxy.query_call(self._client_id, query_num,
     48                                           query_method, kwargs)
     49 
     50 
     51     # Interface overrides.
     52     #
     53     def _initialize_impl(self, _test, _host):
     54         """Initializes the feedback object.
     55 
     56         Initializes an XML-RPC proxy and registers the client at the remote end.
     57 
     58         @param _test: An object representing the test case (unused).
     59         @param _host: An object representing the DUT (unused).
     60         """
     61         self._rpc_proxy = xmlrpclib.ServerProxy('http://%s' % self._remote_addr)
     62         try:
     63             self._rpc_proxy.new_client(self._client_id)
     64         except xmlrpclib.Error as e:
     65             raise error.TestError('Feedback client registration error: %s' % e)
     66 
     67 
     68     def _new_query_impl(self, query_id):
     69         """Instantiates a new query.
     70 
     71         @param query_id: A query identifier.
     72 
     73         @return A query object.
     74         """
     75         if query_id in client.INPUT_QUERIES:
     76             query_cls = InputQuery
     77         elif query_id in client.OUTPUT_QUERIES:
     78             query_cls = OutputQuery
     79         else:
     80             raise error.TestError('Unknown query (%s)' % query_id)
     81 
     82         # Create, register and return a new query.
     83         self._query_num += 1
     84         try:
     85             self._rpc_proxy.new_query(self._client_id, query_id, self._query_num)
     86         except xmlrpclib.Error as e:
     87             raise error.TestError('Feedback query registration error: %s' % e)
     88         return query_cls(self, self._query_num)
     89 
     90 
     91     def _finalize_impl(self):
     92         """Finalizes the feedback object."""
     93         try:
     94             self._rpc_proxy.delete_client(self._client_id)
     95         except xmlrpclib.Error as e:
     96             raise error.TestError(
     97                     'Feedback client deregistration error: %s' % e)
     98 
     99 
    100 class _Query(object):
    101     """Human tester feedback query base class."""
    102 
    103     def __init__(self, client, query_num):
    104         super(_Query, self).__init__()
    105         self.client = client
    106         self.query_num = query_num
    107 
    108 
    109     def _make_query_call(self, query_method, **kwargs):
    110         try:
    111             ret, desc = self.client._make_query_call(self.query_num,
    112                                                      query_method, **kwargs)
    113         except xmlrpclib.Error as e:
    114             ret, desc = QUERY_RET_ERROR, str(e)
    115 
    116         if ret == QUERY_RET_SUCCESS:
    117             return
    118         if ret == QUERY_RET_FAIL:
    119             raise error.TestFail('Tester feedback request failed: %s' % desc)
    120         if ret == QUERY_RET_ERROR:
    121             raise error.TestError('Tester feedback request error: %s' % desc)
    122         raise error.TestError('Unknown feedback call return code (%s)' % ret)
    123 
    124 
    125     # Interface overrides.
    126     #
    127     def _prepare_impl(self, **kwargs):
    128         self._make_query_call('prepare', **kwargs)
    129 
    130 
    131     def _validate_impl(self, **kwargs):
    132         self._make_query_call('validate', **kwargs)
    133 
    134 
    135 class OutputQuery(_Query, client.OutputQuery):
    136     """Human tester feedback output query."""
    137 
    138     def __init__(self, client, query_num):
    139         super(OutputQuery, self).__init__(client, query_num)
    140 
    141 
    142 class InputQuery(_Query, client.InputQuery):
    143     """Human tester feedback input query."""
    144 
    145     def __init__(self, client, query_num):
    146         super(InputQuery, self).__init__(client, query_num)
    147 
    148 
    149     # Interface override.
    150     #
    151     def _emit_impl(self):
    152         self._make_query_call('emit')
    153