blob: 19e8240ed38829e17d487bb9ea107954b009fa00 [file] [log] [blame]
Gilad Arnolde57b7e82015-12-08 10:26:13 -08001# 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"""Interactive feedback layer abstraction."""
6
7from autotest_lib.client.common_lib import error
8
9
10# All known queries.
11#
12# Audio playback and recording testing.
13QUERY_AUDIO_PLAYBACK_SILENT = 0
14QUERY_AUDIO_PLAYBACK_AUDIBLE = 1
15QUERY_AUDIO_RECORDING = 2
16# Motion sensor testing.
17QUERY_MOTION_RESTING = 10
18QUERY_MOTION_MOVING = 11
19# USB keyboard plugging and typing.
20QUERY_KEYBOARD_PLUG = 20
21QUERY_KEYBOARD_TYPE = 21
22# GPIO write/read testing.
23QUERY_GPIO_WRITE = 30
24QUERY_GPIO_READ = 31
25# On-board light testing.
26QUERY_LIGHT_ON = 40
27# TODO(garnold) Camera controls testing.
28#QUERY_CAMERA_???
29# Power management testing.
30QUERY_POWER_WAKEUP = 60
31
32
33# Feedback client definition.
34#
35class Client(object):
36 """Interface for an interactive feedback layer."""
37
38 def __init__(self):
39 self._initialized = False
40 self._finalized = False
41
42
43 def _check_active(self):
44 """Ensure that the client was initialized and not finalized."""
45 if not self._initialized:
46 raise error.TestError('Client was not initialized')
47 if self._finalized:
48 raise error.TestError('Client was already finalized')
49
50
51 def __enter__(self):
52 self._check_active()
53 return self
54
55
56 def __exit__(self, ex_type, ex_val, ex_tb):
57 self.finalize()
58
59
60 def initialize(self, test, host):
61 """Initializes the feedback object.
62
63 This method should be called once prior to any other call.
64
65 @param test: An object representing the test case.
66 @param host: An object representing the DUT.
67
68 @raise TestError: There was an error during initialization.
69 """
70 if self._initialized:
71 raise error.TestError('Client was already initialized')
72 if self._finalized:
73 raise error.TestError('Client was already finalized')
74 self._initialize_impl(test, host)
75 self._initialized = True
76 return self
77
78
79 def _initialize_impl(self, test, host):
80 """Implementation of feedback client initialization.
81
82 This should be implemented in concrete subclasses.
83 """
84 raise NotImplementedError
85
86
87 def new_query(self, query_id):
88 """Instantiates a new query.
89
90 @param query_id: A query identifier (see QUERY_ constants above).
91
92 @return A query object.
93
94 @raise TestError: Query is invalid or not supported.
95 """
96 self._check_active()
97 return self._new_query_impl(query_id)
98
99
100 def _new_query_impl(self, query_id):
101 """Implementation of new query instantiation.
102
103 This should be implemented in concrete subclasses.
104 """
105 raise NotImplementedError
106
107
108 def finalize(self):
109 """Finalizes the feedback object.
110
111 This method should be called once when done using the client.
112
113 @raise TestError: There was an error while finalizing the client.
114 """
115 self._check_active()
116 self._finalize_impl()
117 self._finalized = True
118
119
120 def _finalize_impl(self):
121 """Implementation of feedback client finalization.
122
123 This should be implemented in concrete subclasses.
124 """
125 raise NotImplementedError
126
127
128# Feedback query definitions.
129#
130class _Query(object):
131 """Interactive feedback query base class.
132
133 This class is further derived and should not be inherited directly.
134 """
135
136 def __init__(self):
137 self._prepare_called = False
138 self._validate_called = False
139
140
141 def prepare(self, **kwargs):
142 """Prepares the tester for providing or capturing feedback.
143
144 @raise TestError: Query preparation failed.
145 """
146 if self._prepare_called:
147 raise error.TestError('Prepare was already called')
148 self._prepare_impl(**kwargs)
149 self._prepare_called = True
150
151
152 def _prepare_impl(self, **kwargs):
153 """Implementation of query preparation logic.
154
155 This should be implemented in concrete subclasses.
156 """
157 raise NotImplementedError
158
159
160 def validate(self, **kwargs):
161 """Validates the interactive input/output result.
162
163 This enforces that the method is called at most once, then delegates
164 to an underlying implementation method.
165
166 @raise TestError: An error occurred during validation.
167 @raise TestFail: Query validation failed.
168 """
169 if self._validate_called:
170 raise error.TestError('Validate was already called')
171 self._validate_impl(**kwargs)
172 self._validate_called = True
173
174
175 def _validate_impl(self, **kwargs):
176 """Implementation of query validation logic.
177
178 This should be implemented in concrete subclasses.
179 """
180 raise NotImplementedError
181
182
183class OutputQuery(_Query):
184 """Interface for an output interactive feedback query.
185
186 This class mandates that prepare() is called prior to validate().
187 Subclasses should override implementations of _prepare_impl() and
188 _validate_impl().
189 """
190
191 def __init__(self):
192 super(OutputQuery, self).__init__()
193
194
195 def validate(self, **kwargs):
196 """Validates the interactive input/output result.
197
198 This enforces the precondition and delegates to the base method.
199
200 @raise TestError: An error occurred during validation.
201 @raise TestFail: Query validation failed.
202 """
203 if not self._prepare_called:
204 raise error.TestError('Prepare was not called')
205 super(OutputQuery, self).validate(**kwargs)
206
207
208class InputQuery(_Query):
209 """Interface for an input interactive feedback query.
210
211 This class mandates that prepare() is called first, then emit(), and
212 finally validate(). Subclasses should override implementations of
213 _prepare_impl(), _emit_impl() and _validate_impl().
214 """
215
216 def __init__(self):
217 super(InputQuery, self).__init__()
218 self._emit_called = False
219
220
221 def validate(self, **kwargs):
222 """Validates the interactive input/output result.
223
224 This enforces the precondition and delegates to the base method.
225
226 @raise TestError: An error occurred during validation.
227 @raise TestFail: Query validation failed.
228 """
229 if not self._emit_called:
230 raise error.TestError('Emit was not called')
231 super(InputQuery, self).validate(**kwargs)
232
233
234 def emit(self):
235 """Instructs the tester to emit a feedback to be captured by the test.
236
237 This enforces the precondition and ensures the method is called at most
238 once, then delegates to an underlying implementation method.
239
240 @raise TestError: An error occurred during emission.
241 """
242 if not self._prepare_called:
243 raise error.TestError('Prepare was not called')
244 if self._emit_called:
245 raise error.TestError('Emit was already called')
246 self._emit_impl()
247 self._emit_called = True
248
249
250 def _emit_impl(self):
251 """Implementation of query emission logic.
252
253 This should be implemented in concrete subclasses.
254 """
255 raise NotImplementedError