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