Support set/get value in fake vehicle hardware.
Support setValues and getValues in fake vehicle hardware
implementation.
Test: atest FakeVehicleHardwareTest
Bug: 201830716
Change-Id: I4b94408434fd8511ab79d757116b776105d69222
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 4820fd4..c5702aa 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -8,6 +8,9 @@
},
{
"name": "VehicleHalVehicleUtilsTest"
+ },
+ {
+ "name": "FakeVehicleHardwareTest"
}
]
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index b091517..6dc3e76 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -106,15 +106,67 @@
return mServerSidePropStore->getAllConfigs();
}
-StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&&,
- const std::vector<SetValueRequest>&) {
- // TODO(b/201830716): Implement this.
+StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&& callback,
+ const std::vector<SetValueRequest>& requests) {
+ std::vector<VehiclePropValue> updatedValues;
+ std::vector<SetValueResult> results;
+ for (auto& request : requests) {
+ const VehiclePropValue* value = &request.value;
+ ALOGD("setValues(%d)", value->prop);
+
+ auto updatedValue = mValuePool->obtain(*value);
+ int64_t timestamp = elapsedRealtimeNano();
+ updatedValue->timestamp = timestamp;
+
+ auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+ SetValueResult setValueResult;
+ setValueResult.requestId = request.requestId;
+ if (!writeResult.ok()) {
+ ALOGE("failed to write value into property store, error: %s, code: %d",
+ writeResult.error().message().c_str(), writeResult.error().code());
+ setValueResult.status = StatusCode::INVALID_ARG;
+ } else {
+ setValueResult.status = StatusCode::OK;
+ }
+ results.push_back(std::move(setValueResult));
+ }
+
+ // In the real vhal, the values will be sent to Car ECU. We just pretend it is done here and
+ // send back the updated property values to client.
+ callback(std::move(results));
+
return StatusCode::OK;
}
-StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback&&,
- const std::vector<GetValueRequest>&) const {
- // TODO(b/201830716): Implement this.
+StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback&& callback,
+ const std::vector<GetValueRequest>& requests) const {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ const VehiclePropValue* value = &request.prop;
+ ALOGD("getValues(%d)", value->prop);
+
+ auto readResult = mServerSidePropStore->readValue(*value);
+ GetValueResult getValueResult;
+ getValueResult.requestId = request.requestId;
+ if (!readResult.ok()) {
+ auto error = readResult.error();
+ if (error.code() == toInt(StatusCode::NOT_AVAILABLE)) {
+ ALOGW("%s", "value has not been set yet");
+ getValueResult.status = StatusCode::NOT_AVAILABLE;
+ } else {
+ ALOGE("failed to get value, error: %s, code: %d", error.message().c_str(),
+ error.code());
+ getValueResult.status = StatusCode::INVALID_ARG;
+ }
+ } else {
+ getValueResult.status = StatusCode::OK;
+ getValueResult.prop = *readResult.value();
+ }
+ results.push_back(std::move(getValueResult));
+ }
+
+ callback(std::move(results));
+
return StatusCode::OK;
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index d901b38..650a131 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -41,6 +41,8 @@
using ::testing::Eq;
using ::testing::WhenSortedBy;
+constexpr int INVALID_PROP_ID = 0;
+
} // namespace
class FakeVehicleHardwareTest : public ::testing::Test {
@@ -159,6 +161,268 @@
ASSERT_EQ(configs.size(), defaultconfig::getDefaultConfigs().size());
}
+TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ int64_t requestId = 1;
+
+ for (auto& config : defaultconfig::getDefaultConfigs()) {
+ int propId = config.config.prop;
+ if (isGlobalProp(propId)) {
+ if (config.initialValue == RawPropValues{}) {
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
+ VehiclePropValue{.prop = propId}, StatusCode::NOT_AVAILABLE);
+ continue;
+ }
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
+ VehiclePropValue{
+ .prop = propId,
+ .value = config.initialValue,
+ },
+ StatusCode::OK);
+ continue;
+ }
+ for (auto areaConfig : config.config.areaConfigs) {
+ StatusCode status = StatusCode::OK;
+ VehiclePropValue propValue{
+ .prop = propId,
+ .areaId = areaConfig.areaId,
+ };
+ if (config.initialAreaValues.empty()) {
+ if (config.initialValue == RawPropValues{}) {
+ status = StatusCode::NOT_AVAILABLE;
+ } else {
+ propValue.value = config.initialValue;
+ }
+ } else if (auto valueForAreaIt = config.initialAreaValues.find(areaConfig.areaId);
+ valueForAreaIt != config.initialAreaValues.end()) {
+ propValue.value = valueForAreaIt->second;
+ } else {
+ status = StatusCode::NOT_AVAILABLE;
+ }
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, propValue,
+ status);
+ }
+ }
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueResult> getValueResultsWithNoTimestamp;
+ for (auto& result : getGetValueResults()) {
+ GetValueResult resultCopy = result;
+ resultCopy.prop->timestamp = 0;
+ getValueResultsWithNoTimestamp.push_back(std::move(resultCopy));
+ }
+ ASSERT_THAT(getValueResultsWithNoTimestamp, ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetValues) {
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ // Although callback might be called asynchronously, in our implementation, the callback would
+ // be called before setValues returns.
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetValuesError) {
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+
+ int64_t requestId = 1;
+
+ VehiclePropValue invalidProp = {
+ .prop = INVALID_PROP_ID,
+ };
+ addSetValueRequest(requests, expectedResults, requestId++, invalidProp,
+ StatusCode::INVALID_ARG);
+
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ // Although callback might be called asynchronously, in our implementation, the callback would
+ // be called before setValues returns.
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
+ getHardware()->registerOnPropertyChangeEvent(std::bind(
+ &FakeVehicleHardwareTest_testRegisterOnPropertyChangeEvent_Test::onPropertyChangeEvent,
+ this, std::placeholders::_1));
+
+ auto testValues = getTestPropValues();
+ std::vector<SetValueRequest> requests;
+ std::vector<SetValueResult> expectedResults;
+ int64_t requestId = 1;
+ for (auto& value : testValues) {
+ addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
+ }
+ int64_t timestamp = elapsedRealtimeNano();
+
+ StatusCode status = setValues(requests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ auto updatedValues = getChangedProperties();
+ std::vector<VehiclePropValue> updatedValuesWithNoTimestamp;
+ for (auto& value : updatedValues) {
+ ASSERT_GE(value.timestamp, timestamp);
+ VehiclePropValue valueCopy = value;
+ valueCopy.timestamp = 0;
+ updatedValuesWithNoTimestamp.push_back(std::move(valueCopy));
+ }
+
+ ASSERT_THAT(updatedValuesWithNoTimestamp, WhenSortedBy(mPropValueCmp, Eq(testValues)));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValues) {
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+ int64_t timestamp = elapsedRealtimeNano();
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ for (auto& value : getTestPropValues()) {
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueResult> getValueResultsWithNoTimestamp;
+ for (auto& result : getGetValueResults()) {
+ ASSERT_GE(result.prop->timestamp, timestamp);
+ GetValueResult resultCopy = result;
+ resultCopy.prop->timestamp = 0;
+ getValueResultsWithNoTimestamp.push_back(std::move(resultCopy));
+ }
+ ASSERT_THAT(getValueResultsWithNoTimestamp, ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValuesErrorInvalidProp) {
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ for (auto& value : getTestPropValues()) {
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, value,
+ StatusCode::OK);
+ }
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ VehiclePropValue invalidProp = {
+ .prop = INVALID_PROP_ID,
+ };
+ addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++, invalidProp,
+ StatusCode::INVALID_ARG);
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getGetValueResults(), ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testReadValuesErrorNotAvailable) {
+ std::vector<GetValueRequest> getValueRequests;
+ std::vector<GetValueResult> expectedGetValueResults;
+ // VEHICLE_MAP_SERVICE does not have initial value, 'get' must always return
+ // StatusCode::NOT_AVAILABLE.
+ addGetValueRequest(getValueRequests, expectedGetValueResults, 0,
+ VehiclePropValue{
+ .prop = VEHICLE_MAP_SERVICE,
+ },
+ StatusCode::NOT_AVAILABLE);
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getGetValueResults(), ContainerEq(expectedGetValueResults));
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetStatusMustIgnore) {
+ VehiclePropValue testValue = getTestPropValues()[0];
+ testValue.status = VehiclePropertyStatus::UNAVAILABLE;
+
+ std::vector<SetValueRequest> setValueRequests;
+ std::vector<SetValueResult> expectedSetValueResults;
+
+ int64_t requestId = 1;
+ addSetValueRequest(setValueRequests, expectedSetValueResults, requestId++, testValue,
+ StatusCode::OK);
+
+ // In our implementation, this would finish immediately.
+ StatusCode status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_THAT(getSetValueResults(), ContainerEq(expectedSetValueResults));
+
+ std::vector<GetValueRequest> getValueRequests;
+ getValueRequests.push_back(GetValueRequest{
+ .requestId = requestId++,
+ .prop = testValue,
+ });
+
+ // In our implementation, this would finish immediately.
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults().size(), static_cast<size_t>(1));
+ ASSERT_EQ(getGetValueResults()[0].status, StatusCode::OK);
+ // The status should be by-default AVAILABLE for new status.
+ ASSERT_EQ(getGetValueResults()[0].prop->status, VehiclePropertyStatus::AVAILABLE);
+
+ // Try to set the property again. The status should not be overwritten.
+ status = setValues(setValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ status = getValues(getValueRequests);
+
+ ASSERT_EQ(status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults().size(), static_cast<size_t>(2));
+ ASSERT_EQ(getGetValueResults()[1].status, StatusCode::OK);
+ ASSERT_EQ(getGetValueResults()[1].prop->status, VehiclePropertyStatus::AVAILABLE);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware