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"
20using namespace testing::ext;
21using namespace std;
22
23namespace init_ut {
24class HookMgrUnitTest : public testing::Test {
25public:
26    static void SetUpTestCase(void) {};
27    static void TearDownTestCase(void) {};
28    void SetUp() {};
29    void TearDown() {};
30};
31
32struct HookExecCtx {
33    int result;
34    int retErr;
35};
36
37static 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
53static int OhosTestHookRetOK(const HOOK_INFO *hookInfo, void *executionContext)
54{
55    return OhosHookTestCommon(executionContext, 1);
56}
57
58static int OhosTestHookRetOKEx(const HOOK_INFO *hookInfo, void *executionContext)
59{
60    return OhosHookTestCommon(executionContext, 2);
61}
62
63static int OhosTestHookRetOKEx2(const HOOK_INFO *hookInfo, void *executionContext)
64{
65    return OhosHookTestCommon(executionContext, 3);
66}
67
68static void OhosHookPrint(const HOOK_INFO *hookInfo, void *traversalCookie)
69{
70    printf("\tstage[%02d] prio[%02d].\n", hookInfo->stage, hookInfo->prio);
71}
72
73static 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
82HWTEST_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
184HWTEST_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
251HWTEST_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
304HWTEST_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