/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include // NOLINT #include // NOLINT #include // NOLINT namespace android { namespace frameworks { namespace automotive { namespace vhal { namespace aidl_test { using ::android::hardware::automotive::vehicle::toInt; using ::android::hardware::automotive::vehicle::VhalResult; using ::aidl::android::hardware::automotive::vehicle::BnVehicle; using ::aidl::android::hardware::automotive::vehicle::GetValueRequest; using ::aidl::android::hardware::automotive::vehicle::GetValueRequests; using ::aidl::android::hardware::automotive::vehicle::GetValueResult; using ::aidl::android::hardware::automotive::vehicle::GetValueResults; using ::aidl::android::hardware::automotive::vehicle::IVehicle; using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::RawPropValues; using ::aidl::android::hardware::automotive::vehicle::SetValueRequest; using ::aidl::android::hardware::automotive::vehicle::SetValueRequests; using ::aidl::android::hardware::automotive::vehicle::SetValueResult; using ::aidl::android::hardware::automotive::vehicle::SetValueResults; using ::aidl::android::hardware::automotive::vehicle::StatusCode; using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs; using ::aidl::android::hardware::automotive::vehicle::VehiclePropError; using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; using ::ndk::ScopedAStatus; using ::ndk::SharedRefBase; class MockVhal final : public BnVehicle { public: using CallbackType = std::shared_ptr; ~MockVhal() { std::unique_lock lk(mLock); mCv.wait_for(lk, std::chrono::milliseconds(1000), [this] { return mThreadCount == 0; }); } ScopedAStatus getAllPropConfigs(VehiclePropConfigs* returnConfigs) override { if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } returnConfigs->payloads = mPropConfigs; return ScopedAStatus::ok(); } ScopedAStatus getValues(const CallbackType& callback, const GetValueRequests& requests) override { mGetValueRequests = requests.payloads; if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } if (mWaitTimeInMs == 0) { callback->onGetValues(GetValueResults{.payloads = mGetValueResults}); } else { mThreadCount++; std::thread t([this, callback]() { std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTimeInMs)); callback->onGetValues(GetValueResults{.payloads = mGetValueResults}); mThreadCount--; mCv.notify_one(); }); // Detach the thread here so we do not have to maintain the thread object. mThreadCount // and mCv make sure we wait for all threads to end before we exit. t.detach(); } return ScopedAStatus::ok(); } ScopedAStatus setValues(const CallbackType& callback, const SetValueRequests& requests) override { mSetValueRequests = requests.payloads; if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } if (mWaitTimeInMs == 0) { callback->onSetValues(SetValueResults{.payloads = mSetValueResults}); } else { mThreadCount++; std::thread t([this, callback]() { std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTimeInMs)); callback->onSetValues(SetValueResults{.payloads = mSetValueResults}); mThreadCount--; mCv.notify_one(); }); // Detach the thread here so we do not have to maintain the thread object. mThreadCount // and mCv make sure we wait for all threads to end before we exit. t.detach(); } return ScopedAStatus::ok(); } ScopedAStatus getPropConfigs(const std::vector& props, VehiclePropConfigs* returnConfigs) override { mGetPropConfigPropIds = props; if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } returnConfigs->payloads = mPropConfigs; return ScopedAStatus::ok(); } ScopedAStatus subscribe(const CallbackType& callback, const std::vector& options, [[maybe_unused]] int32_t maxSharedMemoryFileCount) override { mSubscriptionCallback = callback; mSubscriptionOptions = options; if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } return ScopedAStatus::ok(); } ScopedAStatus unsubscribe([[maybe_unused]] const CallbackType& callback, const std::vector& propIds) override { mUnsubscribePropIds = propIds; if (mStatus != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificError(toInt(mStatus)); } return ScopedAStatus::ok(); } ScopedAStatus returnSharedMemory([[maybe_unused]] const CallbackType& callback, [[maybe_unused]] int64_t sharedMemoryId) override { return ScopedAStatus::ok(); } // Test Functions void setGetValueResults(std::vector results) { mGetValueResults = results; } std::vector getGetValueRequests() { return mGetValueRequests; } void setSetValueResults(std::vector results) { mSetValueResults = results; } std::vector getSetValueRequests() { return mSetValueRequests; } void setWaitTimeInMs(int64_t waitTimeInMs) { mWaitTimeInMs = waitTimeInMs; } void setStatus(StatusCode status) { mStatus = status; } void setPropConfigs(std::vector configs) { mPropConfigs = configs; } std::vector getGetPropConfigPropIds() { return mGetPropConfigPropIds; } std::vector getSubscriptionOptions() { return mSubscriptionOptions; } void triggerOnPropertyEvent(const std::vector& values) { VehiclePropValues propValues = { .payloads = values, }; mSubscriptionCallback->onPropertyEvent(propValues, /*sharedMemoryCount=*/0); } void triggerSetErrorEvent(const std::vector& errors) { VehiclePropErrors propErrors = { .payloads = errors, }; mSubscriptionCallback->onPropertySetError(propErrors); } std::vector getUnsubscribedPropIds() { return mUnsubscribePropIds; } private: std::mutex mLock; std::vector mGetValueResults; std::vector mGetValueRequests; std::vector mSetValueResults; std::vector mSetValueRequests; std::vector mPropConfigs; std::vector mGetPropConfigPropIds; int64_t mWaitTimeInMs = 0; StatusCode mStatus = StatusCode::OK; std::condition_variable mCv; std::atomic mThreadCount = 0; CallbackType mSubscriptionCallback; std::vector mSubscriptionOptions; std::vector mUnsubscribePropIds; }; class MockSubscriptionCallback : public ISubscriptionCallback { public: void onPropertyEvent(const std::vector>& values) override { for (const auto& value : values) { mEventPropIds.push_back(value->getPropId()); } } void onPropertySetError(const std::vector& errors) override { mErrors = errors; } std::vector getEventPropIds() { return mEventPropIds; } std::vector getErrors() { return mErrors; } private: std::vector mEventPropIds; std::vector mErrors; }; class AidlVhalClientTest : public ::testing::Test { protected: class TestLinkUnlinkImpl final : public AidlVhalClient::ILinkUnlinkToDeath { public: binder_status_t linkToDeath([[maybe_unused]] AIBinder* binder, [[maybe_unused]] AIBinder_DeathRecipient* recipient, void* cookie) override { mCookie = cookie; return STATUS_OK; } binder_status_t unlinkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override { // DO nothing. return STATUS_OK; } void* getCookie() { return mCookie; } private: void* mCookie; }; constexpr static int32_t TEST_PROP_ID = 1; constexpr static int32_t TEST_AREA_ID = 2; constexpr static int32_t TEST_PROP_ID_2 = 3; constexpr static int64_t TEST_TIMEOUT_IN_MS = 100; void SetUp() override { mVhal = SharedRefBase::make(); auto impl = std::make_unique(); // We are sure impl would be alive when we use mLinkUnlinkImpl. mLinkUnlinkImpl = impl.get(); mVhalClient = std::unique_ptr( new AidlVhalClient(mVhal, TEST_TIMEOUT_IN_MS, std::move(impl))); } AidlVhalClient* getClient() { return mVhalClient.get(); } MockVhal* getVhal() { return mVhal.get(); } void triggerBinderDied() { AidlVhalClient::onBinderDied(mLinkUnlinkImpl->getCookie()); } void triggerBinderUnlinked() { AidlVhalClient::onBinderUnlinked(mLinkUnlinkImpl->getCookie()); } size_t countOnBinderDiedCallbacks() { return mVhalClient->countOnBinderDiedCallbacks(); } private: std::shared_ptr mVhal; std::unique_ptr mVhalClient; TestLinkUnlinkImpl* mLinkUnlinkImpl; }; TEST_F(AidlVhalClientTest, testIsAidl) { ASSERT_TRUE(getClient()->isAidlVhal()); } TEST_F(AidlVhalClientTest, testGetValueNormal) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setWaitTimeInMs(10); getVhal()->setGetValueResults({ GetValueResult{ .requestId = 0, .status = StatusCode::OK, .prop = VehiclePropValue{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = RawPropValues{ .int32Values = {1}, }, }, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); std::mutex lock; std::condition_variable cv; VhalResult> result; VhalResult>* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [&lock, &cv, resultPtr, gotResultPtr](VhalResult> r) { { std::lock_guard lockGuard(lock); *resultPtr = std::move(r); *gotResultPtr = true; } cv.notify_one(); }); getClient()->getValue(propValue, callback); std::unique_lock lk(lock); cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; }); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_TRUE(result.ok()); auto gotValue = std::move(result.value()); ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID); ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID); ASSERT_EQ(gotValue->getInt32Values(), std::vector({1})); } TEST_F(AidlVhalClientTest, testGetValueSync) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setWaitTimeInMs(10); getVhal()->setGetValueResults({ GetValueResult{ .requestId = 0, .status = StatusCode::OK, .prop = VehiclePropValue{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = RawPropValues{ .int32Values = {1}, }, }, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult> result = getClient()->getValueSync(propValue); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_TRUE(result.ok()); auto gotValue = std::move(result.value()); ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID); ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID); ASSERT_EQ(gotValue->getInt32Values(), std::vector({1})); } TEST_F(AidlVhalClientTest, testGetValueTimeout) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; // The request will time-out before the response. getVhal()->setWaitTimeInMs(200); getVhal()->setGetValueResults({ GetValueResult{ .requestId = 0, .status = StatusCode::OK, .prop = VehiclePropValue{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = RawPropValues{ .int32Values = {1}, }, }, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); std::mutex lock; std::condition_variable cv; VhalResult> result; VhalResult>* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [&lock, &cv, resultPtr, gotResultPtr](VhalResult> r) { { std::lock_guard lockGuard(lock); *resultPtr = std::move(r); *gotResultPtr = true; } cv.notify_one(); }); getClient()->getValue(propValue, callback); std::unique_lock lk(lock); cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; }); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::TRY_AGAIN); } TEST_F(AidlVhalClientTest, testGetValueErrorStatus) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setStatus(StatusCode::INTERNAL_ERROR); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult> result; VhalResult>* resultPtr = &result; getClient()->getValue(propValue, std::make_shared( [resultPtr](VhalResult> r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testGetValueNonOkayResult) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setGetValueResults({ GetValueResult{ .requestId = 0, .status = StatusCode::INTERNAL_ERROR, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult> result; VhalResult>* resultPtr = &result; getClient()->getValue(propValue, std::make_shared( [resultPtr](VhalResult> r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testGetValueIgnoreInvalidRequestId) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setGetValueResults({ GetValueResult{ .requestId = 0, .status = StatusCode::OK, .prop = VehiclePropValue{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = RawPropValues{ .int32Values = {1}, }, }, }, // This result has invalid request ID and should be ignored. GetValueResult{ .requestId = 1, .status = StatusCode::INTERNAL_ERROR, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult> result; VhalResult>* resultPtr = &result; getClient()->getValue(propValue, std::make_shared( [resultPtr](VhalResult> r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getGetValueRequests(), std::vector({GetValueRequest{.requestId = 0, .prop = testProp}})); ASSERT_TRUE(result.ok()); auto gotValue = std::move(result.value()); ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID); ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID); ASSERT_EQ(gotValue->getInt32Values(), std::vector({1})); } TEST_F(AidlVhalClientTest, testSetValueNormal) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setWaitTimeInMs(10); getVhal()->setSetValueResults({ SetValueResult{ .requestId = 0, .status = StatusCode::OK, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); std::mutex lock; std::condition_variable cv; VhalResult result; VhalResult* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [&lock, &cv, resultPtr, gotResultPtr](VhalResult r) { { std::lock_guard lockGuard(lock); *resultPtr = std::move(r); *gotResultPtr = true; } cv.notify_one(); }); getClient()->setValue(propValue, callback); std::unique_lock lk(lock); cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; }); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_TRUE(result.ok()); } TEST_F(AidlVhalClientTest, testSetValueSync) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setWaitTimeInMs(10); getVhal()->setSetValueResults({ SetValueResult{ .requestId = 0, .status = StatusCode::OK, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult result = getClient()->setValueSync(propValue); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_TRUE(result.ok()); } TEST_F(AidlVhalClientTest, testSetValueTimeout) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; // The request will time-out before the response. getVhal()->setWaitTimeInMs(200); getVhal()->setSetValueResults({ SetValueResult{ .requestId = 0, .status = StatusCode::OK, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); std::mutex lock; std::condition_variable cv; VhalResult result; VhalResult* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [&lock, &cv, resultPtr, gotResultPtr](VhalResult r) { { std::lock_guard lockGuard(lock); *resultPtr = std::move(r); *gotResultPtr = true; } cv.notify_one(); }); getClient()->setValue(propValue, callback); std::unique_lock lk(lock); cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; }); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::TRY_AGAIN); } TEST_F(AidlVhalClientTest, testSetValueErrorStatus) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setStatus(StatusCode::INTERNAL_ERROR); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult result; VhalResult* resultPtr = &result; getClient()->setValue(propValue, std::make_shared( [resultPtr](VhalResult r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testSetValueNonOkayResult) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setSetValueResults({ SetValueResult{ .requestId = 0, .status = StatusCode::INTERNAL_ERROR, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult result; VhalResult* resultPtr = &result; getClient()->setValue(propValue, std::make_shared( [resultPtr](VhalResult r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testSetValueIgnoreInvalidRequestId) { VehiclePropValue testProp{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, }; getVhal()->setSetValueResults({ SetValueResult{ .requestId = 0, .status = StatusCode::OK, }, // This result has invalid request ID and should be ignored. SetValueResult{ .requestId = 1, .status = StatusCode::INTERNAL_ERROR, }, }); AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID); VhalResult result; VhalResult* resultPtr = &result; getClient()->setValue(propValue, std::make_shared( [resultPtr](VhalResult r) { *resultPtr = std::move(r); })); ASSERT_EQ(getVhal()->getSetValueRequests(), std::vector({SetValueRequest{.requestId = 0, .value = testProp}})); ASSERT_TRUE(result.ok()); } TEST_F(AidlVhalClientTest, testAddOnBinderDiedCallback) { struct Result { bool callbackOneCalled = false; bool callbackTwoCalled = false; } result; getClient()->addOnBinderDiedCallback(std::make_shared( [&result] { result.callbackOneCalled = true; })); getClient()->addOnBinderDiedCallback(std::make_shared( [&result] { result.callbackTwoCalled = true; })); triggerBinderDied(); ASSERT_TRUE(result.callbackOneCalled); ASSERT_TRUE(result.callbackTwoCalled); triggerBinderUnlinked(); ASSERT_EQ(countOnBinderDiedCallbacks(), static_cast(0)); } TEST_F(AidlVhalClientTest, testRemoveOnBinderDiedCallback) { struct Result { bool callbackOneCalled = false; bool callbackTwoCalled = false; } result; auto callbackOne = std::make_shared( [&result] { result.callbackOneCalled = true; }); auto callbackTwo = std::make_shared( [&result] { result.callbackTwoCalled = true; }); getClient()->addOnBinderDiedCallback(callbackOne); getClient()->addOnBinderDiedCallback(callbackTwo); getClient()->removeOnBinderDiedCallback(callbackOne); triggerBinderDied(); ASSERT_FALSE(result.callbackOneCalled); ASSERT_TRUE(result.callbackTwoCalled); triggerBinderUnlinked(); ASSERT_EQ(countOnBinderDiedCallbacks(), static_cast(0)); } TEST_F(AidlVhalClientTest, testGetAllPropConfigs) { getVhal()->setPropConfigs({ VehiclePropConfig{ .prop = TEST_PROP_ID, .areaConfigs = {{ .areaId = TEST_AREA_ID, .minInt32Value = 0, .maxInt32Value = 1, }}, }, VehiclePropConfig{ .prop = TEST_PROP_ID_2, }, }); auto result = getClient()->getAllPropConfigs(); ASSERT_TRUE(result.ok()); std::vector> configs = std::move(result.value()); ASSERT_EQ(configs.size(), static_cast(2)); ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID); ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast(1)); const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs(); ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID); ASSERT_EQ(areaConfig->getMinInt32Value(), 0); ASSERT_EQ(areaConfig->getMaxInt32Value(), 1); ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2); ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast(0)); } TEST_F(AidlVhalClientTest, testGetAllPropConfigsError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); auto result = getClient()->getAllPropConfigs(); ASSERT_FALSE(result.ok()); ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testGetPropConfigs) { getVhal()->setPropConfigs({ VehiclePropConfig{ .prop = TEST_PROP_ID, .areaConfigs = {{ .areaId = TEST_AREA_ID, .minInt32Value = 0, .maxInt32Value = 1, }}, }, VehiclePropConfig{ .prop = TEST_PROP_ID_2, }, }); std::vector propIds = {TEST_PROP_ID, TEST_PROP_ID_2}; auto result = getClient()->getPropConfigs(propIds); ASSERT_EQ(getVhal()->getGetPropConfigPropIds(), propIds); ASSERT_TRUE(result.ok()); std::vector> configs = std::move(result.value()); ASSERT_EQ(configs.size(), static_cast(2)); ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID); ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast(1)); const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs(); ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID); ASSERT_EQ(areaConfig->getMinInt32Value(), 0); ASSERT_EQ(areaConfig->getMaxInt32Value(), 1); ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2); ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast(0)); } TEST_F(AidlVhalClientTest, testGetPropConfigsError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); std::vector propIds = {TEST_PROP_ID, TEST_PROP_ID_2}; auto result = getClient()->getPropConfigs(propIds); ASSERT_FALSE(result.ok()); } TEST_F(AidlVhalClientTest, testSubscribe) { std::vector options = { { .propId = TEST_PROP_ID, .areaIds = {TEST_AREA_ID}, .sampleRate = 1.0, }, { .propId = TEST_PROP_ID_2, .sampleRate = 2.0, }, }; auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->subscribe(options); ASSERT_TRUE(result.ok()); ASSERT_EQ(getVhal()->getSubscriptionOptions(), options); getVhal()->triggerOnPropertyEvent(std::vector{ { .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value.int32Values = {1}, }, }); ASSERT_EQ(callback->getEventPropIds(), std::vector({TEST_PROP_ID})); getVhal()->triggerSetErrorEvent(std::vector({ { .propId = TEST_PROP_ID, .areaId = TEST_AREA_ID, .errorCode = StatusCode::INTERNAL_ERROR, }, })); auto errors = callback->getErrors(); ASSERT_EQ(errors.size(), static_cast(1)); ASSERT_EQ(errors[0].propId, TEST_PROP_ID); ASSERT_EQ(errors[0].areaId, TEST_AREA_ID); ASSERT_EQ(errors[0].status, StatusCode::INTERNAL_ERROR); } TEST_F(AidlVhalClientTest, testSubscribeError) { std::vector options = { { .propId = TEST_PROP_ID, .areaIds = {TEST_AREA_ID}, .sampleRate = 1.0, }, { .propId = TEST_PROP_ID_2, .sampleRate = 2.0, }, }; getVhal()->setStatus(StatusCode::INTERNAL_ERROR); auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->subscribe(options); ASSERT_FALSE(result.ok()); } TEST_F(AidlVhalClientTest, testUnubscribe) { auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->unsubscribe({TEST_PROP_ID}); ASSERT_TRUE(result.ok()); ASSERT_EQ(getVhal()->getUnsubscribedPropIds(), std::vector({TEST_PROP_ID})); } TEST_F(AidlVhalClientTest, testUnubscribeError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->unsubscribe({TEST_PROP_ID}); ASSERT_FALSE(result.ok()); } } // namespace aidl_test } // namespace vhal } // namespace automotive } // namespace frameworks } // namespace android