1 /*
2 * Copyright (c) 2025 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 <gtest/gtest.h>
17
18 #include "native_fence.h"
19
20 #include <chrono>
21 #include <cstring>
22 #include <cerrno>
23 #include <fcntl.h>
24 #include <iostream>
25 #include <linux/sync_file.h>
26 #include <csignal>
27 #include <sys/ioctl.h>
28 #include <sys/signalfd.h>
29 #include <thread>
30 #include <unistd.h>
31
32 namespace OHOS {
33 namespace {
34 constexpr int INVALID_FD = -1;
35 constexpr uint32_t TIMEOUT_MS = 5000;
36 } // namespace
37
38 class NativeFenceTest : public testing::Test {
39 public:
SetUpTestCase()40 static void SetUpTestCase() {}
TearDownTestCase()41 static void TearDownTestCase() {}
SetUp()42 void SetUp() {}
TearDown()43 void TearDown() {}
44 };
45
46 /*
47 * Function: NativeFenceWaitTest
48 * Type: Function
49 * Rank: Important(2)
50 * EnvConditions: N/A
51 * CaseDescription: 1. preSetUp: open a valid fence fd.
52 * 2. operation: call OH_NativeFence_Wait with valid fence fd and timeout.
53 * 3. result: OH_NativeFence_Wait returns false because no event occurred after timeout.
54 */
TEST_F(NativeFenceTest,NativeFenceWaitTest)55 TEST_F(NativeFenceTest, NativeFenceWaitTest)
56 {
57 // Test invalid fence fd
58 bool result = OH_NativeFence_Wait(INVALID_FD, TIMEOUT_MS);
59 EXPECT_FALSE(result);
60
61 // Test valid fence fd
62 int fd = open("/dev/GPIO_TEST", O_RDONLY);
63 ASSERT_GE(fd, 0);
64 bool result2 = false;
65 result2 = OH_NativeFence_Wait(fd, 0);
66 EXPECT_FALSE(result2);
67 auto startTime = std::chrono::steady_clock::now();
68 result2 = OH_NativeFence_Wait(fd, TIMEOUT_MS);
69 auto endTime = std::chrono::steady_clock::now();
70 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
71 std::cout << "OH_NativeFence_Wait cost time: " << duration << "ms" << std::endl;
72 EXPECT_FALSE(result2);
73 OH_NativeFence_Close(fd);
74 }
75
76 /*
77 * Function: NativeFenceWaitWithSignalTest
78 * Type: Function
79 * Rank: Important(2)
80 * EnvConditions: N/A
81 * CaseDescription: 1. preSetUp: create a valid fence fd by signalfd.
82 * 2. operation: waitThread call OH_NativeFence_Wait with valid fence fd and timeout. \n
83 * mainThread call kill to send signal after 3 seconds.
84 * 3. result: OH_NativeFence_Wait should return true because has event occurred after 3 seconds.
85 */
TEST_F(NativeFenceTest,NativeFenceWaitWithSignalTest)86 TEST_F(NativeFenceTest, NativeFenceWaitWithSignalTest)
87 {
88 // Test invalid fence fd
89 bool result = OH_NativeFence_Wait(INVALID_FD, TIMEOUT_MS);
90 EXPECT_FALSE(result);
91
92 std::atomic<bool> signaled(false);
93 sigset_t mask;
94 sigemptyset(&mask);
95 sigaddset(&mask, SIGINT); // Monitor SIGINT signal (Ctrl C)
96 sigaddset(&mask, SIGTERM); // Monitor SIGTERM signal (kill command)
97 sigprocmask(SIG_BLOCK, &mask, nullptr);
98 int sfd = signalfd(-1, &mask, 0);
99 if (sfd == -1) {
100 perror("signalfd failed");
101 exit(1);
102 }
103
104 std::thread waitThread([&]() {
105 bool result2 = false;
106 auto startTime = std::chrono::steady_clock::now();
107 result2 = OH_NativeFence_Wait(sfd, TIMEOUT_MS);
108 auto endTime = std::chrono::steady_clock::now();
109 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
110 std::cout << "OH_NativeFence_Wait cost time: " << duration << "ms" << std::endl;
111 EXPECT_TRUE(result2);
112 signaled.store(true);
113 });
114
115 std::this_thread::sleep_for(std::chrono::seconds(3)); // 3 means main thread sleep 3 seconds.
116 pid_t target_pid = getpid();
117 int ret = kill(target_pid, SIGINT);
118 if (ret < 0) {
119 FAIL() << "kill failed: " << strerror(errno);
120 }
121
122 // Waiting for waitThread to complete
123 waitThread.join();
124
125 // checks the signaled variable to ensure that OH_NativeFence_Wait has returned
126 EXPECT_TRUE(signaled.load());
127 OH_NativeFence_Close(sfd);
128 }
129
130 /*
131 * Function: NativeFenceIsValidTest
132 * Type: Function
133 * Rank: Important(2)
134 * EnvConditions: N/A
135 * CaseDescription: 1. preSetUp: create a valid and invalid fence fd.
136 * 2. operation: call the OH_NativeFence_IsValid with a fence fd.
137 * 3. result: legitimate ID returns true, illegal ID returns false.
138 */
TEST_F(NativeFenceTest,NativeFenceIsValidTest)139 TEST_F(NativeFenceTest, NativeFenceIsValidTest)
140 {
141 // Test invalid fence fd
142 bool result = OH_NativeFence_IsValid(INVALID_FD);
143 EXPECT_FALSE(result);
144
145 OH_NativeFence_Close(INVALID_FD);
146
147 // Test valid fence fd
148 int fd = open("/dev/GPIO_TEST", O_RDONLY);
149 ASSERT_GE(fd, 0);
150 result = OH_NativeFence_IsValid(fd);
151 EXPECT_TRUE(result);
152 OH_NativeFence_Close(fd);
153 }
154
155 /*
156 * Function: NativeFenceLoopCallInterfaceTest
157 * Type: Function
158 * Rank: Important(2)
159 * EnvConditions: N/A
160 * CaseDescription: 1. preSetUp: create a valid fence fd.
161 * 2. operation: call the OH_NativeFence_IsValid and OH_NativeFence_Close with 1000 times.
162 * 3. result: Interface execution without crash.
163 */
TEST_F(NativeFenceTest,NativeFenceLoopCallInterfaceTest)164 TEST_F(NativeFenceTest, NativeFenceLoopCallInterfaceTest)
165 {
166 auto start = std::chrono::high_resolution_clock::now();
167 for (auto i = 0; i != 1000; i++) { // 1000 represents the number of cycles
168 bool result = OH_NativeFence_IsValid(INVALID_FD);
169 EXPECT_FALSE(result);
170 }
171 auto end = std::chrono::high_resolution_clock::now();
172 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
173 std::cout << "OH_NativeFence_IsValid cost time: " << duration.count() << "ms" << std::endl;
174 ASSERT_GE(duration.count(), 0);
175
176 start = std::chrono::high_resolution_clock::now();
177 for (auto i = 0; i != 1000; i++) { // 1000 represents the number of cycles
178 int fd = open("/dev/GPIO_TEST", O_RDONLY);
179 ASSERT_GE(fd, 0);
180 OH_NativeFence_Close(fd);
181 }
182 end = std::chrono::high_resolution_clock::now();
183 duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
184 std::cout << "OH_NativeFence_Close cost time: " << duration.count() << "ms" << std::endl;
185 ASSERT_GE(duration.count(), 0);
186 }
187
188 /*
189 * Function: NativeFenceWaitForeverWithSignalTest
190 * Type: Function
191 * Rank: Important(2)
192 * EnvConditions: N/A
193 * CaseDescription: 1. preSetUp: create a valid fence fd by signalfd.
194 * 2. operation: waitThread call OH_NativeFence_WaitForever with valid fence fd and timeout. \n
195 * mainThread call kill to send signal after 3 seconds.
196 * 3. result: OH_NativeFence_WaitForever should return true because has event occurred after 3 seconds.
197 */
TEST_F(NativeFenceTest,NativeFenceWaitForeverWithSignalTest)198 TEST_F(NativeFenceTest, NativeFenceWaitForeverWithSignalTest)
199 {
200 // Test invalid fence fd
201 bool result = OH_NativeFence_WaitForever(INVALID_FD);
202 EXPECT_FALSE(result);
203
204 std::atomic<bool> signaled(false);
205 sigset_t mask;
206 sigemptyset(&mask);
207 sigaddset(&mask, SIGINT); // Monitor SIGINT signal (Ctrl C)
208 sigaddset(&mask, SIGTERM); // Monitor SIGTERM signal (kill command)
209 sigprocmask(SIG_BLOCK, &mask, nullptr);
210
211 int sfd = signalfd(-1, &mask, 0);
212 if (sfd == -1) {
213 perror("signalfd failed");
214 exit(1);
215 }
216 std::thread waitThread([&]() {
217 bool result2 = false;
218 result2 = OH_NativeFence_WaitForever(sfd);
219 EXPECT_TRUE(result2);
220 signaled.store(true);
221 });
222 std::this_thread::sleep_for(std::chrono::seconds(3)); // 3 means main thread sleep 3 seconds.
223 pid_t target_pid = getpid();
224 int ret = kill(target_pid, SIGINT);
225 if (ret < 0) {
226 FAIL() << "kill failed: " << strerror(errno);
227 }
228
229 // Waiting for waitThread to complete
230 waitThread.join();
231
232 // checks the signaled variable to ensure that OH_NativeFence_WaitForever has returned
233 EXPECT_TRUE(signaled.load());
234 OH_NativeFence_Close(sfd);
235 }
236 } // namespace OHOS