diff options
author | Yu Shan <shanyu@google.com> | 2021-09-13 17:28:00 -0700 |
---|---|---|
committer | Yu Shan <shanyu@google.com> | 2021-09-13 17:28:00 -0700 |
commit | 9de3fb07ce91f3e5227498aa0b7670b989bce5fb (patch) | |
tree | 7b5d1a8b42432ca74ee6e2deee83eab06b64c1f4 /automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp | |
parent | 36b6d0887e0635434610ed26b6ae7e64f1f2db8b (diff) |
Migrate VehicleObjectPool
Test: atest VehicleHalVehicleUtilsTest
Bug: 199337732
Change-Id: I93772c401dc077f1fbab79e302336494039308d1
Diffstat (limited to 'automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp')
-rw-r--r-- | automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp new file mode 100644 index 0000000000..a62532c911 --- /dev/null +++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2021 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 <thread> + +#include <gtest/gtest.h> + +#include <utils/SystemClock.h> + +#include <VehicleHalTypes.h> +#include <VehicleObjectPool.h> +#include <VehicleUtils.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +namespace { + +using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; + +struct TestPropertyTypeInfo { + VehiclePropertyType type; + bool recyclable; + size_t vecSize; +}; + +std::vector<TestPropertyTypeInfo> getAllPropertyTypes() { + return { + { + .type = VehiclePropertyType::INT32, + .recyclable = true, + .vecSize = 1, + }, + { + .type = VehiclePropertyType::INT64, + .recyclable = true, + .vecSize = 1, + }, + { + .type = VehiclePropertyType::FLOAT, + .recyclable = true, + .vecSize = 1, + }, + { + .type = VehiclePropertyType::INT32_VEC, + .recyclable = true, + .vecSize = 4, + }, + { + .type = VehiclePropertyType::INT64_VEC, + .recyclable = true, + .vecSize = 4, + }, + { + .type = VehiclePropertyType::FLOAT_VEC, + .recyclable = true, + .vecSize = 4, + }, + { + .type = VehiclePropertyType::BYTES, + .recyclable = true, + .vecSize = 4, + }, + { + .type = VehiclePropertyType::INT32_VEC, + .recyclable = false, + .vecSize = 5, + }, + { + .type = VehiclePropertyType::INT64_VEC, + .recyclable = false, + .vecSize = 5, + }, + { + .type = VehiclePropertyType::FLOAT_VEC, + .recyclable = false, + .vecSize = 5, + }, + { + .type = VehiclePropertyType::BYTES, + .recyclable = false, + .vecSize = 5, + }, + { + .type = VehiclePropertyType::STRING, + .recyclable = false, + .vecSize = 0, + }, + { + .type = VehiclePropertyType::MIXED, + .recyclable = false, + .vecSize = 0, + }, + }; +} + +} // namespace + +class VehicleObjectPoolTest : public ::testing::Test { + protected: + void SetUp() override { + mStats = PoolStats::instance(); + resetStats(); + mValuePool.reset(new VehiclePropValuePool); + } + + void TearDown() override { + // At the end, all created objects should be either recycled or deleted. + ASSERT_EQ(mStats->Obtained, mStats->Recycled + mStats->Deleted); + // Some objects could be recycled multiple times. + ASSERT_LE(mStats->Created, mStats->Recycled + mStats->Deleted); + } + + PoolStats* mStats; + std::unique_ptr<VehiclePropValuePool> mValuePool; + + private: + void resetStats() { + mStats->Obtained = 0; + mStats->Created = 0; + mStats->Recycled = 0; + mStats->Deleted = 0; + } +}; + +class VehiclePropertyTypesTest : public VehicleObjectPoolTest, + public testing::WithParamInterface<TestPropertyTypeInfo> {}; + +TEST_P(VehiclePropertyTypesTest, testRecycle) { + auto info = GetParam(); + if (!info.recyclable) { + GTEST_SKIP(); + } + + auto value = mValuePool->obtain(info.type, info.vecSize); + void* raw = value.get(); + value.reset(); + // At this point, value should be recycled and the only object in the pool. + ASSERT_EQ(mValuePool->obtain(info.type, info.vecSize).get(), raw); + + ASSERT_EQ(mStats->Obtained, 2u); + ASSERT_EQ(mStats->Created, 1u); +} + +TEST_P(VehiclePropertyTypesTest, testNotRecyclable) { + auto info = GetParam(); + if (info.recyclable) { + GTEST_SKIP(); + } + + auto value = mValuePool->obtain(info.type, info.vecSize); + + ASSERT_EQ(mStats->Obtained, 0u) << "Non recyclable object should not be obtained from the pool"; + ASSERT_EQ(mStats->Created, 0u) << "Non recyclable object should not be created from the pool"; +} + +INSTANTIATE_TEST_SUITE_P(AllPropertyTypes, VehiclePropertyTypesTest, + ::testing::ValuesIn(getAllPropertyTypes())); + +TEST_F(VehicleObjectPoolTest, testObtainNewObject) { + auto value = mValuePool->obtain(VehiclePropertyType::INT32); + void* raw = value.get(); + value.reset(); + // At this point, value should be recycled and the only object in the pool. + ASSERT_EQ(mValuePool->obtain(VehiclePropertyType::INT32).get(), raw); + // Obtaining value of another type - should return a new object + ASSERT_NE(mValuePool->obtain(VehiclePropertyType::FLOAT).get(), raw); + + ASSERT_EQ(mStats->Obtained, 3u); + ASSERT_EQ(mStats->Created, 2u); +} + +TEST_F(VehicleObjectPoolTest, testObtainStrings) { + mValuePool->obtain(VehiclePropertyType::STRING); + auto stringProp = mValuePool->obtain(VehiclePropertyType::STRING); + stringProp->value.stringValue = "Hello"; + void* raw = stringProp.get(); + stringProp.reset(); // delete the pointer + + auto newStringProp = mValuePool->obtain(VehiclePropertyType::STRING); + + ASSERT_EQ(newStringProp->value.stringValue.size(), 0u); + ASSERT_NE(mValuePool->obtain(VehiclePropertyType::STRING).get(), raw); + ASSERT_EQ(mStats->Obtained, 0u); +} + +TEST_F(VehicleObjectPoolTest, testObtainBoolean) { + auto prop = mValuePool->obtainBoolean(true); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, (VehiclePropValue{ + .value = {.int32Values = {1}}, + })); +} + +TEST_F(VehicleObjectPoolTest, testObtainInt32) { + auto prop = mValuePool->obtainInt32(1234); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, (VehiclePropValue{ + .value = {.int32Values = {1234}}, + })); +} + +TEST_F(VehicleObjectPoolTest, testObtainInt64) { + auto prop = mValuePool->obtainInt64(1234); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, (VehiclePropValue{ + .value = {.int64Values = {1234}}, + })); +} + +TEST_F(VehicleObjectPoolTest, testObtainFloat) { + auto prop = mValuePool->obtainFloat(1.234); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, (VehiclePropValue{ + .value = {.floatValues = {1.234}}, + })); +} + +TEST_F(VehicleObjectPoolTest, testObtainString) { + auto prop = mValuePool->obtainString("test"); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, (VehiclePropValue{ + .value = {.stringValue = "test"}, + })); +} + +TEST_F(VehicleObjectPoolTest, testObtainComplex) { + auto prop = mValuePool->obtainComplex(); + + ASSERT_NE(prop, nullptr); + ASSERT_EQ(*prop, VehiclePropValue{}); +} + +TEST_F(VehicleObjectPoolTest, testObtainCopyInt32Values) { + VehiclePropValue prop{ + // INT32_VEC property. + .prop = toInt(VehicleProperty::INFO_FUEL_TYPE), + .areaId = 2, + .timestamp = 3, + .value = {.int32Values = {1, 2, 3, 4}}, + }; + auto gotValue = mValuePool->obtain(prop); + + ASSERT_NE(gotValue, nullptr); + ASSERT_EQ(*gotValue, prop); +} + +TEST_F(VehicleObjectPoolTest, testObtainCopyInt64Values) { + VehiclePropValue prop{ + // INT64_VEC property. + .prop = toInt(VehicleProperty::WHEEL_TICK), + .areaId = 2, + .timestamp = 3, + .value = {.int64Values = {1, 2, 3, 4}}, + }; + auto gotValue = mValuePool->obtain(prop); + + ASSERT_NE(gotValue, nullptr); + ASSERT_EQ(*gotValue, prop); +} + +TEST_F(VehicleObjectPoolTest, testObtainCopyFloatValues) { + VehiclePropValue prop{ + // FLOAT_VEC property. + .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION), + .areaId = 2, + .timestamp = 3, + .value = {.floatValues = {1, 2, 3, 4}}, + }; + auto gotValue = mValuePool->obtain(prop); + + ASSERT_NE(gotValue, nullptr); + ASSERT_EQ(*gotValue, prop); +} + +TEST_F(VehicleObjectPoolTest, testObtainCopyString) { + VehiclePropValue prop{ + // STRING property. + .prop = toInt(VehicleProperty::INFO_VIN), + .areaId = 2, + .timestamp = 3, + .value = {.stringValue = "test"}, + }; + auto gotValue = mValuePool->obtain(prop); + + ASSERT_NE(gotValue, nullptr); + ASSERT_EQ(*gotValue, prop); +} + +TEST_F(VehicleObjectPoolTest, testObtainCopyMixed) { + VehiclePropValue prop{ + // MIxed property. + .prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE), + .areaId = 2, + .timestamp = 3, + .value = + { + .int32Values = {1, 2, 3}, + .floatValues = {4.0, 5.0}, + .stringValue = "test", + }, + }; + auto gotValue = mValuePool->obtain(prop); + + ASSERT_NE(gotValue, nullptr); + ASSERT_EQ(*gotValue, prop); +} + +TEST_F(VehicleObjectPoolTest, testMultithreaded) { + // In this test we have T threads that concurrently in C cycles + // obtain and release O VehiclePropValue objects of FLOAT / INT32 types. + + const int T = 2; + const int C = 500; + const int O = 100; + + auto poolPtr = mValuePool.get(); + + std::vector<std::thread> threads; + for (int i = 0; i < T; i++) { + threads.push_back(std::thread([&poolPtr]() { + for (int j = 0; j < C; j++) { + std::vector<recyclable_ptr<VehiclePropValue>> vec; + for (int k = 0; k < O; k++) { + vec.push_back(poolPtr->obtain(k % 2 == 0 ? VehiclePropertyType::FLOAT + : VehiclePropertyType::INT32)); + } + } + })); + } + + for (auto& t : threads) { + t.join(); + } + + ASSERT_EQ(mStats->Obtained, static_cast<uint32_t>(T * C * O)); + ASSERT_EQ(mStats->Recycled + mStats->Deleted, static_cast<uint32_t>(T * C * O)); + // Created less than obtained in one cycle. + ASSERT_LE(mStats->Created, static_cast<uint32_t>(T * O)); +} + +TEST_F(VehicleObjectPoolTest, testMemoryLimitation) { + std::vector<recyclable_ptr<VehiclePropValue>> vec; + for (size_t i = 0; i < 10000; i++) { + vec.push_back(mValuePool->obtain(VehiclePropertyType::INT32)); + } + // We have too many values, not all of them would be recycled, some of them will be deleted. + vec.clear(); + + ASSERT_EQ(mStats->Obtained, 10000u); + ASSERT_EQ(mStats->Created, 10000u); + ASSERT_GT(mStats->Deleted, 0u) << "expect some values to be deleted, not recycled if too many " + "values are in the pool"; +} + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android |