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#include <cstdlib>
16#include "init_cmds.h"
17#include "init_group_manager.h"
18#include "init_hashmap.h"
19#include "init_param.h"
20#include "init_service_manager.h"
21#include "init_utils.h"
22#include "init_unittest.h"
23#include "le_timer.h"
24#include "param_stub.h"
25#include "securec.h"
26#include "control_fd.h"
27
28using namespace testing::ext;
29using namespace std;
30
31typedef struct {
32    HashNode node;
33    char name[0];
34} TestHashNode;
35
36static int TestHashNodeCompare(const HashNode *node1, const HashNode *node2)
37{
38    TestHashNode *testNode1 = HASHMAP_ENTRY(node1, TestHashNode, node);
39    TestHashNode *testNode2 = HASHMAP_ENTRY(node2, TestHashNode, node);
40    return strcmp(testNode1->name, testNode2->name);
41}
42
43static int TestHashKeyCompare(const HashNode *node1, const void *key)
44{
45    TestHashNode *testNode1 = HASHMAP_ENTRY(node1, TestHashNode, node);
46    return strcmp(testNode1->name, reinterpret_cast<char *>(const_cast<void *>(key)));
47}
48
49static int TestHashNodeFunction(const HashNode *node)
50{
51    TestHashNode *testNode = HASHMAP_ENTRY(node, TestHashNode, node);
52    int code = 0;
53    size_t nameLen = strlen(testNode->name);
54    for (size_t i = 0; i < nameLen; i++) {
55        code += testNode->name[i] - 'A';
56    }
57    return code;
58}
59
60static int TestHashKeyFunction(const void *key)
61{
62    int code = 0;
63    const char *buff = static_cast<const char *>(key);
64    size_t buffLen = strlen(buff);
65    for (size_t i = 0; i < buffLen; i++) {
66        code += buff[i] - 'A';
67    }
68    return code;
69}
70
71static void TestHashNodeFree(const HashNode *node, void *context)
72{
73    TestHashNode *testNode = HASHMAP_ENTRY(node, TestHashNode, node);
74    printf("TestHashNodeFree %s\n", testNode->name);
75    free(testNode);
76}
77
78static TestHashNode *TestCreateHashNode(const char *value)
79{
80    TestHashNode *node = reinterpret_cast<TestHashNode *>(malloc(sizeof(TestHashNode) + strlen(value) + 1));
81    if (node == nullptr) {
82        return nullptr;
83    }
84    int ret = strcpy_s(node->name, strlen(value) + 1, value);
85    if (ret != 0) {
86        free(node);
87        return nullptr;
88    }
89    HASHMAPInitNode(&node->node);
90    return node;
91}
92
93static void DoCmdByName(const char *name, const char *cmdContent)
94{
95    int cmdIndex = 0;
96    (void)GetMatchCmd(name, &cmdIndex);
97    DoCmdByIndex(cmdIndex, cmdContent, nullptr);
98}
99
100namespace init_ut {
101class InitGroupManagerUnitTest : public testing::Test {
102public:
103    static void SetUpTestCase(void) {};
104    static void TearDownTestCase(void) {};
105    void SetUp(void) {};
106    void TearDown(void) {};
107};
108
109HashInfo g_info = {
110    TestHashNodeCompare,
111    TestHashKeyCompare,
112    TestHashNodeFunction,
113    TestHashKeyFunction,
114    TestHashNodeFree,
115    2
116};
117
118HWTEST_F(InitGroupManagerUnitTest, TestHashMap001, TestSize.Level1)
119{
120    HashMapHandle handle;
121    OH_HashMapCreate(&handle, &g_info);
122    const char *str1 = "Test hash map node 1";
123    const char *str2 = "Test hash map node 2";
124    const char *str3 = "Test hash map node 3";
125    TestHashNode *node1 = TestCreateHashNode(str1);
126    TestHashNode *node2 = TestCreateHashNode(str2);
127    OH_HashMapAdd(handle, &node1->node);
128    OH_HashMapAdd(handle, &node2->node);
129    HashNode *node = OH_HashMapGet(handle, (const void *)str1);
130    EXPECT_NE(node != nullptr, 0);
131    if (node) {
132        TestHashNode *tmp = HASHMAP_ENTRY(node, TestHashNode, node);
133        EXPECT_EQ(strcmp(tmp->name, str1), 0);
134    }
135    node = OH_HashMapGet(handle, (const void *)str2);
136    EXPECT_NE(node != nullptr, 0);
137    if (node) {
138        TestHashNode *tmp = HASHMAP_ENTRY(node, TestHashNode, node);
139        EXPECT_EQ(strcmp(tmp->name, str2), 0);
140    }
141    TestHashNode *node3 = TestCreateHashNode(str3);
142    OH_HashMapAdd(handle, &node3->node);
143    node3 = TestCreateHashNode("Test hash map node 4");
144    OH_HashMapAdd(handle, &node3->node);
145    node3 = TestCreateHashNode("Test hash map node 5");
146    OH_HashMapAdd(handle, &node3->node);
147    node = OH_HashMapGet(handle, (const void *)str3);
148    EXPECT_NE(node != nullptr, 0);
149    if (node) {
150        TestHashNode *tmp = HASHMAP_ENTRY(node, TestHashNode, node);
151        EXPECT_EQ(strcmp(tmp->name, str3), 0);
152    }
153    OH_HashMapIsEmpty(handle);
154    OH_HashMapTraverse(handle, [](const HashNode *node, const void *context) {return;}, nullptr);
155    OH_HashMapDestory(handle, nullptr);
156}
157
158HWTEST_F(InitGroupManagerUnitTest, TestHashMap002, TestSize.Level1)
159{
160    HashMapHandle handle;
161    OH_HashMapCreate(&handle, &g_info);
162    TestHashNode *node4 = TestCreateHashNode("pre-init");
163    OH_HashMapAdd(handle, &node4->node);
164    OH_HashMapRemove(handle, "pre-init");
165    TestHashNodeFree(&node4->node, nullptr);
166
167    const char *act = "load_persist_props_action";
168    TestHashNode *node5 = TestCreateHashNode(act);
169    OH_HashMapAdd(handle, &node5->node);
170    HashNode *node = OH_HashMapGet(handle, (const void *)act);
171    EXPECT_NE(node != nullptr, 0);
172    if (node) {
173        TestHashNode *tmp = HASHMAP_ENTRY(node, TestHashNode, node);
174        EXPECT_EQ(strcmp(tmp->name, act), 0);
175    }
176    OH_HashMapIsEmpty(handle);
177    OH_HashMapTraverse(handle, [](const HashNode *node, const void *context) {return;}, nullptr);
178    OH_HashMapDestory(handle, nullptr);
179}
180
181HWTEST_F(InitGroupManagerUnitTest, TestInitGroupMgrInit, TestSize.Level1)
182{
183    InitServiceSpace();
184    InitWorkspace *workspace = GetInitWorkspace();
185    EXPECT_EQ(workspace->groupMode, GROUP_BOOT);
186    workspace->groupMode = GROUP_BOOT;
187    if (strcpy_s(workspace->groupModeStr, GROUP_NAME_MAX_LENGTH, "device.boot.group") != EOK) {
188        EXPECT_EQ(1, 0);
189    }
190    // test read cfgfile
191    int ret = InitParseGroupCfg();
192    EXPECT_EQ(ret, 0);
193}
194
195HWTEST_F(InitGroupManagerUnitTest, TestAddService, TestSize.Level1)
196{
197    const char *serviceStr = "{"
198	    "\"services\": [{"
199            "\"name\" : \"test-service\","
200            "\"path\" : [\"/dev/test_service\"],"
201            "\"start-mode\" : \"condition\","
202            "\"end-mode\" : \"after-exec\","
203            "\"console\":1,"
204            "\"writepid\":[\"/dev/test_service\"],"
205            "\"jobs\" : {"
206                    "\"on-boot\" : \"boot:bootjob1\","
207                    "\"on-start\" : \"service:startjob\","
208                    "\"on-stop\" : \"service:stopjob\","
209                    "\"on-restart\" : \"service:restartjob\""
210                "}"
211        "},{"
212            "\"name\" : \"test-service2\","
213            "\"path\" : [\"/dev/test_service\"],"
214            "\"console\":1,"
215            "\"start-mode\" : \"boot\","
216            "\"writepid\":[\"/dev/test_service\"],"
217            "\"jobs\" : {"
218                    "\"on-boot\" : \"boot:bootjob1\","
219                    "\"on-start\" : \"service:startjob\","
220                    "\"on-stop\" : \"service:stopjob\","
221                    "\"on-restart\" : \"service:restartjob\""
222                "}"
223        "}]"
224    "}";
225
226    cJSON *fileRoot = cJSON_Parse(serviceStr);
227    ASSERT_NE(nullptr, fileRoot);
228    ConfigContext context = { INIT_CONTEXT_MAIN };
229    ParseAllServices(fileRoot, &context);
230    cJSON_Delete(fileRoot);
231
232    Service *service = GetServiceByName("test-service");
233    ServiceStartTimer(service, 1);
234    ServiceStopTimer(service);
235    ASSERT_NE(service != nullptr, 0);
236    EXPECT_EQ(service->startMode, START_MODE_CONDITION);
237    ReleaseService(service);
238    service = GetServiceByName("test-service2");
239    ASSERT_NE(service != nullptr, 0);
240    EXPECT_EQ(service->startMode, START_MODE_BOOT);
241    ReleaseService(service);
242}
243
244/**
245 * @brief
246 *
247
248    "socket" : [{
249        "name" : "ueventd",
250        "family" : "AF_INET", // AF_INET,AF_INET6,AF_UNIX(AF_LOCAL),AF_NETLINK
251        "type" : : "SOCK_STREAM", // SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_PACKET,SOCK_SEQPACKET
252        "protocol" : "IPPROTO_TCP", // IPPROTO_TCP,IPPTOTO_UDP,IPPROTO_SCTP,PPROTO_TIPC
253        "permissions" : "0660",
254        "uid" : "system",
255        "gid" : "system",
256        "option" : {
257            "passcred" : "true",
258            "rcvbufforce" : "",
259            "cloexec" : "",
260            "nonblock : ""
261        }
262    }],
263 */
264HWTEST_F(InitGroupManagerUnitTest, TestAddServiceDeny, TestSize.Level1)
265{
266    const char *serviceStr = "{"
267	    "\"services\": [{"
268            "\"name\" : \"test-service5\","
269            "\"path\" : [\"/dev/test_service\"],"
270            "\"start-mode\" : \"by-condition\","
271            "\"end-mode\" : \"ready\","
272            "\"console\":1,"
273            "\"writepid\":[\"/dev/test_service\"],"
274            "\"jobs\" : {"
275                    "\"on-boot\" : \"boot:bootjob1\","
276                    "\"on-start\" : \"service:startjob\","
277                    "\"on-stop\" : \"service:stopjob\","
278                    "\"on-restart\" : \"service:restartjob\""
279                "}"
280        "}]"
281    "}";
282    InitWorkspace *workspace = GetInitWorkspace();
283    workspace->groupMode = GROUP_CHARGE;
284
285    cJSON *fileRoot = cJSON_Parse(serviceStr);
286    ASSERT_NE(nullptr, fileRoot);
287    ConfigContext context = { INIT_CONTEXT_MAIN };
288    ParseAllServices(fileRoot, &context);
289    cJSON_Delete(fileRoot);
290
291    Service *service = GetServiceByName("test-service5");
292    ASSERT_EQ(service, nullptr);
293    workspace->groupMode = GROUP_BOOT;
294}
295
296HWTEST_F(InitGroupManagerUnitTest, TestAddService2, TestSize.Level1)
297{
298    const char *serviceStr = "{"
299	    "\"services\": [{"
300            "\"name\" : \"test-service6\","
301            "\"path\" : [\"/dev/test_service\"],"
302            "\"console\":1,"
303            "\"writepid\":[\"/dev/test_service\"],"
304            "\"jobs\" : {"
305                    "\"on-boot\" : \"boot:bootjob1\","
306                    "\"on-start\" : \"service:startjob\","
307                    "\"on-stop\" : \"service:stopjob\","
308                    "\"on-restart\" : \"service:restartjob\""
309                "}"
310        "}]"
311    "}";
312
313    InitWorkspace *workspace = GetInitWorkspace();
314    workspace->groupMode = GROUP_CHARGE;
315
316    InitGroupNode *node = AddGroupNode(NODE_TYPE_SERVICES, "test-service6");
317    ASSERT_NE(nullptr, node);
318
319    cJSON *fileRoot = cJSON_Parse(serviceStr);
320    ASSERT_NE(nullptr, fileRoot);
321    ConfigContext context = { INIT_CONTEXT_MAIN };
322    ParseAllServices(fileRoot, &context);
323    cJSON_Delete(fileRoot);
324    char cmdStr[] = "all#bootevent";
325    char cmdStr1[] = "parameter_service";
326    ProcessControlFd(ACTION_DUMP, "all", nullptr);
327    ProcessControlFd(ACTION_DUMP, cmdStr, nullptr);
328    ProcessControlFd(ACTION_DUMP, cmdStr1, nullptr);
329    ProcessControlFd(ACTION_SANDBOX, cmdStr, nullptr);
330    ProcessControlFd(ACTION_MODULEMGR, cmdStr, nullptr);
331    ProcessControlFd(ACTION_MAX, cmdStr, nullptr);
332    Service *service = GetServiceByName("test-service6");
333    ASSERT_NE(service, nullptr);
334    workspace->groupMode = GROUP_BOOT;
335}
336
337HWTEST_F(InitGroupManagerUnitTest, TestParseServiceCpucore, TestSize.Level1)
338{
339    const char *jsonStr = "{\"services\":{\"name\":\"test_service22\",\"path\":[\"/data/init_ut/test_service\"],"
340        "\"importance\":-20,\"uid\":\"root\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
341        "\"gid\":[\"root\"], \"cpucore\":[5, 2, 4, 1, 2, 0, 1], \"critical\":[1]}}";
342    cJSON* jobItem = cJSON_Parse(jsonStr);
343    ASSERT_NE(nullptr, jobItem);
344    cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
345    ASSERT_NE(nullptr, serviceItem);
346    Service *service = AddService("test_service22");
347    const int invalidImportantValue = 20;
348    SetImportantValue(service, "", invalidImportantValue, 1);
349    if (service != nullptr) {
350        int ret = ParseOneService(serviceItem, service);
351        GetAccessToken();
352        DoCmdByName("timer_start ", "test_service22|5000");
353        DoCmdByName("timer_start ", "test_service22|aa");
354        DoCmdByName("timer_start ", "");
355        EXPECT_EQ(ret, 0);
356        StartServiceByName("test_service22|path");
357        ReleaseService(service);
358    }
359    cJSON_Delete(jobItem);
360}
361
362HWTEST_F(InitGroupManagerUnitTest, TestUpdaterServiceFds, TestSize.Level1)
363{
364    Service *service = AddService("test_service8");
365    ASSERT_NE(nullptr, service);
366    int fds[1] = { -1 }; // ServiceStop will release fds
367    UpdaterServiceFds(nullptr, nullptr, 0);
368    UpdaterServiceFds(service, fds, 1);
369    UpdaterServiceFds(service, fds, 0);
370    UpdaterServiceFds(service, fds, 1);
371    UpdaterServiceFds(service, nullptr, 1);
372    UpdaterServiceFds(service, fds, 1);
373    int ret = UpdaterServiceFds(service, nullptr, 2); // 2 is fd num
374    ASSERT_NE(ret, 0);
375    service->attribute = SERVICE_ATTR_TIMERSTART;
376    ServiceStartTimer(service, 0);
377}
378HWTEST_F(InitGroupManagerUnitTest, TestProcessWatchEvent, TestSize.Level1)
379{
380    Service *service = AddService("test_service9");
381    ASSERT_NE(nullptr, service);
382    ServiceSocket servercfg = {.next = nullptr, .sockFd = 0};
383    service->socketCfg = &servercfg;
384    ServiceWatcher watcher;
385    int ret = AddSocketWatcher(&watcher, service, 0);
386    ASSERT_EQ(ret, 0);
387    uint32_t event;
388    ((WatcherTask *)watcher)->processEvent((WatcherHandle)watcher, 0, &event, service);
389    service->socketCfg = nullptr;
390}
391
392HWTEST_F(InitGroupManagerUnitTest, TestCheckNodeValid, TestSize.Level1)
393{
394    int ret = CheckNodeValid(NODE_TYPE_MAX, "charger");
395    EXPECT_EQ(ret, -1);
396    ret = CheckNodeValid(NODE_TYPE_PLUGINS, "charger");
397    EXPECT_EQ(ret, -1);
398}
399
400HWTEST_F(InitGroupManagerUnitTest, TestGetGroupHashMap, TestSize.Level1)
401{
402    HashMapHandle handle = GetGroupHashMap(NODE_TYPE_GROUPS);
403    EXPECT_TRUE(handle == nullptr);
404}
405}  // namespace init_ut
406