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 
__anon10ccb06e0102(std::string path) 108     auto add = [&addCalled, &addPath](std::string path) {
109         addCalled = true;
110         addPath = std::move(path);
111     };
__anon10ccb06e0202(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     EXPECT_TRUE(addCalled);
137     EXPECT_FALSE(removeCalled);
138     EXPECT_THAT(addPath, StartsWith(DEV_INPUT_PATH));
139     EXPECT_TRUE(Exists(addPath));
140     addCalled = false;
141     removeCalled = false;
142 
143     ASSERT_NO_FATAL_FAILURE(fake.Destroy());
144     PollEvents(detector);
145     EXPECT_FALSE(addCalled);
146     EXPECT_EQ(removePath, addPath);
147     addCalled = false;
148     removeCalled = false;
149 
150     PollEvents(detector);
151     EXPECT_FALSE(addCalled);
152     EXPECT_FALSE(removeCalled);
153 }
154 
155 HWTEST_F(HotplugTest, TestSpecialCases, TestSize.Level1)
156 {
157     OHOS::MMI::HotplugDetector detector;
158 
__anon10ccb06e0302(std::string path) 159     auto dummy = [](std::string path) {};
160 
161     EXPECT_NO_FATAL_FAILURE(detector.OnEvent());
162 
163     EXPECT_TRUE(detector.Init(dummy, dummy));
164     auto fd = detector.GetFd();
165     ASSERT_GE(fd, 0);
166 
167     ASSERT_GE(fcntl(fd, F_SETFL, O_NONBLOCK), 0);
168 
169     EXPECT_NO_FATAL_FAILURE(detector.OnEvent());
170 
171     detector.Stop();
172     EXPECT_EQ(detector.GetFd(), -1);
173 }
174 
175 HWTEST_F(HotplugTest, TestInitFail, TestSize.Level1)
176 {
177     OHOS::MMI::HotplugDetector detector;
178 
__anon10ccb06e0402(std::string) 179     auto empty = [](std::string) {};
180 
181     EXPECT_FALSE(detector.Init(nullptr, nullptr));
182     EXPECT_FALSE(detector.Init(empty, nullptr));
183     EXPECT_FALSE(detector.Init(nullptr, empty));
184 }
185