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