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