• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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