From c357e98dcc35fd6283e038d89d8d9da45c9f0e07 Mon Sep 17 00:00:00 2001 From: Benjamin Schwartz Date: Tue, 26 Jan 2021 10:15:23 -0800 Subject: [PATCH] power/stats: Add VTS tests for power stats hal Bug: 165345767 Test: atest VtsHalPowerStatsTargetTest Change-Id: Iba90d106a5be13d817a4a2fb36098781ea2f9ee0 Merged-In: Iba90d106a5be13d817a4a2fb36098781ea2f9ee0 --- .../aidl/vts/VtsHalPowerStatsTargetTest.cpp | 352 ++++++++++++++++-- 1 file changed, 318 insertions(+), 34 deletions(-) diff --git a/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp index f293773383..033bf1a3a4 100644 --- a/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp +++ b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp @@ -21,10 +21,21 @@ #include #include +#include +#include +#include +#include + using aidl::android::hardware::power::stats::Channel; +using aidl::android::hardware::power::stats::EnergyConsumer; +using aidl::android::hardware::power::stats::EnergyConsumerAttribution; +using aidl::android::hardware::power::stats::EnergyConsumerResult; +using aidl::android::hardware::power::stats::EnergyConsumerType; using aidl::android::hardware::power::stats::EnergyMeasurement; using aidl::android::hardware::power::stats::IPowerStats; using aidl::android::hardware::power::stats::PowerEntity; +using aidl::android::hardware::power::stats::State; +using aidl::android::hardware::power::stats::StateResidency; using aidl::android::hardware::power::stats::StateResidencyResult; using ndk::SpAIBinder; @@ -37,12 +48,61 @@ class PowerStatsAidl : public testing::TestWithParam { ASSERT_NE(nullptr, powerstats.get()); } + template + std::vector getRandomSubset(std::vector const& collection); + + void testNameValid(const std::string& name); + + template + void testUnique(std::vector const& collection, S T::*field); + + template + void testMatching(std::vector const& c1, R T::*f1, std::vector const& c2, R S::*f2); + std::shared_ptr powerstats; }; -TEST_P(PowerStatsAidl, TestReadEnergyMeter) { - std::vector data; - ASSERT_TRUE(powerstats->readEnergyMeters({}, &data).isOk()); +// Returns a random subset from a collection +template +std::vector PowerStatsAidl::getRandomSubset(std::vector const& collection) { + if (collection.empty()) { + return {}; + } + + std::vector selected; + std::sample(collection.begin(), collection.end(), std::back_inserter(selected), + rand() % collection.size() + 1, std::mt19937{std::random_device{}()}); + + return selected; +} + +// Tests whether a name is valid +void PowerStatsAidl::testNameValid(const std::string& name) { + EXPECT_NE(name, ""); +} + +// Tests whether the fields in a given collection are unique +template +void PowerStatsAidl::testUnique(std::vector const& collection, S T::*field) { + std::set cSet; + for (auto const& elem : collection) { + EXPECT_TRUE(cSet.insert(elem.*field).second); + } +} + +template +void PowerStatsAidl::testMatching(std::vector const& c1, R T::*f1, std::vector const& c2, + R S::*f2) { + std::set c1fields, c2fields; + for (auto elem : c1) { + c1fields.insert(elem.*f1); + } + + for (auto elem : c2) { + c2fields.insert(elem.*f2); + } + + EXPECT_EQ(c1fields, c2fields); } // Each PowerEntity must have a valid name @@ -51,80 +111,304 @@ TEST_P(PowerStatsAidl, ValidatePowerEntityNames) { ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); for (auto info : infos) { - EXPECT_NE(info.name, ""); + testNameValid(info.name); } } // Each power entity must have a unique name TEST_P(PowerStatsAidl, ValidatePowerEntityUniqueNames) { - std::vector infos; - ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); - std::set names; - for (auto info : infos) { - EXPECT_TRUE(names.insert(info.name).second); - } + testUnique(entities, &PowerEntity::name); } // Each PowerEntity must have a unique ID TEST_P(PowerStatsAidl, ValidatePowerEntityIds) { - std::vector infos; - ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); - std::set ids; - for (auto info : infos) { - EXPECT_TRUE(ids.insert(info.id).second); + testUnique(entities, &PowerEntity::id); +} + +// Each power entity must have at least one state +TEST_P(PowerStatsAidl, ValidateStateSize) { + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); + + for (auto entity : entities) { + EXPECT_GT(entity.states.size(), 0); } } // Each state must have a valid name TEST_P(PowerStatsAidl, ValidateStateNames) { - std::vector infos; - ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); - for (auto info : infos) { - for (auto state : info.states) { - EXPECT_NE(state.name, ""); + for (auto entity : entities) { + for (auto state : entity.states) { + testNameValid(state.name); } } } // Each state must have a name that is unique to the given PowerEntity TEST_P(PowerStatsAidl, ValidateStateUniqueNames) { - std::vector infos; - ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); - for (auto info : infos) { - std::set stateNames; - for (auto state : info.states) { - EXPECT_TRUE(stateNames.insert(state.name).second); - } + for (auto entity : entities) { + testUnique(entity.states, &State::name); } } // Each state must have an ID that is unique to the given PowerEntity TEST_P(PowerStatsAidl, ValidateStateUniqueIds) { - std::vector infos; - ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk()); + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); - for (auto info : infos) { - std::set stateIds; - for (auto state : info.states) { - EXPECT_TRUE(stateIds.insert(state.id).second); - } + for (auto entity : entities) { + testUnique(entity.states, &State::id); } } +// State residency must return a valid status TEST_P(PowerStatsAidl, TestGetStateResidency) { std::vector results; ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk()); } +// State residency must return all results +TEST_P(PowerStatsAidl, TestGetStateResidencyAllResults) { + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); + + std::vector results; + ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk()); + + testMatching(entities, &PowerEntity::id, results, &StateResidencyResult::id); +} + +// Each result must contain all state residencies +TEST_P(PowerStatsAidl, TestGetStateResidencyAllStateResidencies) { + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); + + std::vector results; + ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk()); + + for (auto entity : entities) { + auto it = std::find_if(results.begin(), results.end(), + [&entity](const auto& x) { return x.id == entity.id; }); + ASSERT_NE(it, results.end()); + + testMatching(entity.states, &State::id, it->stateResidencyData, &StateResidency::id); + } +} + +// State residency must return results for each requested power entity +TEST_P(PowerStatsAidl, TestGetStateResidencySelectedResults) { + std::vector entities; + ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk()); + if (entities.empty()) { + return; + } + + std::vector selectedEntities = getRandomSubset(entities); + std::vector selectedIds; + for (auto const& entity : selectedEntities) { + selectedIds.push_back(entity.id); + } + + std::vector selectedResults; + ASSERT_TRUE(powerstats->getStateResidency(selectedIds, &selectedResults).isOk()); + + testMatching(selectedEntities, &PowerEntity::id, selectedResults, &StateResidencyResult::id); +} + +// Energy meter info must return a valid status TEST_P(PowerStatsAidl, TestGetEnergyMeterInfo) { std::vector info; ASSERT_TRUE(powerstats->getEnergyMeterInfo(&info).isOk()); } +// Each channel must have a valid name and subsystem +TEST_P(PowerStatsAidl, ValidateChannelNames) { + std::vector channels; + ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk()); + for (auto channel : channels) { + testNameValid(channel.name); + testNameValid(channel.subsystem); + } +} + +// Each channel must have a unique name +TEST_P(PowerStatsAidl, ValidateChannelUniqueNames) { + std::vector channels; + ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk()); + + testUnique(channels, &Channel::name); +} + +// Each channel must have a unique ID +TEST_P(PowerStatsAidl, ValidateChannelUniqueIds) { + std::vector channels; + ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk()); + + testUnique(channels, &Channel::id); +} + +// Reading energy meter must return a valid status +TEST_P(PowerStatsAidl, TestReadEnergyMeter) { + std::vector data; + ASSERT_TRUE(powerstats->readEnergyMeters({}, &data).isOk()); +} + +// Reading energy meter must return results for all available channels +TEST_P(PowerStatsAidl, TestGetAllEnergyMeasurements) { + std::vector channels; + ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk()); + + std::vector measurements; + ASSERT_TRUE(powerstats->readEnergyMeters({}, &measurements).isOk()); + + testMatching(channels, &Channel::id, measurements, &EnergyMeasurement::id); +} + +// Reading energy must must return results for each selected channel +TEST_P(PowerStatsAidl, TestGetSelectedEnergyMeasurements) { + std::vector channels; + ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk()); + if (channels.empty()) { + return; + } + + std::vector selectedChannels = getRandomSubset(channels); + std::vector selectedIds; + for (auto const& channel : selectedChannels) { + selectedIds.push_back(channel.id); + } + + std::vector selectedMeasurements; + ASSERT_TRUE(powerstats->readEnergyMeters(selectedIds, &selectedMeasurements).isOk()); + + testMatching(selectedChannels, &Channel::id, selectedMeasurements, &EnergyMeasurement::id); +} + +// Energy consumer info must return a valid status +TEST_P(PowerStatsAidl, TestGetEnergyConsumerInfo) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); +} + +// Each energy consumer must have a unique id +TEST_P(PowerStatsAidl, TestGetEnergyConsumerUniqueId) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + + testUnique(consumers, &EnergyConsumer::id); +} + +// Each energy consumer must have a valid name +TEST_P(PowerStatsAidl, ValidateEnergyConsumerNames) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + + for (auto consumer : consumers) { + testNameValid(consumer.name); + } +} + +// Each energy consumer must have a unique name +TEST_P(PowerStatsAidl, ValidateEnergyConsumerUniqueNames) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + + testUnique(consumers, &EnergyConsumer::name); +} + +// Energy consumers of the same type must have ordinals that are 0,1,2,..., N - 1 +TEST_P(PowerStatsAidl, ValidateEnergyConsumerOrdinals) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + + std::unordered_map> ordinalMap; + + // Ordinals must be unique for each type + for (auto consumer : consumers) { + EXPECT_TRUE(ordinalMap[consumer.type].insert(consumer.ordinal).second); + } + + // Min ordinal must be 0, max ordinal must be N - 1 + for (const auto& [unused, ordinals] : ordinalMap) { + EXPECT_EQ(0, *std::min_element(ordinals.begin(), ordinals.end())); + EXPECT_EQ(ordinals.size() - 1, *std::max_element(ordinals.begin(), ordinals.end())); + } +} + +// Energy consumed must return a valid status +TEST_P(PowerStatsAidl, TestGetEnergyConsumed) { + std::vector results; + ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk()); +} + +// Energy consumed must return data for all energy consumers +TEST_P(PowerStatsAidl, TestGetAllEnergyConsumed) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + + std::vector results; + ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk()); + + testMatching(consumers, &EnergyConsumer::id, results, &EnergyConsumerResult::id); +} + +// Energy consumed must return data for each selected energy consumer +TEST_P(PowerStatsAidl, TestGetSelectedEnergyConsumed) { + std::vector consumers; + ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk()); + if (consumers.empty()) { + return; + } + + std::vector selectedConsumers = getRandomSubset(consumers); + std::vector selectedIds; + for (auto const& consumer : selectedConsumers) { + selectedIds.push_back(consumer.id); + } + + std::vector selectedResults; + ASSERT_TRUE(powerstats->getEnergyConsumed(selectedIds, &selectedResults).isOk()); + + testMatching(selectedConsumers, &EnergyConsumer::id, selectedResults, + &EnergyConsumerResult::id); +} + +// Energy consumed attribution uids must be unique for a given energy consumer +TEST_P(PowerStatsAidl, ValidateEnergyConsumerAttributionUniqueUids) { + std::vector results; + ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk()); + + for (auto result : results) { + testUnique(result.attribution, &EnergyConsumerAttribution::uid); + } +} + +// Energy consumed total energy >= sum total of uid-attributed energy +TEST_P(PowerStatsAidl, TestGetEnergyConsumedAttributedEnergy) { + std::vector results; + ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk()); + + for (auto result : results) { + int64_t totalAttributedEnergyUWs = 0; + for (auto attribution : result.attribution) { + totalAttributedEnergyUWs += attribution.energyUWs; + } + EXPECT_TRUE(result.energyUWs >= totalAttributedEnergyUWs); + } +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerStatsAidl); INSTANTIATE_TEST_SUITE_P( PowerStats, PowerStatsAidl,