blob: 6c56a1a4c95cfb362144a411ddba319419b5e9b1 [file] [log] [blame]
Steve Paik7861f4e2017-02-22 15:02:41 -08001#!/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.
Scott Randolph95fb30b2017-05-11 17:32:26 -070024 If the VehicleHalProto.proto file has changed, re-generate the python version using
25 a command of the form:
Steve Paik7861f4e2017-02-22 15:02:41 -080026 protoc -I=<proto_dir> --python_out=<out_dir> <proto_dir>/VehicleHalProto.proto
Scott Randolph95fb30b2017-05-11 17:32:26 -070027 For example:
28 protoDir=~/android/master/hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto
29 outDir=~/android/master/packages/services/Car/tools/emulator
30 protoc -I=$protoDir --python_out=$outDir $protoDir/VehicleHalProto.proto
Steve Paik7861f4e2017-02-22 15:02:41 -080031"""
32
Enrico Granata66d5a972017-04-05 16:48:08 -070033from __future__ import print_function
34
Steve Paik7861f4e2017-02-22 15:02:41 -080035# Suppress .pyc files
36import sys
37sys.dont_write_bytecode = True
38
39import VehicleHalProto_pb2
Chao Yand1a11b52017-10-04 13:54:03 -070040import vhal_consts_2_0
Steve Paik7861f4e2017-02-22 15:02:41 -080041import vhal_emulator
42import logging
43
44class VhalTest:
45 # Global vars
46 _badProps = [0, 0x3FFFFFFF] # List of bad properties to try for negative tests
47 _configs = 0 # List of configs from DUT
48 _log = 0 # Logger module
49 _vhal = 0 # Handle to VHAL object that communicates over socket to DUT
Steve Paik23608322017-08-02 18:24:29 -070050 # TODO: b/38203109 - Fix OBD2 values, implement handling for complex properties
51 _skipProps = [
Chao Yand1a11b52017-10-04 13:54:03 -070052 vhal_consts_2_0.VEHICLEPROPERTY_OBD2_LIVE_FRAME,
53 vhal_consts_2_0.VEHICLEPROPERTY_OBD2_FREEZE_FRAME,
54 vhal_consts_2_0.VEHICLEPROPERTY_OBD2_FREEZE_FRAME_INFO,
55 vhal_consts_2_0.VEHICLEPROPERTY_OBD2_FREEZE_FRAME_CLEAR,
56 vhal_consts_2_0.VEHICLEPROPERTY_VEHICLE_MAP_SERVICE,
57 vhal_consts_2_0.VEHICLEPROPERTY_WHEEL_TICK, # Need to support complex properties
Steve Paik23608322017-08-02 18:24:29 -070058 0x21E00666 # FakeDataControllingProperty - an internal test property
59 ]
Steve Paik7861f4e2017-02-22 15:02:41 -080060
61 def _getMidpoint(self, minVal, maxVal):
62 retVal = minVal + (maxVal - minVal)/2
63 return retVal
64
65 # Generates a test value based on the config
66 def _generateTestValue(self, cfg, idx, origValue):
67 valType = cfg.value_type
68 if valType in self._types.TYPE_STRING:
69 testValue = "test string"
70 elif valType in self._types.TYPE_BYTES:
71 # Generate array of integers counting from 0
Enrico Granata66d5a972017-04-05 16:48:08 -070072 testValue = list(range(len(origValue)))
Chao Yand1a11b52017-10-04 13:54:03 -070073 elif valType == vhal_consts_2_0.VEHICLEPROPERTYTYPE_BOOLEAN:
Steve Paik7861f4e2017-02-22 15:02:41 -080074 testValue = origValue ^ 1
75 elif valType in self._types.TYPE_INT32:
76 try:
77 testValue = self._getMidpoint(cfg.area_configs[idx].min_int32_value,
78 cfg.area_configs[idx].max_int32_value)
79 except:
80 # min/max values aren't set. Set a hard-coded value
81 testValue = 123
82 elif valType in self._types.TYPE_INT64:
83 try:
84 testValue = self._getMidpoint(cfg.area_configs[idx].min_int64_value,
85 cfg.area_configs[idx].max_int64_value)
86 except:
87 # min/max values aren't set. Set a large hard-coded value
88 testValue = 1 << 50
89 elif valType in self._types.TYPE_FLOAT:
90 try:
91 testValue = self._getMidpoint(cfg.area_configs[idx].min_float_value,
92 cfg.area_configs[idx].max_float_value)
93 except:
94 # min/max values aren't set. Set a hard-coded value
95 testValue = 123.456
96 # Truncate float to 5 decimal places
97 testValue = "%.5f" % testValue
98 testValue = float(testValue)
99 else:
Steve Paik23608322017-08-02 18:24:29 -0700100 self._log.error("generateTestValue: valType=0x%X is not handled", valType)
Steve Paik7861f4e2017-02-22 15:02:41 -0800101 testValue = None
102 return testValue
103
104 # Helper function to extract values array from rxMsg
105 def _getValueFromMsg(self, rxMsg):
106 # Check to see only one property value is returned
107 if len(rxMsg.value) != 1:
108 self._log.error("getValueFromMsg: Received invalid value")
109 value = None
110 else:
111 valType = rxMsg.value[0].value_type
Aditi Nagaraj18a3e8d2018-02-07 14:49:17 -0800112 try:
113 if valType in self._types.TYPE_STRING:
114 value = rxMsg.value[0].string_value
115 elif valType in self._types.TYPE_BYTES:
116 value = rxMsg.value[0].bytes_value
117 elif valType == vhal_consts_2_0.VEHICLEPROPERTYTYPE_BOOLEAN:
118 value = rxMsg.value[0].int32_values[0]
119 elif valType in self._types.TYPE_INT32:
120 value = rxMsg.value[0].int32_values[0]
121 elif valType in self._types.TYPE_INT64:
122 value = rxMsg.value[0].int64_values[0]
123 elif valType in self._types.TYPE_FLOAT:
124 value = rxMsg.value[0].float_values[0]
125 # Truncate float to 5 decimal places
126 value = "%.5f" % value
127 value = float(value)
128 else:
129 self._log.error("getValueFromMsg: valType=0x%X is not handled", valType)
130 value = None
131 except IndexError:
132 self._log.error("getValueFromMsg: Received malformed message: %s", str(rxMsg))
133 value = None
134 return value
135
136 def _validateVmsMessage(self, rxMsg):
137 return (len(rxMsg.value) == 1 and rxMsg.value[0].value_type in self._types.TYPE_MIXED and
138 len(rxMsg.value[0].int32_values) > 0 and
139 vhal_consts_2_0.VMSMESSAGETYPE_SUBSCRIBE <= rxMsg.value[0].int32_values[0]
140 <= vhal_consts_2_0.VMSMESSAGETYPE_LAST_VMS_MESSAGE_TYPE)
141
142 def _getVmsMessageTypeFromMsg(self, rxMsg):
143 if self._validateVmsMessage(rxMsg):
144 value = rxMsg.value[0].int32_values[
145 vhal_consts_2_0.VMSBASEMESSAGEINTEGERVALUESINDEX_MESSAGE_TYPE]
146 else:
147 self._log.error("getVmsMessageTypeFromMsg: Received invalid message")
148 value = None
Steve Paik7861f4e2017-02-22 15:02:41 -0800149 return value
150
151 # Helper function to receive a message and validate the type and status
152 # retVal = 1 if no errors
153 # retVal = 0 if errors detected
154 def _rxMsgAndValidate(self, expectedType, expectedStatus):
155 retVal = 1
156 rxMsg = self._vhal.rxMsg()
157 if rxMsg.msg_type != expectedType:
Steve Paik23608322017-08-02 18:24:29 -0700158 self._log.error("rxMsg Type expected: 0x%X, received: 0x%X", expectedType, rxMsg.msg_type)
Steve Paik7861f4e2017-02-22 15:02:41 -0800159 retVal = 0
160 if rxMsg.status != expectedStatus:
Steve Paik23608322017-08-02 18:24:29 -0700161 self._log.error("rxMsg Status expected: 0x%X, received: 0x%X", expectedStatus, rxMsg.status)
Steve Paik7861f4e2017-02-22 15:02:41 -0800162 retVal = 0
163 return rxMsg, retVal
164
165 # Calls getConfig() on each individual property ID and verifies it matches with the config
166 # received in getConfigAll()
167 def testGetConfig(self):
168 self._log.info("Starting testGetConfig...")
169 for cfg in self._configs:
Steve Paik23608322017-08-02 18:24:29 -0700170 self._log.debug(" Getting config for propId=0x%X", cfg.prop)
Steve Paik7861f4e2017-02-22 15:02:41 -0800171 self._vhal.getConfig(cfg.prop)
172 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_CONFIG_RESP,
173 VehicleHalProto_pb2.RESULT_OK)
174 if retVal:
175 if rxMsg.config[0] != cfg:
Steve Paik23608322017-08-02 18:24:29 -0700176 self._log.error("testGetConfig failed. prop=0x%X, expected:\n%s\nreceived:\n%s",
Steve Paik7861f4e2017-02-22 15:02:41 -0800177 cfg.prop, str(cfg), str(rxMsg.config))
178 self._log.info(" Finished testGetConfig!")
179
180 # Calls getConfig() on invalid property ID and verifies it generates an error
181 def testGetBadConfig(self):
182 self._log.info("Starting testGetBadConfig...")
183 for prop in self._badProps:
Steve Paik23608322017-08-02 18:24:29 -0700184 self._log.debug(" Testing bad propId=0x%X", prop)
Steve Paik7861f4e2017-02-22 15:02:41 -0800185 self._vhal.getConfig(prop)
186 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_CONFIG_RESP,
187 VehicleHalProto_pb2.ERROR_INVALID_PROPERTY)
188 if retVal:
189 for cfg in rxMsg.config:
Steve Paik23608322017-08-02 18:24:29 -0700190 self._log.error("testGetBadConfig prop=0x%X, expected:None, received:\n%s",
Steve Paik7861f4e2017-02-22 15:02:41 -0800191 cfg.prop, str(rxMsg.config))
192 self._log.info(" Finished testGetBadConfig!")
193
194 def testGetPropertyAll(self):
195 self._log.info("Starting testGetPropertyAll...")
196 self._vhal.getPropertyAll()
197 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_ALL_RESP,
198 VehicleHalProto_pb2.RESULT_OK)
199 if retVal == 0:
200 self._log.error("testGetPropertyAll: Failed to receive proper rxMsg")
201
202 # TODO: Finish writing this test. What should we be testing, anyway?
203
204 self._log.info(" Finished testGetPropertyAll!")
205
206 def testGetSet(self):
207 self._log.info("Starting testGetSet()...")
208 for cfg in self._configs:
Steve Paik23608322017-08-02 18:24:29 -0700209 if cfg.prop in self._skipProps:
210 # Skip properties that cannot be handled properly by this test.
211 self._log.warning(" Skipping propId=0x%X", cfg.prop)
212 continue
213
Steve Paik7861f4e2017-02-22 15:02:41 -0800214 areas = cfg.supported_areas
215 idx = -1
216 while (idx == -1) | (areas != 0):
217 idx += 1
218 # Get the area to test
219 area = areas & (areas -1)
220 area ^= areas
221
222 # Remove the area from areas
223 areas ^= area
224
Steve Paik23608322017-08-02 18:24:29 -0700225 self._log.debug(" Testing propId=0x%X, area=0x%X", cfg.prop, area)
Steve Paik7861f4e2017-02-22 15:02:41 -0800226
227 # Get the current value
228 self._vhal.getProperty(cfg.prop, area)
229 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP,
230 VehicleHalProto_pb2.RESULT_OK)
231
232 # Save the original value
233 origValue = self._getValueFromMsg(rxMsg)
234 if origValue == None:
Steve Paik23608322017-08-02 18:24:29 -0700235 self._log.error("testGetSet: Could not get value for prop=0x%X, area=0x%X",
Steve Paik7861f4e2017-02-22 15:02:41 -0800236 cfg.prop, area)
237 continue
238
239 # Generate the test value
240 testValue = self._generateTestValue(cfg, idx, origValue)
241 if testValue == None:
Steve Paik23608322017-08-02 18:24:29 -0700242 self._log.error("testGetSet: Cannot generate test value for prop=0x%X, area=0x%X",
Steve Paik7861f4e2017-02-22 15:02:41 -0800243 cfg.prop, area)
244 continue
245
246 # Send the new value
247 self._vhal.setProperty(cfg.prop, area, testValue)
248 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_RESP,
Steve Paik23608322017-08-02 18:24:29 -0700249 VehicleHalProto_pb2.RESULT_OK)
Steve Paik7861f4e2017-02-22 15:02:41 -0800250
251 # Get the new value and verify it
252 self._vhal.getProperty(cfg.prop, area)
253 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP,
254 VehicleHalProto_pb2.RESULT_OK)
255 newValue = self._getValueFromMsg(rxMsg)
256 if newValue != testValue:
Steve Paik23608322017-08-02 18:24:29 -0700257 self._log.error("testGetSet: set failed for propId=0x%X, area=0x%X", cfg.prop, area)
Enrico Granata66d5a972017-04-05 16:48:08 -0700258 print("testValue= ", testValue, "newValue= ", newValue)
Steve Paik7861f4e2017-02-22 15:02:41 -0800259 continue
260
261 # Reset the value to what it was before
262 self._vhal.setProperty(cfg.prop, area, origValue)
263 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_RESP,
264 VehicleHalProto_pb2.RESULT_OK)
265 self._log.info(" Finished testGetSet()!")
266
267 def testGetBadProperty(self):
268 self._log.info("Starting testGetBadProperty()...")
269 for prop in self._badProps:
Steve Paik23608322017-08-02 18:24:29 -0700270 self._log.debug(" Testing bad propId=0x%X", prop)
Steve Paik7861f4e2017-02-22 15:02:41 -0800271 self._vhal.getProperty(prop, 0)
272 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP,
273 VehicleHalProto_pb2.ERROR_INVALID_PROPERTY)
274 if retVal:
275 for value in rxMsg.value:
Steve Paik23608322017-08-02 18:24:29 -0700276 self._log.error("testGetBadProperty prop=0x%X, expected:None, received:\n%s",
Steve Paik7861f4e2017-02-22 15:02:41 -0800277 prop, str(rxMsg))
278 self._log.info(" Finished testGetBadProperty()!")
279
280 def testSetBadProperty(self):
281 self._log.info("Starting testSetBadProperty()...")
282 area = 1
283 value = 100
284 for prop in self._badProps:
Steve Paik23608322017-08-02 18:24:29 -0700285 self._log.debug(" Testing bad propId=0x%X", prop)
Steve Paik7861f4e2017-02-22 15:02:41 -0800286 area = area + 1
287 value = value + 1
288 try:
289 self._vhal.setProperty(prop, area, value)
Steve Paik23608322017-08-02 18:24:29 -0700290 self._log.error("testGetBadProperty failed. prop=0x%X, area=0x%X, value=%d",
Steve Paik7861f4e2017-02-22 15:02:41 -0800291 prop, area, value)
292 except ValueError as e:
293 # Received expected error
294 pass
295 self._log.info(" Finished testSetBadProperty()!")
296
Aditi Nagaraj18a3e8d2018-02-07 14:49:17 -0800297 def testGetVmsAvailability(self):
298 self._log.info("Starting testVms()...")
299
300 # Request the availability from the VmsCore.
301 value = {'int32_values' : [vhal_consts_2_0.VMSMESSAGETYPE_AVAILABILITY_REQUEST] }
302 self._vhal.setProperty(
303 vhal_consts_2_0.VEHICLEPROPERTY_VEHICLE_MAP_SERVICE, 0, value)
304
305 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_RESP,
306 VehicleHalProto_pb2.RESULT_OK)
307
308 # The Vms Core should immediately respond
309 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.SET_PROPERTY_ASYNC,
310 VehicleHalProto_pb2.RESULT_OK)
311
312 if self._getVmsMessageTypeFromMsg(rxMsg) != vhal_consts_2_0.VMSMESSAGETYPE_AVAILABILITY_RESPONSE:
313 self._log.error("testVms: VmsCore did not respond with AvailabilityResponse: %s", str(rxMsg))
314
315
316 # Test that we can get the property on command
317 self._vhal.getProperty(
318 vhal_consts_2_0.VEHICLEPROPERTY_VEHICLE_MAP_SERVICE, 0)
319 rxMsg, retVal = self._rxMsgAndValidate(VehicleHalProto_pb2.GET_PROPERTY_RESP,
320 VehicleHalProto_pb2.RESULT_OK)
321
322 if self._getVmsMessageTypeFromMsg(rxMsg) != vhal_consts_2_0.VMSMESSAGETYPE_AVAILABILITY_RESPONSE:
323 self._log.error("testVms: VmsCore did not respond with AvailabilityResponse: %s", str(rxMsg))
324 else:
325 # Parse Availability Response
326 layers = rxMsg.value[0].int32_values[
327 vhal_consts_2_0.VMSAVAILABILITYSTATEINTEGERVALUESINDEX_NUMBER_OF_ASSOCIATED_LAYERS]
328 index = vhal_consts_2_0.VMSAVAILABILITYSTATEINTEGERVALUESINDEX_LAYERS_START
329 numPublishersIndex = vhal_consts_2_0.VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_VERSION
330 self._log.info("testVms: %d available layers", layers)
331 for layer in xrange(layers):
332 self._log.info("testVms: Available layer: %s",
333 rxMsg.value[0].int32_values[index:index+numPublishersIndex])
334 index += numPublishersIndex + 1 + rxMsg.value[0].int32_values[index+numPublishersIndex]
335
336 if len(rxMsg.value[0].int32_values) != index:
337 self._log.error("testVms: Malformed AvailabilityResponse: index: %d %s", index, str(rxMsg))
338
Steve Paik7861f4e2017-02-22 15:02:41 -0800339 def runTests(self):
340 self.testGetConfig()
341 self.testGetBadConfig()
342 self.testGetPropertyAll()
343 self.testGetSet()
344 self.testGetBadProperty()
345 self.testSetBadProperty()
Aditi Nagaraj18a3e8d2018-02-07 14:49:17 -0800346 self.testGetVmsAvailability()
Steve Paik7861f4e2017-02-22 15:02:41 -0800347 # Add new tests here to be run
348
349
350 # Valid logLevels:
351 # CRITICAL 50
352 # ERRROR 40
353 # WARNING 30
354 # INFO 20
355 # DEBUG 10
356 # NOTSET 0
357 def __init__(self, types, logLevel=20):
358 self._types = types
359 # Configure the logger
360 logging.basicConfig()
361 self._log = logging.getLogger('vhal_emulator_test')
362 self._log.setLevel(logLevel)
363 # Start the VHAL Emulator
364 self._vhal = vhal_emulator.Vhal(types)
365 # Get the list of configs
366 self._vhal.getConfigAll()
367 self._configs = self._vhal.rxMsg().config
368
369if __name__ == '__main__':
Chao Yand1a11b52017-10-04 13:54:03 -0700370 v = VhalTest(vhal_consts_2_0.vhal_types_2_0)
Steve Paik7861f4e2017-02-22 15:02:41 -0800371 v.runTests()