• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import xmlrpclib
8
9import common
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.common_lib.feedback import client
12
13
14# Query return codes.
15#
16QUERY_RET_SUCCESS = 0
17QUERY_RET_FAIL = 1
18QUERY_RET_ERROR = 2
19
20
21class 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
104class _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
139class 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
146class 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