1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyFloat;
26 import static org.mockito.Mockito.atLeast;
27 import static org.mockito.Mockito.verify;
28 
29 import static java.lang.Integer.toHexString;
30 
31 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
32 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
33 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
34 import android.os.SystemClock;
35 import android.util.Log;
36 
37 import androidx.test.ext.junit.runners.AndroidJUnit4;
38 import androidx.test.filters.MediumTest;
39 
40 import com.android.car.vehiclehal.VehiclePropValueBuilder;
41 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
42 
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.Map;
50 import java.util.Set;
51 
52 /**
53  * Test for {@link com.android.car.CarPropertyService}
54  */
55 @RunWith(AndroidJUnit4.class)
56 @MediumTest
57 public class CarPropertyServiceTest extends MockedCarTestBase {
58     private static final String TAG = CarPropertyServiceTest.class.getSimpleName();
59 
60     private final Map<Integer, VehiclePropValue> mDefaultPropValues = new HashMap<>();
61 
62     private CarPropertyService mService;
63 
CarPropertyServiceTest()64     public CarPropertyServiceTest() {
65         // Unusual default values for the vehicle properties registered to listen via
66         // CarPropertyService.registerListener. Unusual default values like the car is in motion,
67         // night mode is on, or the car is low on fuel.
68         mDefaultPropValues.put(VehicleProperty.GEAR_SELECTION,
69                 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
70                 .addIntValue(VehicleGear.GEAR_DRIVE)
71                 .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
72         mDefaultPropValues.put(VehicleProperty.PARKING_BRAKE_ON,
73                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
74                 .setBooleanValue(false)
75                 .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
76         mDefaultPropValues.put(VehicleProperty.PERF_VEHICLE_SPEED,
77                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
78                 .addFloatValue(30.0f)
79                 .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
80         mDefaultPropValues.put(VehicleProperty.NIGHT_MODE,
81                 VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
82                 .setBooleanValue(true)
83                 .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
84     }
85 
86     @Override
configureMockedHal()87     protected synchronized void configureMockedHal() {
88         PropertyHandler handler = new PropertyHandler();
89         for (VehiclePropValue value : mDefaultPropValues.values()) {
90             handler.onPropertySet(value);
91             addProperty(value.prop, handler);
92         }
93     }
94 
95     @Override
spyOnBeforeCarImplInit()96     protected synchronized void spyOnBeforeCarImplInit() {
97         mService = CarLocalServices.getService(CarPropertyService.class);
98         assertThat(mService).isNotNull();
99         spyOn(mService);
100     }
101 
102     @Test
testMatchesDefaultPropertyValues()103     public void testMatchesDefaultPropertyValues() {
104         Set<Integer> expectedPropIds = mDefaultPropValues.keySet();
105         ArgumentCaptor<Integer> propIdCaptor = ArgumentCaptor.forClass(Integer.class);
106         verify(mService, atLeast(expectedPropIds.size())).registerListener(
107                 propIdCaptor.capture(), anyFloat(), any());
108 
109         Set<Integer> actualPropIds = new HashSet<Integer>(propIdCaptor.getAllValues());
110         assertWithMessage("Should assign default values for missing property IDs")
111                 .that(expectedPropIds).containsAtLeastElementsIn(actualPropIds.toArray());
112         assertWithMessage("Missing registerListener for property IDs")
113                 .that(actualPropIds).containsAtLeastElementsIn(expectedPropIds.toArray());
114     }
115 
116     private static final class PropertyHandler implements VehicleHalPropertyHandler {
117         private final Map<Integer, VehiclePropValue> mMap = new HashMap<>();
118 
119         @Override
onPropertySet(VehiclePropValue value)120         public synchronized void onPropertySet(VehiclePropValue value) {
121             mMap.put(value.prop, value);
122         }
123 
124         @Override
onPropertyGet(VehiclePropValue value)125         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
126             assertWithMessage("onPropertyGet missing property: %s", toHexString(value.prop))
127                     .that(mMap).containsKey(value.prop);
128             VehiclePropValue currentValue = mMap.get(value.prop);
129             return currentValue != null ? currentValue : value;
130         }
131 
132         @Override
onPropertySubscribe(int property, float sampleRate)133         public synchronized void onPropertySubscribe(int property, float sampleRate) {
134             assertWithMessage("onPropertySubscribe missing property: %s", toHexString(property))
135                     .that(mMap).containsKey(property);
136             Log.d(TAG, "onPropertySubscribe property "
137                     + property + " sampleRate " + sampleRate);
138         }
139 
140         @Override
onPropertyUnsubscribe(int property)141         public synchronized void onPropertyUnsubscribe(int property) {
142             assertWithMessage("onPropertyUnsubscribe missing property: %s", toHexString(property))
143                     .that(mMap).containsKey(property);
144             Log.d(TAG, "onPropertyUnSubscribe property " + property);
145         }
146     }
147 }
148