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