1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# 4# Copyright 2017 Google Inc. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19""" 20 This module tests the Vehicle HAL using adb socket. 21 22 Protocol Buffer: 23 This module relies on VehicleHalProto_pb2.py being in sync with the protobuf in the VHAL. 24 If the VehicleHalProto.proto file has changed, re-generate the python version using: 25 26 protoc -I=<proto_dir> --python_out=<out_dir> <proto_dir>/VehicleHalProto.proto 27 protoc -I=proto --python_out=proto proto/VehicleHalProto.proto 28""" 29 30# Suppress .pyc files 31import sys 32sys.dont_write_bytecode = True 33 34import VehicleHalProto_pb2 35import vhal_consts_2_0 36import vhal_emulator 37import logging 38 39class VhalTest: 40 # Global vars 41 _badProps = [0, 0x3FFFFFFF] # List of bad properties to try for negative tests 42 _configs = 0 # List of configs from DUT 43 _log = 0 # Logger module 44 _vhal = 0 # Handle to VHAL object that communicates over socket to DUT 45 46 def _getMidpoint(self, minVal, maxVal): 47 retVal = minVal + (maxVal - minVal)/2 48 return retVal 49 50 # Generates a test value based on the config 51 def _generateTestValue(self, cfg, idx, origValue): 52 valType = cfg.value_type 53 if valType in self._types.TYPE_STRING: 54 testValue = "test string" 55 elif valType in self._types.TYPE_BYTES: 56 # Generate array of integers counting from 0 57 testValue = range(len(origValue)) 58 elif valType == vhal_consts_2_0.VEHICLE_VALUE_TYPE_BOOLEAN: 59 testValue = origValue ^ 1 60 elif valType in self._types.TYPE_INT32: 61 try: 62 testValue = self._getMidpoint(cfg.area_configs[idx].min_int32_value, 63 cfg.area_configs[idx].max_int32_value) 64 except: 65 # min/max values aren't set. Set a hard-coded value 66 testValue = 123 67 elif valType in self._types.TYPE_INT64: 68 try: 69 testValue = self._getMidpoint(cfg.area_configs[idx].min_int64_value, 70 cfg.area_configs[idx].max_int64_value) 71 except: 72 # min/max values aren't set. Set a large hard-coded value 73 testValue = 1 << 50 74 elif valType in self._types.TYPE_FLOAT: 75 try: 76 testValue = self._getMidpoint(cfg.area_configs[idx].min_float_value, 77 cfg.area_configs[idx].max_float_value) 78 except: 79 # min/max values aren't set. Set a hard-coded value 80 testValue = 123.456 81 # Truncate float to 5 decimal places 82 testValue = "%.5f" % testValue 83 testValue = float(testValue) 84 else: 85 self._log.error("generateTestValue: valType=%d is not handled", valType) 86 testValue = None 87 return testValue 88 89 # Helper function to extract values array from rxMsg 90 def _getValueFromMsg(self, rxMsg): 91 # Check to see only one property value is returned 92 if len(rxMsg.value) != 1: 93 self._log.error("getValueFromMsg: Received invalid value") 94 value = None 95 else: 96 valType = rxMsg.value[0].value_type 97 if valType in self._types.TYPE_STRING: 98 value = rxMsg.value[0].string_value 99 elif valType in self._types.TYPE_BYTES: 100 value = rxMsg.value[0].bytes_value 101 elif valType == vhal_consts_2_0.VEHICLE_VALUE_TYPE_BOOLEAN: 102 value = rxMsg.value[0].int32_values[0] 103 elif valType in self._types.TYPE_INT32: 104 value = rxMsg.value[0].int32_values[0] 105 elif valType in self._types.TYPE_INT64: 106 value = rxMsg.value[0].int64_values[0] 107 elif valType in self._types.TYPE_FLOAT: 108 value = rxMsg.value[0].float_values[0] 109 # Truncate float to 5 decimal places 110 value = "%.5f" % value 111 value = float(value) 112 else: 113 self._log.error("getValuesFromMsg: valType=%d is not handled", valType) 114 value = None 115 return value 116 117 # Helper function to receive a message and validate the type and status 118 # retVal = 1 if no errors 119 # retVal = 0 if errors detected 120 def _rxMsgAndValidate(self, expectedType, expectedStatus): 121 retVal = 1 122 rxMsg = self._vhal.rxMsg() 123 if rxMsg.msg_type != expectedType: 124 self._log.error("rxMsg Type expected: %d, received: %d", expectedType, rxMsg.msg_type) 125 retVal = 0 126 if rxMsg.status != expectedStatus: 127 self._log.error("rxMsg Status expected: %d, received: %d", expectedStatus, rxMsg.status) 128 retVal = 0 129 return rxMsg, retVal 130 131 # Calls getConfig() on each individual property ID and verifies it matches with the config 132 # received in getConfigAll() 133 def testGetConfig(self): 134 self._log.info("Starting testGetConfig...") 135 for cfg in self._configs: 136 self._log.debug(" Getting config for propId=%d", cfg.prop) 137 self._vhal.getConfig(cfg.prop) 138 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_CONFIG_RESP, 139 VehicleHalProto_pb2.RESULT_OK) 140 if retVal: 141 if rxMsg.config[0] != cfg: 142 self._log.error("testGetConfig failed. prop=%d, expected:\n%s\nreceived:\n%s", 143 cfg.prop, str(cfg), str(rxMsg.config)) 144 self._log.info(" Finished testGetConfig!") 145 146 # Calls getConfig() on invalid property ID and verifies it generates an error 147 def testGetBadConfig(self): 148 self._log.info("Starting testGetBadConfig...") 149 for prop in self._badProps: 150 self._log.debug(" Testing bad propId=%d", prop) 151 self._vhal.getConfig(prop) 152 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_CONFIG_RESP, 153 VehicleHalProto_pb2.ERROR_INVALID_PROPERTY) 154 if retVal: 155 for cfg in rxMsg.config: 156 self._log.error("testGetBadConfig prop=%d, expected:None, received:\n%s", 157 cfg.prop, str(rxMsg.config)) 158 self._log.info(" Finished testGetBadConfig!") 159 160 def testGetPropertyAll(self): 161 self._log.info("Starting testGetPropertyAll...") 162 self._vhal.getPropertyAll() 163 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_ALL_RESP, 164 VehicleHalProto_pb2.RESULT_OK) 165 if retVal == 0: 166 self._log.error("testGetPropertyAll: Failed to receive proper rxMsg") 167 168 # TODO: Finish writing this test. What should we be testing, anyway? 169 170 self._log.info(" Finished testGetPropertyAll!") 171 172 def testGetSet(self): 173 self._log.info("Starting testGetSet()...") 174 for cfg in self._configs: 175 areas = cfg.supported_areas 176 idx = -1 177 while (idx == -1) | (areas != 0): 178 idx += 1 179 # Get the area to test 180 area = areas & (areas -1) 181 area ^= areas 182 183 # Remove the area from areas 184 areas ^= area 185 186 self._log.debug(" Testing propId=%d, area=%d", cfg.prop, area) 187 188 # Get the current value 189 self._vhal.getProperty(cfg.prop, area) 190 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP, 191 VehicleHalProto_pb2.RESULT_OK) 192 193 # Save the original value 194 origValue = self._getValueFromMsg(rxMsg) 195 if origValue == None: 196 self._log.error("testGetSet: Could not get value for prop=%d, area=%d", 197 cfg.prop, area) 198 continue 199 200 # Generate the test value 201 testValue = self._generateTestValue(cfg, idx, origValue) 202 if testValue == None: 203 self._log.error("testGetSet: Cannot generate test value for prop=%d, area=%d", 204 cfg.prop, area) 205 continue 206 207 # Send the new value 208 self._vhal.setProperty(cfg.prop, area, testValue) 209 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_RESP, 210 VehicleHalProto_pb2.RESULT_OK) 211 212 # Get the new value and verify it 213 self._vhal.getProperty(cfg.prop, area) 214 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP, 215 VehicleHalProto_pb2.RESULT_OK) 216 newValue = self._getValueFromMsg(rxMsg) 217 if newValue != testValue: 218 self._log.error("testGetSet: set failed for propId=%d, area=%d", cfg.prop, area) 219 print "testValue= ", testValue, "newValue= ", newValue 220 continue 221 222 # Reset the value to what it was before 223 self._vhal.setProperty(cfg.prop, area, origValue) 224 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_RESP, 225 VehicleHalProto_pb2.RESULT_OK) 226 self._log.info(" Finished testGetSet()!") 227 228 def testGetBadProperty(self): 229 self._log.info("Starting testGetBadProperty()...") 230 for prop in self._badProps: 231 self._log.debug(" Testing bad propId=%d", prop) 232 self._vhal.getProperty(prop, 0) 233 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP, 234 VehicleHalProto_pb2.ERROR_INVALID_PROPERTY) 235 if retVal: 236 for value in rxMsg.value: 237 self._log.error("testGetBadProperty prop=%d, expected:None, received:\n%s", 238 prop, str(rxMsg)) 239 self._log.info(" Finished testGetBadProperty()!") 240 241 def testSetBadProperty(self): 242 self._log.info("Starting testSetBadProperty()...") 243 area = 1 244 value = 100 245 for prop in self._badProps: 246 self._log.debug(" Testing bad propId=%d", prop) 247 area = area + 1 248 value = value + 1 249 try: 250 self._vhal.setProperty(prop, area, value) 251 self._log.error("testGetBadProperty failed. prop=%d, area=%d, value=%d", 252 prop, area, value) 253 except ValueError as e: 254 # Received expected error 255 pass 256 self._log.info(" Finished testSetBadProperty()!") 257 258 def runTests(self): 259 self.testGetConfig() 260 self.testGetBadConfig() 261 self.testGetPropertyAll() 262 self.testGetSet() 263 self.testGetBadProperty() 264 self.testSetBadProperty() 265 # Add new tests here to be run 266 267 268 # Valid logLevels: 269 # CRITICAL 50 270 # ERRROR 40 271 # WARNING 30 272 # INFO 20 273 # DEBUG 10 274 # NOTSET 0 275 def __init__(self, types, logLevel=20): 276 self._types = types 277 # Configure the logger 278 logging.basicConfig() 279 self._log = logging.getLogger('vhal_emulator_test') 280 self._log.setLevel(logLevel) 281 # Start the VHAL Emulator 282 self._vhal = vhal_emulator.Vhal(types) 283 # Get the list of configs 284 self._vhal.getConfigAll() 285 self._configs = self._vhal.rxMsg().config 286 287if __name__ == '__main__': 288 v = VhalTest(vhal_consts_2_0.vhal_types_2_0) 289 v.runTests() 290 291