blob: b7aace302df0aa4bfefd353a9bc0d1501d564c6f [file] [log] [blame]
Yifan Hongc2bed972020-08-07 16:27:49 -07001/*
2 * Copyright (C) 2020 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#include <sysexits.h>
18#include <unistd.h>
19
20#include <iostream>
21#include <string>
22
23#include <android-base/file.h>
24#include <android-base/logging.h>
25#include <android-base/strings.h>
Yifan Hongb5d70332021-10-20 17:15:32 -070026#include <android/hardware/health/2.1/IHealth.h>
Yifan Hongc2bed972020-08-07 16:27:49 -070027#include <gmock/gmock.h>
28#include <gtest/gtest.h>
29#include <health/utils.h>
30
Yifan Hongb5d70332021-10-20 17:15:32 -070031#include "healthd_mode_charger_hidl.h"
Yifan Hongc2bed972020-08-07 16:27:49 -070032
33using android::hardware::Return;
34using android::hardware::health::InitHealthdConfig;
35using std::string_literals::operator""s;
36using testing::_;
37using testing::Invoke;
38using testing::NiceMock;
39using testing::StrEq;
40using testing::Test;
41
42namespace android {
43
44// A replacement to ASSERT_* to be used in a forked process. When the condition is not met,
45// print a gtest message, then exit abnormally.
46class ChildAssertHelper : public std::stringstream {
47 public:
48 ChildAssertHelper(bool res, const char* expr, const char* file, int line) : res_(res) {
49 (*this) << file << ":" << line << ": `" << expr << "` evaluates to false\n";
50 }
51 ~ChildAssertHelper() {
52 EXPECT_TRUE(res_) << str();
53 if (!res_) exit(EX_SOFTWARE);
54 }
55
56 private:
57 bool res_;
58 DISALLOW_COPY_AND_ASSIGN(ChildAssertHelper);
59};
60#define CHILD_ASSERT_TRUE(expr) ChildAssertHelper(expr, #expr, __FILE__, __LINE__)
61
62// Run |test_body| in a chroot jail in a forked process. |subdir| is a sub-directory in testdata.
63// Within |test_body|,
64// - non-fatal errors may be reported using EXPECT_* macro as usual.
65// - fatal errors must be reported using CHILD_ASSERT_TRUE macro. ASSERT_* must not be used.
66void ForkTest(const std::string& subdir, const std::function<void(void)>& test_body) {
67 pid_t pid = fork();
68 ASSERT_GE(pid, 0) << "Fork fails: " << strerror(errno);
69 if (pid == 0) {
70 // child
71 CHILD_ASSERT_TRUE(
72 chroot((android::base::GetExecutableDirectory() + "/" + subdir).c_str()) != -1)
73 << "Failed to chroot to " << subdir << ": " << strerror(errno);
74 test_body();
75 // EXPECT_* macros may set the HasFailure bit without calling exit(). Set exit status
76 // accordingly.
77 exit(::testing::Test::HasFailure() ? EX_SOFTWARE : EX_OK);
78 }
79 // parent
80 int status;
81 ASSERT_NE(-1, waitpid(pid, &status, 0)) << "waitpid() fails: " << strerror(errno);
82 ASSERT_TRUE(WIFEXITED(status)) << "Test fails, waitpid() returns " << status;
83 ASSERT_EQ(EX_OK, WEXITSTATUS(status)) << "Test fails, child process returns " << status;
84}
85
86class MockHealth : public android::hardware::health::V2_1::IHealth {
87 MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, registerCallback,
88 (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
89 MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, unregisterCallback,
90 (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
91 MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, update, ());
92 MOCK_METHOD(Return<void>, getChargeCounter, (getChargeCounter_cb _hidl_cb));
93 MOCK_METHOD(Return<void>, getCurrentNow, (getCurrentNow_cb _hidl_cb));
94 MOCK_METHOD(Return<void>, getCurrentAverage, (getCurrentAverage_cb _hidl_cb));
95 MOCK_METHOD(Return<void>, getCapacity, (getCapacity_cb _hidl_cb));
96 MOCK_METHOD(Return<void>, getEnergyCounter, (getEnergyCounter_cb _hidl_cb));
97 MOCK_METHOD(Return<void>, getChargeStatus, (getChargeStatus_cb _hidl_cb));
98 MOCK_METHOD(Return<void>, getStorageInfo, (getStorageInfo_cb _hidl_cb));
99 MOCK_METHOD(Return<void>, getDiskStats, (getDiskStats_cb _hidl_cb));
100 MOCK_METHOD(Return<void>, getHealthInfo, (getHealthInfo_cb _hidl_cb));
101 MOCK_METHOD(Return<void>, getHealthConfig, (getHealthConfig_cb _hidl_cb));
102 MOCK_METHOD(Return<void>, getHealthInfo_2_1, (getHealthInfo_2_1_cb _hidl_cb));
103 MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
104};
105
Yifan Hongb5d70332021-10-20 17:15:32 -0700106class TestCharger : public ChargerHidl {
Yifan Hongc2bed972020-08-07 16:27:49 -0700107 public:
108 // Inherit constructor.
Yifan Hongb5d70332021-10-20 17:15:32 -0700109 using ChargerHidl::ChargerHidl;
Yifan Hongc2bed972020-08-07 16:27:49 -0700110 // Expose protected functions to be used in tests.
Yifan Hongb5d70332021-10-20 17:15:32 -0700111 void Init(struct healthd_config* config) override { ChargerHidl::Init(config); }
Yifan Hongc2bed972020-08-07 16:27:49 -0700112 MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
113 MOCK_METHOD(int, CreateMultiDisplaySurface,
114 (const std::string& name, int* frames, int* fps, GRSurface*** surface));
115};
116
117// Intentionally leak TestCharger instance to avoid calling ~HealthLoop() because ~HealthLoop()
118// should never be called. But still verify expected calls upon destruction.
119class VerifiedTestCharger {
120 public:
121 VerifiedTestCharger(TestCharger* charger) : charger_(charger) {
122 testing::Mock::AllowLeak(charger_);
123 }
124 TestCharger& operator*() { return *charger_; }
125 TestCharger* operator->() { return charger_; }
126 ~VerifiedTestCharger() { testing::Mock::VerifyAndClearExpectations(charger_); }
127
128 private:
129 TestCharger* charger_;
130};
131
132// Do not use SetUp and TearDown of a test suite, as they will be invoked in the parent process, not
133// the child process. In particular, if the test suite contains mocks, they will not be verified in
134// the child process. Instead, create mocks within closures in each tests.
135void ExpectChargerResAt(const std::string& root) {
136 sp<NiceMock<MockHealth>> health(new NiceMock<MockHealth>());
137 VerifiedTestCharger charger(new NiceMock<TestCharger>(health));
138
139 // Only one frame in all testdata/**/animation.txt
140 GRSurface* multi[] = {nullptr};
141
142 EXPECT_CALL(*charger, CreateDisplaySurface(StrEq(root + "charger/battery_fail.png"), _))
143 .WillRepeatedly(Invoke([](const auto&, GRSurface** surface) {
144 *surface = nullptr;
145 return 0;
146 }));
147 EXPECT_CALL(*charger,
148 CreateMultiDisplaySurface(StrEq(root + "charger/battery_scale.png"), _, _, _))
149 .WillRepeatedly(Invoke([&](const auto&, int* frames, int* fps, GRSurface*** surface) {
150 *frames = arraysize(multi);
151 *fps = 60; // Unused fps value
152 *surface = multi;
153 return 0;
154 }));
155 struct healthd_config healthd_config;
156 InitHealthdConfig(&healthd_config);
157 charger->Init(&healthd_config);
158};
159
160// Test that if resources does not exist in /res or in /product/etc/res, load from /system.
161TEST(ChargerLoadAnimationRes, Empty) {
162 ForkTest("empty", std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
163}
164
165// Test loading everything from /res
166TEST(ChargerLoadAnimationRes, Legacy) {
167 ForkTest("legacy", std::bind(&ExpectChargerResAt, "/res/images/"));
168}
169
170// Test loading animation text from /res but images from /system if images does not exist under
171// /res.
172TEST(ChargerLoadAnimationRes, LegacyTextSystemImages) {
173 ForkTest("legacy_text_system_images",
174 std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
175}
176
177// Test loading everything from /product
178TEST(ChargerLoadAnimationRes, Product) {
179 ForkTest("product", std::bind(&ExpectChargerResAt, "/product/etc/res/images/"));
180}
181
182} // namespace android