blob: 964c7c8157f5fd1f0454d009f9bd69e91ea3df93 [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) {
Pavel Maltsev0e0a9252016-12-05 11:03:52 -0800185 hidl_vec<VehicleProperty> properties =
186 { VehicleProperty::HVAC_FAN_SPEED, VehicleProperty::INFO_MAKE };
Pavel Maltseve2603e32016-10-25 16:03:23 -0700187 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;
Pavel Maltsev0e0a9252016-12-05 11:03:52 -0800200 manager->getPropConfigs({ 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
Pavel Maltsev0e0a9252016-12-05 11:03:52 -0800233 hidl_vec<SubscribeOptions> options = {
234 SubscribeOptions {
235 .propId = PROP,
236 .flags = SubscribeFlags::DEFAULT
237 },
238 };
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700239
240 StatusCode res = manager->subscribe(cb, options);
241 ASSERT_EQ(StatusCode::OK, res);
242
243 hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
244}
245
Pavel Maltseve2603e32016-10-25 16:03:23 -0700246TEST_F(VehicleHalManagerTest, subscribe) {
247 const VehicleProperty PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
248
249 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
250
Pavel Maltsev0e0a9252016-12-05 11:03:52 -0800251 hidl_vec<SubscribeOptions> options = {
252 SubscribeOptions {
253 .propId = PROP,
254 .flags = SubscribeFlags::DEFAULT
255 }
256 };
Pavel Maltseve2603e32016-10-25 16:03:23 -0700257
258 StatusCode res = manager->subscribe(cb, options);
259 ASSERT_EQ(StatusCode::OK, res);
260
261 auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
262 unsubscribedValue->prop = VehicleProperty::HVAC_FAN_SPEED;
263
264 hal->sendPropEvent(std::move(unsubscribedValue));
265 auto& receivedEnvents = cb->getReceivedEvents();
266
267 ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700268 << receivedEnvents.size()
269 << (receivedEnvents.size() > 0
270 ? toString(receivedEnvents.front()[0]) : "");
Pavel Maltseve2603e32016-10-25 16:03:23 -0700271
272 auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
273 subscribedValue->prop = PROP;
274 subscribedValue->value.int32Values[0] = 42;
275
276 cb->reset();
277 VehiclePropValue actualValue(*subscribedValue.get());
278 hal->sendPropEvent(std::move(subscribedValue));
279
280 ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700281 << receivedEnvents.size();
Pavel Maltseve2603e32016-10-25 16:03:23 -0700282
283 ASSERT_EQ(toString(actualValue),
284 toString(cb->getReceivedEvents().front()[0]));
285}
286
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700287TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
288 const VehicleProperty PROP = VehicleProperty::HVAC_SEAT_TEMPERATURE;
289
290 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
291
Pavel Maltsev0e0a9252016-12-05 11:03:52 -0800292 hidl_vec<SubscribeOptions> options = {
293 SubscribeOptions {
294 .propId = PROP,
295 .flags = SubscribeFlags::HAL_EVENT
296 },
297 };
Pavel Maltsevdb179c52016-10-27 15:43:06 -0700298
299 StatusCode res = manager->subscribe(cb, options);
300 // Unable to subscribe on Hal Events for write-only properties.
301 ASSERT_EQ(StatusCode::INVALID_ARG, res);
302
303
304 options[0].flags = SubscribeFlags::SET_CALL;
305
306 res = manager->subscribe(cb, options);
307 // OK to subscribe on SET method call for write-only properties.
308 ASSERT_EQ(StatusCode::OK, res);
309}
310
311TEST_F(VehicleHalManagerTest, get_StaticString) {
312 invokeGet(VehicleProperty::INFO_MAKE, 0);
313
314 ASSERT_EQ(StatusCode::OK, actualStatusCode);
315 ASSERT_EQ(VehicleProperty::INFO_MAKE, actualValue.prop);
316 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
317}
318
319TEST_F(VehicleHalManagerTest, get_NegativeCases) {
320 // Write-only property must fail.
321 invokeGet(VehicleProperty::HVAC_SEAT_TEMPERATURE, 0);
322 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
323
324 // Unknown property must fail.
325 invokeGet(VehicleProperty::MIRROR_Z_MOVE, 0);
326 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
327}
328
329TEST_F(VehicleHalManagerTest, get_Retriable) {
330 actualStatusCode = StatusCode::TRY_AGAIN;
331 int attempts = 0;
332 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
333 invokeGet(VehicleProperty::INFO_FUEL_CAPACITY, 0);
334
335 }
336 ASSERT_EQ(StatusCode::OK, actualStatusCode);
337 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
338 ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
339}
340
341TEST_F(VehicleHalManagerTest, set_Basic) {
342 const auto PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
343 const auto VAL = 7;
344
345 auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
346 expectedValue->prop = PROP;
347 expectedValue->areaId = 0;
348
349 actualStatusCode = manager->set(*expectedValue.get());
350 ASSERT_EQ(StatusCode::OK, actualStatusCode);
351
352 invokeGet(PROP, 0);
353 ASSERT_EQ(StatusCode::OK, actualStatusCode);
354 ASSERT_EQ(PROP, actualValue.prop);
355 ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
356}
357
358TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
359 const auto PROP = VehicleProperty::HVAC_FAN_SPEED;
360 const auto VAL1 = 1;
361 const auto VAL2 = 2;
362 const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
363 const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
364
365 {
366 auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
367 expectedValue1->prop = PROP;
368 expectedValue1->areaId = AREA1;
369 actualStatusCode = manager->set(*expectedValue1.get());
370 ASSERT_EQ(StatusCode::OK, actualStatusCode);
371
372 auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
373 expectedValue2->prop = PROP;
374 expectedValue2->areaId = AREA2;
375 actualStatusCode = manager->set(*expectedValue2.get());
376 ASSERT_EQ(StatusCode::OK, actualStatusCode);
377 }
378
379 {
380 invokeGet(PROP, AREA1);
381 ASSERT_EQ(StatusCode::OK, actualStatusCode);
382 ASSERT_EQ(PROP, actualValue.prop);
383 ASSERT_EQ(AREA1, actualValue.areaId);
384 ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
385
386 invokeGet(PROP, AREA2);
387 ASSERT_EQ(StatusCode::OK, actualStatusCode);
388 ASSERT_EQ(PROP, actualValue.prop);
389 ASSERT_EQ(AREA2, actualValue.areaId);
390 ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
391 }
392}
393
394TEST_F(VehicleHalManagerTest, set_Retriable) {
395 const auto PROP = VehicleProperty::MIRROR_FOLD;
396
397 auto v = hal->getValuePool()->obtainBoolean(true);
398 v->prop = PROP;
399 v->areaId = 0;
400
401 actualStatusCode = StatusCode::TRY_AGAIN;
402 int attempts = 0;
403 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
404 actualStatusCode = manager->set(*v.get());
405 }
406
407 ASSERT_EQ(StatusCode::OK, actualStatusCode);
408 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
409
410 invokeGet(PROP, 0);
411 ASSERT_EQ(StatusCode::OK, actualStatusCode);
412 ASSERT_TRUE(actualValue.value.int32Values[0]);
413}
414
415TEST(HalClientVectorTest, basic) {
416 HalClientVector clients;
Pavel Maltseve2603e32016-10-25 16:03:23 -0700417 sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
418
419 sp<HalClient> c1 = new HalClient(callback1, 10, 20);
420 sp<HalClient> c2 = new HalClient(callback1, 10, 20);
421
422 clients.addOrUpdate(c1);
423 clients.addOrUpdate(c1);
424 clients.addOrUpdate(c2);
425 ASSERT_EQ(2u, clients.size());
426 ASSERT_FALSE(clients.isEmpty());
Pavel Maltsev6fee6282016-12-02 16:43:24 -0800427 ASSERT_LE(0, clients.indexOf(c1));
428 ASSERT_LE(0, clients.remove(c1));
429 ASSERT_GT(0, clients.indexOf(c1)); // c1 was already removed
430 ASSERT_GT(0, clients.remove(c1)); // attempt to remove c1 again
431 ASSERT_LE(0, clients.remove(c2));
Pavel Maltseve2603e32016-10-25 16:03:23 -0700432
433 ASSERT_TRUE(clients.isEmpty());
434}
435
436} // namespace anonymous
437
438} // namespace V2_0
439} // namespace vehicle
440} // namespace hardware
441} // namespace android