blob: 6ef12052d12cadb05c7680fbb1082cbe5e915fcc [file] [log] [blame]
Pavel Maltseve2603e32016-10-25 16:03:23 -07001/*
2 * Copyright (C) 2016 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#include <unordered_map>
18#include <iostream>
19
20#include <gtest/gtest.h>
21
22#include <vehicle_hal_manager/VehiclePropConfigIndex.h>
23#include <VehicleHal.h>
24#include <vehicle_hal_manager/VehicleHalManager.h>
Pavel Maltsevdb179c52016-10-27 15:43:06 -070025#include <utils/SystemClock.h>
Pavel Maltseve2603e32016-10-25 16:03:23 -070026#include "vehicle_hal_manager/SubscriptionManager.h"
27
28#include "VehicleHalTestUtils.h"
29
30namespace android {
31namespace hardware {
32namespace vehicle {
33namespace V2_0 {
34
35namespace {
36
37using namespace std::placeholders;
38
Pavel Maltsevdb179c52016-10-27 15:43:06 -070039constexpr char kCarMake[] = "Default Car";
40constexpr int kRetriablePropMockedAttempts = 3;
41
Pavel Maltseve2603e32016-10-25 16:03:23 -070042class MockedVehicleHal : public VehicleHal {
43public:
44 MockedVehicleHal() {
45 mConfigs.assign(std::begin(kVehicleProperties),
46 std::end(kVehicleProperties));
47 }
48
49 std::vector<VehiclePropConfig> listProperties() override {
50 return mConfigs;
51 }
52
Pavel Maltsevdb179c52016-10-27 15:43:06 -070053 VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
54 StatusCode* outStatus) override {
55 *outStatus = StatusCode::OK;
56 VehiclePropValuePtr pValue;
57 VehicleProperty property = requestedPropValue.prop;
58 int32_t areaId = requestedPropValue.areaId;
59
60 switch (property) {
61 case VehicleProperty::INFO_MAKE:
62 pValue = getValuePool()->obtainString(kCarMake);
63 break;
64 case VehicleProperty::INFO_FUEL_CAPACITY:
65 if (fuelCapacityAttemptsLeft-- > 0) {
66 // Emulate property not ready yet.
67 *outStatus = StatusCode::TRY_AGAIN;
68 } else {
69 pValue = getValuePool()->obtainFloat(42.42);
70 }
71 break;
72 default:
73 auto key = makeKey(property, areaId);
74 if (mValues.count(key) == 0) {
75 ALOGW("");
76 }
77 pValue = getValuePool()->obtain(mValues[key]);
78 }
79
80 if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
81 pValue->prop = property;
82 pValue->areaId = areaId;
83 pValue->timestamp = elapsedRealtimeNano();
84 }
85
86 return pValue;
Pavel Maltseve2603e32016-10-25 16:03:23 -070087 }
88
Pavel Maltsevdb179c52016-10-27 15:43:06 -070089 StatusCode set(const VehiclePropValue& propValue) override {
90 if (VehicleProperty::MIRROR_FOLD == propValue.prop
91 && mirrorFoldAttemptsLeft-- > 0) {
92 return StatusCode::TRY_AGAIN;
93 }
94
95 mValues[makeKey(propValue)] = propValue;
96 return StatusCode::OK;
Pavel Maltseve2603e32016-10-25 16:03:23 -070097 }
98
Pavel Maltsevdb179c52016-10-27 15:43:06 -070099 StatusCode subscribe(VehicleProperty property,
Pavel Maltseve2603e32016-10-25 16:03:23 -0700100 int32_t areas,
101 float sampleRate) override {
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700102 return StatusCode::OK;
Pavel Maltseve2603e32016-10-25 16:03:23 -0700103 }
104
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700105 StatusCode unsubscribe(VehicleProperty property) override {
106 return StatusCode::OK;
Pavel Maltseve2603e32016-10-25 16:03:23 -0700107 }
108
109 void sendPropEvent(recyclable_ptr<VehiclePropValue> value) {
110 doHalEvent(std::move(value));
111 }
112
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700113 void sendHalError(StatusCode error, VehicleProperty property,
114 int32_t areaId) {
115 doHalPropertySetError(error, property, areaId);
116 }
117
118public:
119 int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts;
120 int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts;
121
122private:
123 int64_t makeKey(const VehiclePropValue& v) const {
124 return makeKey(v.prop, v.areaId);
125 }
126
127 int64_t makeKey(VehicleProperty prop, int32_t area) const {
128 return (static_cast<int64_t>(prop) << 32) | area;
129 }
130
Pavel Maltseve2603e32016-10-25 16:03:23 -0700131private:
132 std::vector<VehiclePropConfig> mConfigs;
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700133 std::unordered_map<int64_t, VehiclePropValue> mValues;
Pavel Maltseve2603e32016-10-25 16:03:23 -0700134};
135
136class VehicleHalManagerTest : public ::testing::Test {
137protected:
138 void SetUp() override {
139 hal.reset(new MockedVehicleHal);
140 manager.reset(new VehicleHalManager(hal.get()));
141
142 objectPool = hal->getValuePool();
143 }
144
145 void TearDown() override {
146 manager.reset(nullptr);
147 hal.reset(nullptr);
148 }
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700149public:
150 void invokeGet(VehicleProperty property, int32_t areaId) {
151 VehiclePropValue requestedValue {};
152 requestedValue.prop = property;
153 requestedValue.areaId = areaId;
154
155 invokeGet(requestedValue);
156 }
157
158 void invokeGet(const VehiclePropValue& requestedPropValue) {
159 actualValue = VehiclePropValue {}; // reset previous values
160
161 StatusCode refStatus;
162 VehiclePropValue refValue;
163 bool called = false;
164 manager->get(requestedPropValue, [&refStatus, &refValue, &called]
165 (StatusCode status, const VehiclePropValue& value) {
166 refStatus = status;
167 refValue = value;
168 called = true;
169 });
170 ASSERT_TRUE(called) << "callback wasn't called for prop: "
171 << enumToHexString(requestedPropValue.prop);
172
173 actualValue = refValue;
174 actualStatusCode = refStatus;
175 }
Pavel Maltseve2603e32016-10-25 16:03:23 -0700176
177public:
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700178 VehiclePropValue actualValue;
179 StatusCode actualStatusCode;
180
Pavel Maltseve2603e32016-10-25 16:03:23 -0700181 VehiclePropValuePool* objectPool;
182 std::unique_ptr<MockedVehicleHal> hal;
183 std::unique_ptr<VehicleHalManager> manager;
184};
185
Pavel Maltseve2603e32016-10-25 16:03:23 -0700186TEST_F(VehicleHalManagerTest, getPropConfigs) {
187 hidl_vec<VehicleProperty> properties = init_hidl_vec(
188 { VehicleProperty::HVAC_FAN_SPEED,VehicleProperty::INFO_MAKE} );
189 bool called = false;
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700190
Pavel Maltseve2603e32016-10-25 16:03:23 -0700191 manager->getPropConfigs(properties,
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700192 [&called] (StatusCode status,
193 const hidl_vec<VehiclePropConfig>& c) {
194 ASSERT_EQ(StatusCode::OK, status);
Pavel Maltseve2603e32016-10-25 16:03:23 -0700195 ASSERT_EQ(2u, c.size());
196 called = true;
197 });
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700198
Pavel Maltseve2603e32016-10-25 16:03:23 -0700199 ASSERT_TRUE(called); // Verify callback received.
200
201 called = false;
202 manager->getPropConfigs(init_hidl_vec({VehicleProperty::HVAC_FAN_SPEED}),
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700203 [&called] (StatusCode status,
204 const hidl_vec<VehiclePropConfig>& c) {
205 ASSERT_EQ(StatusCode::OK, status);
Pavel Maltseve2603e32016-10-25 16:03:23 -0700206 ASSERT_EQ(1u, c.size());
207 ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0]));
208 called = true;
209 });
210 ASSERT_TRUE(called); // Verify callback received.
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700211
212 // TODO(pavelm): add case case when property was not declared.
Pavel Maltseve2603e32016-10-25 16:03:23 -0700213}
214
215TEST_F(VehicleHalManagerTest, getAllPropConfigs) {
216 bool called = false;
217 manager->getAllPropConfigs(
218 [&called] (const hidl_vec<VehiclePropConfig>& propConfigs) {
219 ASSERT_EQ(arraysize(kVehicleProperties), propConfigs.size());
220
221 for (size_t i = 0; i < propConfigs.size(); i++) {
222 ASSERT_EQ(toString(kVehicleProperties[i]),
223 toString(propConfigs[i]));
224 }
225 called = true;
226 });
227 ASSERT_TRUE(called); // Verify callback received.
228}
229
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700230TEST_F(VehicleHalManagerTest, halErrorEvent) {
231 const VehicleProperty PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
232
233 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
234
235 hidl_vec<SubscribeOptions> options = init_hidl_vec(
236 {
237 SubscribeOptions {
238 .propId = PROP,
239 .flags = SubscribeFlags::DEFAULT
240 },
241 });
242
243 StatusCode res = manager->subscribe(cb, options);
244 ASSERT_EQ(StatusCode::OK, res);
245
246 hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
247}
248
Pavel Maltseve2603e32016-10-25 16:03:23 -0700249TEST_F(VehicleHalManagerTest, subscribe) {
250 const VehicleProperty PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
251
252 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
253
254 hidl_vec<SubscribeOptions> options = init_hidl_vec(
255 {
256 SubscribeOptions {
257 .propId = PROP,
258 .flags = SubscribeFlags::DEFAULT
259 },
260 });
261
262 StatusCode res = manager->subscribe(cb, options);
263 ASSERT_EQ(StatusCode::OK, res);
264
265 auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
266 unsubscribedValue->prop = VehicleProperty::HVAC_FAN_SPEED;
267
268 hal->sendPropEvent(std::move(unsubscribedValue));
269 auto& receivedEnvents = cb->getReceivedEvents();
270
271 ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700272 << receivedEnvents.size()
273 << (receivedEnvents.size() > 0
274 ? toString(receivedEnvents.front()[0]) : "");
Pavel Maltseve2603e32016-10-25 16:03:23 -0700275
276 auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
277 subscribedValue->prop = PROP;
278 subscribedValue->value.int32Values[0] = 42;
279
280 cb->reset();
281 VehiclePropValue actualValue(*subscribedValue.get());
282 hal->sendPropEvent(std::move(subscribedValue));
283
284 ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700285 << receivedEnvents.size();
Pavel Maltseve2603e32016-10-25 16:03:23 -0700286
287 ASSERT_EQ(toString(actualValue),
288 toString(cb->getReceivedEvents().front()[0]));
289}
290
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700291TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
292 const VehicleProperty PROP = VehicleProperty::HVAC_SEAT_TEMPERATURE;
293
294 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
295
296 hidl_vec<SubscribeOptions> options = init_hidl_vec(
297 {
298 SubscribeOptions {
299 .propId = PROP,
300 .flags = SubscribeFlags::HAL_EVENT
301 },
302 });
303
304 StatusCode res = manager->subscribe(cb, options);
305 // Unable to subscribe on Hal Events for write-only properties.
306 ASSERT_EQ(StatusCode::INVALID_ARG, res);
307
308
309 options[0].flags = SubscribeFlags::SET_CALL;
310
311 res = manager->subscribe(cb, options);
312 // OK to subscribe on SET method call for write-only properties.
313 ASSERT_EQ(StatusCode::OK, res);
314}
315
316TEST_F(VehicleHalManagerTest, get_StaticString) {
317 invokeGet(VehicleProperty::INFO_MAKE, 0);
318
319 ASSERT_EQ(StatusCode::OK, actualStatusCode);
320 ASSERT_EQ(VehicleProperty::INFO_MAKE, actualValue.prop);
321 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
322}
323
324TEST_F(VehicleHalManagerTest, get_NegativeCases) {
325 // Write-only property must fail.
326 invokeGet(VehicleProperty::HVAC_SEAT_TEMPERATURE, 0);
327 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
328
329 // Unknown property must fail.
330 invokeGet(VehicleProperty::MIRROR_Z_MOVE, 0);
331 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
332}
333
334TEST_F(VehicleHalManagerTest, get_Retriable) {
335 actualStatusCode = StatusCode::TRY_AGAIN;
336 int attempts = 0;
337 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
338 invokeGet(VehicleProperty::INFO_FUEL_CAPACITY, 0);
339
340 }
341 ASSERT_EQ(StatusCode::OK, actualStatusCode);
342 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
343 ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
344}
345
346TEST_F(VehicleHalManagerTest, set_Basic) {
347 const auto PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
348 const auto VAL = 7;
349
350 auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
351 expectedValue->prop = PROP;
352 expectedValue->areaId = 0;
353
354 actualStatusCode = manager->set(*expectedValue.get());
355 ASSERT_EQ(StatusCode::OK, actualStatusCode);
356
357 invokeGet(PROP, 0);
358 ASSERT_EQ(StatusCode::OK, actualStatusCode);
359 ASSERT_EQ(PROP, actualValue.prop);
360 ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
361}
362
363TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
364 const auto PROP = VehicleProperty::HVAC_FAN_SPEED;
365 const auto VAL1 = 1;
366 const auto VAL2 = 2;
367 const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
368 const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
369
370 {
371 auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
372 expectedValue1->prop = PROP;
373 expectedValue1->areaId = AREA1;
374 actualStatusCode = manager->set(*expectedValue1.get());
375 ASSERT_EQ(StatusCode::OK, actualStatusCode);
376
377 auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
378 expectedValue2->prop = PROP;
379 expectedValue2->areaId = AREA2;
380 actualStatusCode = manager->set(*expectedValue2.get());
381 ASSERT_EQ(StatusCode::OK, actualStatusCode);
382 }
383
384 {
385 invokeGet(PROP, AREA1);
386 ASSERT_EQ(StatusCode::OK, actualStatusCode);
387 ASSERT_EQ(PROP, actualValue.prop);
388 ASSERT_EQ(AREA1, actualValue.areaId);
389 ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
390
391 invokeGet(PROP, AREA2);
392 ASSERT_EQ(StatusCode::OK, actualStatusCode);
393 ASSERT_EQ(PROP, actualValue.prop);
394 ASSERT_EQ(AREA2, actualValue.areaId);
395 ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
396 }
397}
398
399TEST_F(VehicleHalManagerTest, set_Retriable) {
400 const auto PROP = VehicleProperty::MIRROR_FOLD;
401
402 auto v = hal->getValuePool()->obtainBoolean(true);
403 v->prop = PROP;
404 v->areaId = 0;
405
406 actualStatusCode = StatusCode::TRY_AGAIN;
407 int attempts = 0;
408 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
409 actualStatusCode = manager->set(*v.get());
410 }
411
412 ASSERT_EQ(StatusCode::OK, actualStatusCode);
413 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
414
415 invokeGet(PROP, 0);
416 ASSERT_EQ(StatusCode::OK, actualStatusCode);
417 ASSERT_TRUE(actualValue.value.int32Values[0]);
418}
419
420TEST(HalClientVectorTest, basic) {
421 HalClientVector clients;
Pavel Maltseve2603e32016-10-25 16:03:23 -0700422 sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
423
424 sp<HalClient> c1 = new HalClient(callback1, 10, 20);
425 sp<HalClient> c2 = new HalClient(callback1, 10, 20);
426
427 clients.addOrUpdate(c1);
428 clients.addOrUpdate(c1);
429 clients.addOrUpdate(c2);
430 ASSERT_EQ(2u, clients.size());
431 ASSERT_FALSE(clients.isEmpty());
432 ASSERT_GE(0, clients.indexOf(c1));
433 ASSERT_GE(0, clients.remove(c1));
434 ASSERT_GE(0, clients.indexOf(c1));
435 ASSERT_GE(0, clients.remove(c1));
436 ASSERT_GE(0, clients.remove(c2));
437
438 ASSERT_TRUE(clients.isEmpty());
439}
440
441} // namespace anonymous
442
443} // namespace V2_0
444} // namespace vehicle
445} // namespace hardware
446} // namespace android