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