1 /*
2  * Copyright (c) 2021 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 <cinttypes>
17 #include <gtest/gtest.h>
18 #include "hookmgr.h"
19 #include "bootstage.h"
20 using namespace testing::ext;
21 using namespace std;
22 
23 namespace init_ut {
24 class HookMgrUnitTest : public testing::Test {
25 public:
SetUpTestCase(void)26     static void SetUpTestCase(void) {};
TearDownTestCase(void)27     static void TearDownTestCase(void) {};
SetUp()28     void SetUp() {};
TearDown()29     void TearDown() {};
30 };
31 
32 struct HookExecCtx {
33     int result;
34     int retErr;
35 };
36 
OhosHookTestCommon(void * executionContext,int result)37 static int OhosHookTestCommon(void *executionContext, int result)
38 {
39     struct HookExecCtx *ctx;
40 
41     if (executionContext == nullptr) {
42         return 0;
43     }
44 
45     ctx = (struct HookExecCtx *)executionContext;
46     ctx->result = result;
47     if (ctx->retErr) {
48         return -1;
49     }
50     return 0;
51 }
52 
OhosTestHookRetOK(const HOOK_INFO * hookInfo,void * executionContext)53 static int OhosTestHookRetOK(const HOOK_INFO *hookInfo, void *executionContext)
54 {
55     return OhosHookTestCommon(executionContext, 1);
56 }
57 
OhosTestHookRetOKEx(const HOOK_INFO * hookInfo,void * executionContext)58 static int OhosTestHookRetOKEx(const HOOK_INFO *hookInfo, void *executionContext)
59 {
60     return OhosHookTestCommon(executionContext, 2);
61 }
62 
OhosTestHookRetOKEx2(const HOOK_INFO * hookInfo,void * executionContext)63 static int OhosTestHookRetOKEx2(const HOOK_INFO *hookInfo, void *executionContext)
64 {
65     return OhosHookTestCommon(executionContext, 3);
66 }
67 
OhosHookPrint(const HOOK_INFO * hookInfo,void * traversalCookie)68 static void OhosHookPrint(const HOOK_INFO *hookInfo, void *traversalCookie)
69 {
70     printf("\tstage[%02d] prio[%02d].\n", hookInfo->stage, hookInfo->prio);
71 }
72 
dumpAllHooks(HOOK_MGR * hookMgr)73 static void dumpAllHooks(HOOK_MGR *hookMgr)
74 {
75     printf("----------All Hooks---------------\n");
76     HookMgrTraversal(hookMgr, nullptr, OhosHookPrint);
77     printf("----------------------------------\n\n");
78 }
79 
80 #define STAGE_TEST_ONE 0
81 
82 HWTEST_F(HookMgrUnitTest, HookMgrAdd_one_stage_unitest, TestSize.Level1)
83 {
84     int ret;
85     int cnt;
86 
87     cnt = HookMgrGetStagesCnt(nullptr);
88     EXPECT_EQ(cnt, 0);
89 
90     // Add the first hook
91     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
92     EXPECT_EQ(ret, 0);
93     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
94     EXPECT_EQ(cnt, 1);
95     cnt = HookMgrGetStagesCnt(nullptr);
96     EXPECT_EQ(cnt, 1);
97     dumpAllHooks(nullptr);
98 
99     // Add the same hook with the same priority again
100     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
101     EXPECT_EQ(ret, 0);
102     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
103     EXPECT_EQ(cnt, 1);
104     dumpAllHooks(nullptr);
105 
106     // Add the same hook with different priority
107     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
108     EXPECT_EQ(ret, 0);
109     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
110     EXPECT_EQ(cnt, 2);
111     dumpAllHooks(nullptr);
112 
113     // Add the another hook
114     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 10, OhosTestHookRetOKEx);
115     EXPECT_EQ(ret, 0);
116     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
117     EXPECT_EQ(cnt, 3);
118     dumpAllHooks(nullptr);
119 
120     // Add the same hook with the same priority again
121     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
122     EXPECT_EQ(ret, 0);
123     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
124     EXPECT_EQ(cnt, 3);
125     dumpAllHooks(nullptr);
126 
127     // Add the same hook with the same priority again
128     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
129     EXPECT_EQ(ret, 0);
130     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
131     EXPECT_EQ(cnt, 3);
132     dumpAllHooks(nullptr);
133 
134     // Add the another hook
135     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 10, OhosTestHookRetOKEx);
136     EXPECT_EQ(ret, 0);
137     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
138     EXPECT_EQ(cnt, 3);
139     dumpAllHooks(nullptr);
140 
141     // Insert to the end of already exist prio
142     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
143     EXPECT_EQ(ret, 0);
144     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
145     EXPECT_EQ(cnt, 4);
146     dumpAllHooks(nullptr);
147 
148     // Insert to the end of already exist prio
149     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx2);
150     EXPECT_EQ(ret, 0);
151     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
152     EXPECT_EQ(cnt, 5);
153     dumpAllHooks(nullptr);
154 
155     // Insert a new prio hook
156     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 5, OhosTestHookRetOK);
157     EXPECT_EQ(ret, 0);
158     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
159     EXPECT_EQ(cnt, 6);
160     dumpAllHooks(nullptr);
161 
162     // Insert a new prio hook to the beginning
163     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, -5, OhosTestHookRetOK);
164     EXPECT_EQ(ret, 0);
165     cnt = HookMgrGetHooksCnt(nullptr, STAGE_TEST_ONE);
166     EXPECT_EQ(cnt, 7);
167     dumpAllHooks(nullptr);
168 
169     // All hooks are in the same stage
170     cnt = HookMgrGetStagesCnt(nullptr);
171     EXPECT_EQ(cnt, 1);
172 
173     // Delete all hooks in stage 0
174     HookMgrDel(nullptr, STAGE_TEST_ONE, nullptr);
175     cnt = HookMgrGetHooksCnt(nullptr, 0);
176     EXPECT_EQ(cnt, 0);
177     cnt = HookMgrGetStagesCnt(nullptr);
178     EXPECT_EQ(cnt, 0);
179 
180     dumpAllHooks(nullptr);
181     HookMgrDestroy(nullptr);
182 }
183 
184 HWTEST_F(HookMgrUnitTest, HookMgrDel_unitest, TestSize.Level1)
185 {
186     int ret;
187     int cnt;
188 
189     HOOK_MGR *hookMgr = HookMgrCreate("test");
190     ASSERT_NE(hookMgr, nullptr);
191 
192     // Add one, delete one
193     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
194     EXPECT_EQ(ret, 0);
195     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
196     EXPECT_EQ(cnt, 1);
197 
198     HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
199     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
200     EXPECT_EQ(cnt, 0);
201 
202     // Add three same hook with different prio, delete together
203     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
204     EXPECT_EQ(ret, 0);
205     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
206     EXPECT_EQ(cnt, 1);
207     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 5, OhosTestHookRetOK);
208     EXPECT_EQ(ret, 0);
209     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
210     EXPECT_EQ(cnt, 2);
211     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
212     EXPECT_EQ(ret, 0);
213     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
214     EXPECT_EQ(cnt, 3);
215     dumpAllHooks(hookMgr);
216 
217     HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
218     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
219     EXPECT_EQ(cnt, 0);
220 
221     // Add three different hook with same prio, delete one by one
222     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
223     EXPECT_EQ(ret, 0);
224     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
225     EXPECT_EQ(cnt, 1);
226     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
227     EXPECT_EQ(ret, 0);
228     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
229     EXPECT_EQ(cnt, 2);
230     ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx2);
231     EXPECT_EQ(ret, 0);
232     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
233     EXPECT_EQ(cnt, 3);
234     dumpAllHooks(hookMgr);
235 
236     HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
237     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
238     EXPECT_EQ(cnt, 2);
239     dumpAllHooks(hookMgr);
240     HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOKEx2);
241     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
242     EXPECT_EQ(cnt, 1);
243     dumpAllHooks(hookMgr);
244     HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOKEx);
245     cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
246     EXPECT_EQ(cnt, 0);
247 
248     HookMgrDestroy(hookMgr);
249 }
250 
251 HWTEST_F(HookMgrUnitTest, HookMgrExecute_unitest, TestSize.Level1)
252 {
253     int ret;
254     struct HookExecCtx ctx;
255     HOOK_EXEC_OPTIONS options;
256 
257     ctx.result = 0;
258     ctx.retErr = 0;
259 
260     options.flags = 0;
261     options.preHook = nullptr;
262     options.postHook = nullptr;
263 
264     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
265     EXPECT_EQ(ret, 0);
266     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, nullptr);
267     EXPECT_EQ(ret, 0);
268     EXPECT_EQ(ctx.result, 1);
269 
270     // Check ignore error
271     ctx.retErr = 1;
272     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, nullptr);
273     EXPECT_EQ(ret, 0);
274     EXPECT_EQ(ctx.result, 1);
275 
276     // Do not ignore return errors
277     ctx.retErr = 1;
278     options.flags = HOOK_EXEC_EXIT_WHEN_ERROR;
279     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, &options);
280     ASSERT_NE(ret, 0);
281     EXPECT_EQ(ctx.result, 1);
282     options.flags = 0;
283 
284     // Add another hook with same priority
285     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
286     EXPECT_EQ(ret, 0);
287     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, nullptr);
288     EXPECT_EQ(ret, 0);
289     EXPECT_EQ(ctx.result, 2);
290 
291     // Add another hook with higher priority
292     ret = HookMgrAdd(nullptr, STAGE_TEST_ONE, -1, OhosTestHookRetOKEx);
293     EXPECT_EQ(ret, 0);
294     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, nullptr);
295     EXPECT_EQ(ret, 0);
296     EXPECT_EQ(ctx.result, 2);
297 
298     HookMgrDel(nullptr, STAGE_TEST_ONE, OhosTestHookRetOKEx);
299     ret = HookMgrExecute(nullptr, STAGE_TEST_ONE, (void *)&ctx, nullptr);
300     EXPECT_EQ(ret, 0);
301     EXPECT_EQ(ctx.result, 1);
302 }
303 
304 HWTEST_F(HookMgrUnitTest, HookMgrExecuteInit_unitest, TestSize.Level1)
305 {
306     HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, nullptr, nullptr);
307     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, nullptr, nullptr);
308 }
309 } // namespace init_ut
310