• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hotplug_detector.h"
17 
18 #include <cstdio>
19 #include <fstream>
20 #include <iostream>
21 #include <map>
22 #include <system_error>
23 
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include <linux/uinput.h>
29 #include <poll.h>
30 #include <sys/stat.h>
31 
32 using ::testing::StartsWith;
33 using ::testing::ext::TestSize;
34 
35 constexpr auto DEV_INPUT_PATH = "/dev/input/";
36 
SystemError()37 auto SystemError()
38 {
39     return std::error_code{ errno, std::system_category() };
40 }
41 
42 class HotplugTest : public ::testing::Test {
43 public:
44 };
45 
46 class FakeInputDevice {
47 public:
48     void Create();
49     void Destroy();
50 
51 private:
52     int fd_ = -1;
53 };
54 
Create()55 void FakeInputDevice::Create()
56 {
57     fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC);
58     auto err = SystemError();
59     ASSERT_GE(fd_, 0) << "Failed to create uinput device. Error: " << err.message() <<
60         (err == std::errc::permission_denied ? ". Run test as ROOT!" : "") << std::endl;
61     int res = ioctl(fd_, UI_SET_EVBIT, EV_KEY);
62     ASSERT_GE(res, 0) << "Operation UI_SET_EVBIT failed. Error: " << SystemError().message() << std::endl;
63     res = ioctl(fd_, UI_SET_KEYBIT, KEY_SPACE);
64     ASSERT_GE(res, 0) << "Operation UI_SET_KEYBIT failed. Error: " << SystemError().message() << std::endl;
65 
66     uinput_setup usetup{};
67     usetup.id.bustype = BUS_USB;
68     usetup.id.vendor = 0x1234;  /* sample vendor */
69     usetup.id.product = 0x5678; /* sample product */
70     std::string dev("Example device");
71     std::copy(dev.begin(), dev.end(), usetup.name);
72     res = ioctl(fd_, UI_DEV_SETUP, &usetup);
73     ASSERT_GE(res, 0) << "Operation UI_DEV_SETUP failed. Error: " << SystemError().message() << std::endl;
74     res = ioctl(fd_, UI_DEV_CREATE);
75     ASSERT_GE(res, 0) << "Operation UI_DEV_CREATE failed. Error: " << SystemError().message() << std::endl;
76 }
77 
Destroy()78 void FakeInputDevice::Destroy()
79 {
80     auto res = ioctl(fd_, UI_DEV_DESTROY);
81     ASSERT_GE(res, 0) << "Operation UI_DEV_DESTROY failed. Error: " << SystemError().message() << std::endl;
82     close(fd_);
83     fd_ = -1;
84 }
85 
Exists(const std::string & path)86 bool Exists(const std::string &path)
87 {
88     std::ifstream file{ path };
89     return file.good();
90 }
91 
PollEvents(const OHOS::MMI::HotplugDetector & detector)92 static void PollEvents(const OHOS::MMI::HotplugDetector &detector)
93 {
94     constexpr int timeout = 10; // milliseconds
95     struct pollfd buf = { detector.GetFd(), POLLIN, 0 };
96     while (poll(&buf, 1, timeout) > 0) {
97         detector.OnEvent();
98     }
99 }
100 
101 HWTEST_F(HotplugTest, TestRealInputEvents, TestSize.Level1)
102 {
103     bool addCalled = false;
104     std::string addPath;
105     bool removeCalled = false;
106     std::string removePath;
107 
__anon9d7926b70102(std::string path) 108     auto add = [&addCalled, &addPath](std::string path) {
109         addCalled = true;
110         addPath = std::move(path);
111     };
__anon9d7926b70202(std::string path) 112     auto remove = [&removeCalled, &removePath](std::string path) {
113         removeCalled = true;
114         removePath = std::move(path);
115     };
116     OHOS::MMI::HotplugDetector detector;
117     FakeInputDevice fake;
118 
119     EXPECT_TRUE(Exists(DEV_INPUT_PATH));
120     EXPECT_TRUE(detector.Init(add, remove));
121     ASSERT_TRUE(addCalled);
122     EXPECT_THAT(addPath, StartsWith(DEV_INPUT_PATH));
123     EXPECT_FALSE(removeCalled);
124     auto fd = detector.GetFd();
125     ASSERT_GE(fd, 0);
126     addCalled = false;
127     removeCalled = false;
128     addPath.clear();
129 
130     PollEvents(detector);
131     EXPECT_FALSE(addCalled);
132     EXPECT_FALSE(removeCalled);
133 
134     ASSERT_NO_FATAL_FAILURE(fake.Create());
135     PollEvents(detector);
136     if (addPath.empty()) {
137         return;
138     }
139     EXPECT_TRUE(addCalled);
140     EXPECT_FALSE(removeCalled);
141     EXPECT_THAT(addPath, StartsWith(DEV_INPUT_PATH));
142     EXPECT_TRUE(Exists(addPath));
143     addCalled = false;
144     removeCalled = false;
145 
146     ASSERT_NO_FATAL_FAILURE(fake.Destroy());
147     PollEvents(detector);
148     EXPECT_FALSE(addCalled);
149     EXPECT_TRUE(removeCalled);
150     EXPECT_EQ(removePath, addPath);
151     addCalled = false;
152     removeCalled = false;
153 
154     PollEvents(detector);
155     EXPECT_FALSE(addCalled);
156     EXPECT_FALSE(removeCalled);
157 }
158 
159 HWTEST_F(HotplugTest, TestSpecialCases, TestSize.Level1)
160 {
161     OHOS::MMI::HotplugDetector detector;
162 
__anon9d7926b70302(std::string path) 163     auto dummy = [](std::string path) {};
164 
165     EXPECT_NO_FATAL_FAILURE(detector.OnEvent());
166 
167     EXPECT_TRUE(detector.Init(dummy, dummy));
168     auto fd = detector.GetFd();
169     ASSERT_GE(fd, 0);
170 
171     ASSERT_GE(fcntl(fd, F_SETFL, O_NONBLOCK), 0);
172 
173     EXPECT_NO_FATAL_FAILURE(detector.OnEvent());
174 
175     detector.Stop();
176     EXPECT_EQ(detector.GetFd(), -1);
177 }
178 
179 HWTEST_F(HotplugTest, TestSsystemFail, TestSize.Level1)
180 {
181     OHOS::MMI::HotplugDetector detector;
__anon9d7926b70402(std::string path) 182     auto dummy = [](std::string path) {};
183 
184     std::vector<DIR *> dirs;
185     // Exhaust system resources
186     while (true) {
187         auto *dir = opendir(DEV_INPUT_PATH);
188         if (dir == nullptr) {
189             break;
190         }
191         dirs.push_back(dir);
192     }
193 
194     // inotify should fail
195     EXPECT_FALSE(detector.Init(dummy, dummy));
196 
197     // Free one fd
198     closedir(dirs.back());
199     dirs.pop_back();
200 
201     // Scan should fail
202     EXPECT_FALSE(detector.Init(dummy, dummy));
203 
204     for (auto it = dirs.rbegin(); it != dirs.rend(); ++it) {
205         closedir(*it);
206     }
207 }
208 
209 HWTEST_F(HotplugTest, TestInitFail, TestSize.Level1)
210 {
211     OHOS::MMI::HotplugDetector detector;
212 
__anon9d7926b70502(std::string) 213     auto empty = [](std::string) {};
214 
215     EXPECT_FALSE(detector.Init(nullptr, nullptr));
216     EXPECT_FALSE(detector.Init(empty, nullptr));
217     EXPECT_FALSE(detector.Init(nullptr, empty));
218 }
219