1 /*
2 * Copyright (C) 2017 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 #define LOG_TAG "health_hidl_hal_test"
18
19 #include <mutex>
20 #include <set>
21 #include <string>
22
23 #include <VtsHalHidlTargetTestBase.h>
24 #include <android-base/logging.h>
25 #include <android/hardware/health/2.0/IHealth.h>
26 #include <android/hardware/health/2.0/types.h>
27 #include <gflags/gflags.h>
28
29 using ::testing::AssertionFailure;
30 using ::testing::AssertionResult;
31 using ::testing::AssertionSuccess;
32 using ::testing::VtsHalHidlTargetTestBase;
33 using ::testing::VtsHalHidlTargetTestEnvBase;
34
35 DEFINE_bool(force, false, "Force test healthd even when the default instance is present.");
36
37 // If GTEST_SKIP is not implemented, use our own skipping mechanism
38 #ifndef GTEST_SKIP
39 static std::mutex gSkippedTestsMutex;
40 static std::set<std::string> gSkippedTests;
GetCurrentTestName()41 static std::string GetCurrentTestName() {
42 const auto& info = ::testing::UnitTest::GetInstance()->current_test_info();
43 #ifdef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
44 std::string test_suite = info->test_suite_name();
45 #else
46 std::string test_suite = info->test_case_name();
47 #endif
48 return test_suite + "." + info->name();
49 }
50
51 #define GTEST_SKIP() \
52 do { \
53 std::unique_lock<std::mutex> lock(gSkippedTestsMutex); \
54 gSkippedTests.insert(GetCurrentTestName()); \
55 return; \
56 } while (0)
57
58 #define SKIP_IF_SKIPPED() \
59 do { \
60 std::unique_lock<std::mutex> lock(gSkippedTestsMutex); \
61 if (gSkippedTests.find(GetCurrentTestName()) != gSkippedTests.end()) { \
62 std::cerr << "[ SKIPPED ] " << GetCurrentTestName() << std::endl; \
63 return; \
64 } \
65 } while (0)
66 #else
67 #define SKIP_IF_SKIPPED()
68 #endif
69
70 namespace android {
71 namespace hardware {
72 namespace health {
73 namespace V2_0 {
74
75 using V1_0::BatteryStatus;
76
77 // Test environment for graphics.composer
78 class HealthHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
79 public:
80 // get the test environment singleton
Instance()81 static HealthHidlEnvironment* Instance() {
82 static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
83 return instance;
84 }
85
registerTestServices()86 virtual void registerTestServices() override { registerTestService<IHealth>(); }
87
88 private:
HealthHidlEnvironment()89 HealthHidlEnvironment() {}
90
91 GTEST_DISALLOW_COPY_AND_ASSIGN_(HealthHidlEnvironment);
92 };
93
94 class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
95 public:
SetUp()96 virtual void SetUp() override {
97 std::string serviceName = HealthHidlEnvironment::Instance()->getServiceName<IHealth>();
98
99 if (serviceName == "backup" && !FLAGS_force &&
100 ::testing::VtsHalHidlTargetTestBase::getService<IHealth>() != nullptr) {
101 LOG(INFO) << "Skipping tests on healthd because the default instance is present. "
102 << "Use --force if you really want to test healthd.";
103 GTEST_SKIP();
104 }
105
106 LOG(INFO) << "get service with name:" << serviceName;
107 ASSERT_FALSE(serviceName.empty());
108 mHealth = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(serviceName);
109 ASSERT_NE(mHealth, nullptr);
110 }
111
112 sp<IHealth> mHealth;
113 };
114
115 class Callback : public IHealthInfoCallback {
116 public:
healthInfoChanged(const HealthInfo &)117 Return<void> healthInfoChanged(const HealthInfo&) override {
118 std::lock_guard<std::mutex> lock(mMutex);
119 mInvoked = true;
120 mInvokedNotify.notify_all();
121 return Void();
122 }
123 template <typename R, typename P>
waitInvoke(std::chrono::duration<R,P> duration)124 bool waitInvoke(std::chrono::duration<R, P> duration) {
125 std::unique_lock<std::mutex> lock(mMutex);
126 bool r = mInvokedNotify.wait_for(lock, duration, [this] { return this->mInvoked; });
127 mInvoked = false;
128 return r;
129 }
130 private:
131 std::mutex mMutex;
132 std::condition_variable mInvokedNotify;
133 bool mInvoked = false;
134 };
135
136 #define ASSERT_OK(r) ASSERT_TRUE(isOk(r))
137 #define EXPECT_OK(r) EXPECT_TRUE(isOk(r))
138 template <typename T>
isOk(const Return<T> & r)139 AssertionResult isOk(const Return<T>& r) {
140 return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
141 }
142
143 #define ASSERT_ALL_OK(r) ASSERT_TRUE(isAllOk(r))
144 // Both isOk() and Result::SUCCESS
isAllOk(const Return<Result> & r)145 AssertionResult isAllOk(const Return<Result>& r) {
146 if (!r.isOk()) {
147 return AssertionFailure() << r.description();
148 }
149 if (static_cast<Result>(r) != Result::SUCCESS) {
150 return AssertionFailure() << toString(static_cast<Result>(r));
151 }
152 return AssertionSuccess();
153 }
154
155 /**
156 * Test whether callbacks work. Tested functions are IHealth::registerCallback,
157 * unregisterCallback, and update.
158 */
TEST_F(HealthHidlTest,Callbacks)159 TEST_F(HealthHidlTest, Callbacks) {
160 SKIP_IF_SKIPPED();
161 using namespace std::chrono_literals;
162 sp<Callback> firstCallback = new Callback();
163 sp<Callback> secondCallback = new Callback();
164
165 ASSERT_ALL_OK(mHealth->registerCallback(firstCallback));
166 ASSERT_ALL_OK(mHealth->registerCallback(secondCallback));
167
168 // registerCallback may or may not invoke the callback immediately, so the test needs
169 // to wait for the invocation. If the implementation chooses not to invoke the callback
170 // immediately, just wait for some time.
171 firstCallback->waitInvoke(200ms);
172 secondCallback->waitInvoke(200ms);
173
174 // assert that the first callback is invoked when update is called.
175 ASSERT_ALL_OK(mHealth->update());
176
177 ASSERT_TRUE(firstCallback->waitInvoke(1s));
178 ASSERT_TRUE(secondCallback->waitInvoke(1s));
179
180 ASSERT_ALL_OK(mHealth->unregisterCallback(firstCallback));
181
182 // clear any potentially pending callbacks result from wakealarm / kernel events
183 // If there is none, just wait for some time.
184 firstCallback->waitInvoke(200ms);
185 secondCallback->waitInvoke(200ms);
186
187 // assert that the second callback is still invoked even though the first is unregistered.
188 ASSERT_ALL_OK(mHealth->update());
189
190 ASSERT_FALSE(firstCallback->waitInvoke(200ms));
191 ASSERT_TRUE(secondCallback->waitInvoke(1s));
192
193 ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
194 }
195
TEST_F(HealthHidlTest,UnregisterNonExistentCallback)196 TEST_F(HealthHidlTest, UnregisterNonExistentCallback) {
197 SKIP_IF_SKIPPED();
198 sp<Callback> callback = new Callback();
199 auto ret = mHealth->unregisterCallback(callback);
200 ASSERT_OK(ret);
201 ASSERT_EQ(Result::NOT_FOUND, static_cast<Result>(ret)) << "Actual: " << toString(ret);
202 }
203
204 /**
205 * Pass the test if:
206 * - Property is not supported (res == NOT_SUPPORTED)
207 * - Result is success, and predicate is true
208 * @param res the Result value.
209 * @param valueStr the string representation for actual value (for error message)
210 * @param pred a predicate that test whether the value is valid
211 */
212 #define EXPECT_VALID_OR_UNSUPPORTED_PROP(res, valueStr, pred) \
213 EXPECT_TRUE(isPropertyOk(res, valueStr, pred, #pred))
214
isPropertyOk(Result res,const std::string & valueStr,bool pred,const std::string & predStr)215 AssertionResult isPropertyOk(Result res, const std::string& valueStr, bool pred,
216 const std::string& predStr) {
217 if (res == Result::SUCCESS) {
218 if (pred) {
219 return AssertionSuccess();
220 }
221 return AssertionFailure() << "value doesn't match.\nActual: " << valueStr
222 << "\nExpected: " << predStr;
223 }
224 if (res == Result::NOT_SUPPORTED) {
225 return AssertionSuccess();
226 }
227 return AssertionFailure() << "Result is not SUCCESS or NOT_SUPPORTED: " << toString(res);
228 }
229
verifyStorageInfo(const hidl_vec<struct StorageInfo> & info)230 bool verifyStorageInfo(const hidl_vec<struct StorageInfo>& info) {
231 for (size_t i = 0; i < info.size(); i++) {
232 if (!(0 <= info[i].eol && info[i].eol <= 3 && 0 <= info[i].lifetimeA &&
233 info[i].lifetimeA <= 0x0B && 0 <= info[i].lifetimeB && info[i].lifetimeB <= 0x0B)) {
234 return false;
235 }
236 }
237
238 return true;
239 }
240
241 template <typename T>
verifyEnum(T value)242 bool verifyEnum(T value) {
243 for (auto it : hidl_enum_range<T>()) {
244 if (it == value) {
245 return true;
246 }
247 }
248
249 return false;
250 }
251
verifyHealthInfo(const HealthInfo & health_info)252 bool verifyHealthInfo(const HealthInfo& health_info) {
253 if (!verifyStorageInfo(health_info.storageInfos)) {
254 return false;
255 }
256
257 using V1_0::BatteryStatus;
258 using V1_0::BatteryHealth;
259
260 if (!((health_info.legacy.batteryChargeCounter > 0) &&
261 (health_info.legacy.batteryCurrent != INT32_MIN) &&
262 (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
263 verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
264 (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
265 verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
266 return false;
267 }
268
269 return true;
270 }
271
272 /*
273 * Tests the values returned by getChargeCounter() from interface IHealth.
274 */
TEST_F(HealthHidlTest,getChargeCounter)275 TEST_F(HealthHidlTest, getChargeCounter) {
276 SKIP_IF_SKIPPED();
277 EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
278 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
279 }));
280 }
281
282 /*
283 * Tests the values returned by getCurrentNow() from interface IHealth.
284 */
TEST_F(HealthHidlTest,getCurrentNow)285 TEST_F(HealthHidlTest, getCurrentNow) {
286 SKIP_IF_SKIPPED();
287 EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) {
288 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
289 }));
290 }
291
292 /*
293 * Tests the values returned by getCurrentAverage() from interface IHealth.
294 */
TEST_F(HealthHidlTest,getCurrentAverage)295 TEST_F(HealthHidlTest, getCurrentAverage) {
296 SKIP_IF_SKIPPED();
297 EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) {
298 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
299 }));
300 }
301
302 /*
303 * Tests the values returned by getCapacity() from interface IHealth.
304 */
TEST_F(HealthHidlTest,getCapacity)305 TEST_F(HealthHidlTest, getCapacity) {
306 SKIP_IF_SKIPPED();
307 EXPECT_OK(mHealth->getCapacity([](auto result, auto value) {
308 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100);
309 }));
310 }
311
312 /*
313 * Tests the values returned by getEnergyCounter() from interface IHealth.
314 */
TEST_F(HealthHidlTest,getEnergyCounter)315 TEST_F(HealthHidlTest, getEnergyCounter) {
316 SKIP_IF_SKIPPED();
317 EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) {
318 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN);
319 }));
320 }
321
322 /*
323 * Tests the values returned by getChargeStatus() from interface IHealth.
324 */
TEST_F(HealthHidlTest,getChargeStatus)325 TEST_F(HealthHidlTest, getChargeStatus) {
326 SKIP_IF_SKIPPED();
327 EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
328 EXPECT_VALID_OR_UNSUPPORTED_PROP(
329 result, toString(value),
330 value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
331 }));
332 }
333
334 /*
335 * Tests the values returned by getStorageInfo() from interface IHealth.
336 */
TEST_F(HealthHidlTest,getStorageInfo)337 TEST_F(HealthHidlTest, getStorageInfo) {
338 SKIP_IF_SKIPPED();
339 EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
340 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
341 }));
342 }
343
344 /*
345 * Tests the values returned by getDiskStats() from interface IHealth.
346 */
TEST_F(HealthHidlTest,getDiskStats)347 TEST_F(HealthHidlTest, getDiskStats) {
348 SKIP_IF_SKIPPED();
349 EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
350 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), true);
351 }));
352 }
353
354 /*
355 * Tests the values returned by getHealthInfo() from interface IHealth.
356 */
TEST_F(HealthHidlTest,getHealthInfo)357 TEST_F(HealthHidlTest, getHealthInfo) {
358 SKIP_IF_SKIPPED();
359 EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
360 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
361 }));
362 }
363
364 } // namespace V2_0
365 } // namespace health
366 } // namespace hardware
367 } // namespace android
368
main(int argc,char ** argv)369 int main(int argc, char** argv) {
370 using ::android::hardware::health::V2_0::HealthHidlEnvironment;
371 ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
372 ::testing::InitGoogleTest(&argc, argv);
373 HealthHidlEnvironment::Instance()->init(&argc, argv);
374 gflags::ParseCommandLineFlags(&argc, &argv, true /* remove flags */);
375 int status = RUN_ALL_TESTS();
376 LOG(INFO) << "Test result = " << status;
377 return status;
378 }
379