• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cinttypes>
16 #include <hwext/gtest-ext.h>
17 #include <hwext/gtest-tag.h>
18 #include <dlfcn.h>
19 
20 #include "process_data_plugin.h"
21 #include "plugin_module_api.h"
22 
23 using namespace testing::ext;
24 
25 namespace {
26 const std::string DEFAULT_TEST_PATH = "/data/local/tmp/resources";
27 #if defined(__arm__)
28 const std::string SO_PATH = "/system/lib/libprocessplugin.z.so";
29 #elif defined(__aarch64__)
30 const std::string SO_PATH = "/system/lib64/libprocessplugin.z.so";
31 #endif
32 constexpr uint32_t BUF_SIZE = 4 * 1024 * 1024;
33 const int PERCENT = 100;
34 constexpr int PROCESS_NUM = 2;
35 constexpr int THREAD_NUM = 3;
36 std::string g_path = "";
37 std::string g_testPath = "";
38 std::shared_ptr<ProcessDataPlugin> processPlugin = nullptr;
39 
40 struct PssData {
41     int32_t pssInfo;
42 };
43 
44 struct DiskioData {
45     int64_t rchar;
46     int64_t wchar;
47     int64_t syscr;
48     int64_t syscw;
49     int64_t rbytes;
50     int64_t wbytes;
51     int64_t cancelledWbytes;
52 };
53 
54 struct CpuData {
55     double cpuUsage;
56     int32_t threadSum;
57     int64_t cpuTimeMs;
58 };
59 
60 struct ProcessStatus {
61     int32_t pid;
62     std::string name;
63     int32_t ppid;
64     int32_t uid;
65 };
66 
67 struct ProcessCpuData {
68     int64_t utime;
69     int64_t stime;
70     int64_t cutime;
71     int64_t cstime;
72 };
73 
74 struct BootData {
75     int64_t user;
76     int64_t nice;
77     int64_t system;
78     int64_t idle;
79     int64_t iowait;
80     int64_t irq;
81     int64_t softirq;
82     int64_t steal;
83 };
84 
85 PssData g_pssData[] = { {1499}, {230} };
86 DiskioData g_diskioData[] = { {479, 577, 1973, 8092, 2574, 50, 91}, {7201784, 3168, 54150, 35, 22499328, 0, 0} };
87 ProcessStatus g_processStatus[] = { {11, "test", 2, 0}, {1872, "ibus-x11", 0, 1} };
88 ProcessCpuData g_processCpuData[] = { {60, 10, 20, 30}, {70, 10, 50, 30} };
89 BootData g_bootData = {24875428, 3952448, 11859815, 1193297105, 8980661, 0, 2607250, 0};
90 
91 class ProcessDataPluginTest : public ::testing::Test {
92 public:
SetUpTestCase()93     static void SetUpTestCase() {}
94 
TearDownTestCase()95     static void TearDownTestCase()
96     {
97         if (access(g_testPath.c_str(), F_OK) == 0) {
98             std::string str = "rm -rf " + g_testPath;
99             system(str.c_str());
100         }
101     }
102 };
103 
Getexepath()104 string Getexepath()
105 {
106     char buf[PATH_MAX] = "";
107     std::string path = "/proc/self/exe";
108     size_t rslt = readlink(path.c_str(), buf, sizeof(buf));
109     if (rslt < 0 || (rslt >= sizeof(buf))) {
110         return "";
111     }
112     buf[rslt] = '\0';
113     for (int i = rslt; i >= 0; i--) {
114         if (buf[i] == '/') {
115             buf[i + 1] = '\0';
116             break;
117         }
118     }
119     return buf;
120 }
121 
GetFullPath(std::string path)122 std::string GetFullPath(std::string path)
123 {
124     if (path.size() > 0 && path[0] != '/') {
125         return Getexepath() + path;
126     }
127     return path;
128 }
129 
PluginCpuinfoStub(ProcessData & processData,ProcessConfig & protoConfig,bool unusualBuff)130 bool PluginCpuinfoStub(ProcessData& processData, ProcessConfig& protoConfig, bool unusualBuff)
131 {
132     CHECK_NOTNULL(processPlugin, false, "PluginCpuinfoStub fail");
133     // serialize
134     std::vector<uint8_t> configData(protoConfig.ByteSizeLong());
135     int ret = protoConfig.SerializeToArray(configData.data(), configData.size());
136 
137     // start
138     ret = processPlugin->Start(configData.data(), configData.size());
139     if (ret < 0) {
140         return false;
141     }
142 
143     // report
144     std::vector<uint8_t> bufferData(BUF_SIZE);
145     if (unusualBuff) { // buffer异常,调整缓冲区长度为1,测试异常情况
146         bufferData.resize(1, 0);
147     }
148 
149     ret = processPlugin->Report(bufferData.data(), bufferData.size());
150     if (ret > 0) {
151         processData.ParseFromArray(bufferData.data(), ret);
152         return true;
153     }
154 
155     return false;
156 }
157 
GetCpuData(std::vector<CpuData> & cpuDataVec,int64_t Hz)158 void GetCpuData(std::vector<CpuData>& cpuDataVec, int64_t Hz)
159 {
160     int64_t bootTime = (g_bootData.user + g_bootData.nice + g_bootData.system + g_bootData.idle + g_bootData.iowait
161                         + g_bootData.irq + g_bootData.softirq + g_bootData.steal) * Hz;
162     for (int i = 0; i < PROCESS_NUM; i++) {
163         int cpuTimeMs = (g_processCpuData[i].utime + g_processCpuData[i].stime + g_processCpuData[i].cutime
164                             + g_processCpuData[i].cstime) * Hz;
165         double cpuUsage = static_cast<double>(cpuTimeMs) / bootTime * PERCENT;
166         cpuDataVec.push_back({cpuUsage, 1, cpuTimeMs});
167     }
168     cpuDataVec[1].threadSum = THREAD_NUM;
169 }
170 
171 /**
172  * @tc.name: process plugin
173  * @tc.desc: Test whether the path exists.
174  * @tc.type: FUNC
175  */
176 HWTEST_F(ProcessDataPluginTest, TestPath, TestSize.Level1)
177 {
178     g_path = GetFullPath(DEFAULT_TEST_PATH);
179     g_testPath = g_path;
180     EXPECT_NE("", g_path);
181 }
182 
183 /**
184  * @tc.name: process plugin
185  * @tc.desc: process plugin test for report process tree.
186  * @tc.type: FUNC
187  */
188 HWTEST_F(ProcessDataPluginTest, TestPluginReportProcessTree, TestSize.Level1)
189 {
190     g_path = g_testPath + "/proc/";
191     processPlugin = std::make_shared<ProcessDataPlugin>();
192     processPlugin->SetPath(g_path);
193 
194     ProcessData processData;
195     ProcessConfig processConfig;
196     processConfig.set_report_process_tree(true);
197     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
198 
199     for (int i = 0; i < PROCESS_NUM && i < processData.processesinfo().size(); i++) {
200         ProcessInfo processesinfo = processData.processesinfo()[i];
201         EXPECT_EQ(processesinfo.pid(), g_processStatus[i].pid);
202         EXPECT_STREQ(processesinfo.name().c_str(), g_processStatus[i].name.c_str());
203         EXPECT_EQ(processesinfo.ppid(), g_processStatus[i].ppid);
204         EXPECT_EQ(processesinfo.uid(), g_processStatus[i].uid);
205     }
206 
207     EXPECT_EQ(processPlugin->Stop(), 0);
208 }
209 
210 /**
211  * @tc.name: process plugin
212  * @tc.desc: process plugin test for report cpu.
213  * @tc.type: FUNC
214  */
215 HWTEST_F(ProcessDataPluginTest, TestPluginReportCpu, TestSize.Level1)
216 {
217     g_path = g_testPath + "/proc/";
218     processPlugin = std::make_shared<ProcessDataPlugin>();
219     processPlugin->SetPath(g_path);
220 
221     ProcessData processData;
222     ProcessConfig processConfig;
223     processConfig.set_report_process_tree(true);
224     processConfig.set_report_cpu(true);
225     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
226 
227     std::vector<CpuData> cpuDataVec;
228     int64_t Hz = processPlugin->GetUserHz();
229     GetCpuData(cpuDataVec, Hz);
230     for (int i = 0; i < PROCESS_NUM && i < processData.processesinfo().size(); i++) {
231         CpuInfo cpuInfo = processData.processesinfo()[i].cpuinfo();
232         EXPECT_FLOAT_EQ(cpuInfo.cpu_usage(), cpuDataVec[i].cpuUsage);
233         EXPECT_EQ(cpuInfo.thread_sum(), cpuDataVec[i].threadSum);
234         EXPECT_EQ(cpuInfo.cpu_time_ms(), cpuDataVec[i].cpuTimeMs);
235     }
236 
237     EXPECT_EQ(processPlugin->Stop(), 0);
238 }
239 
240 /**
241  * @tc.name: process plugin
242  * @tc.desc: process plugin test for report diskio.
243  * @tc.type: FUNC
244  */
245 HWTEST_F(ProcessDataPluginTest, TestPluginReportDiskio, TestSize.Level1)
246 {
247     g_path = g_testPath + "/proc/";
248     processPlugin = std::make_shared<ProcessDataPlugin>();
249     processPlugin->SetPath(g_path);
250 
251     ProcessData processData;
252     ProcessConfig processConfig;
253     processConfig.set_report_process_tree(true);
254     processConfig.set_report_diskio(true);
255     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
256 
257     for (int i = 0; i < PROCESS_NUM && i < processData.processesinfo().size(); i++) {
258         DiskioInfo diskinfo = processData.processesinfo()[i].diskinfo();
259         EXPECT_EQ(diskinfo.rchar(), g_diskioData[i].rchar);
260         EXPECT_EQ(diskinfo.wchar(), g_diskioData[i].wchar);
261         EXPECT_EQ(diskinfo.syscr(), g_diskioData[i].syscr);
262         EXPECT_EQ(diskinfo.syscw(), g_diskioData[i].syscw);
263         EXPECT_EQ(diskinfo.rbytes(), g_diskioData[i].rbytes);
264         EXPECT_EQ(diskinfo.wbytes(), g_diskioData[i].wbytes);
265         EXPECT_EQ(diskinfo.cancelled_wbytes(), g_diskioData[i].cancelledWbytes);
266     }
267 
268     EXPECT_EQ(processPlugin->Stop(), 0);
269 }
270 
271 /**
272  * @tc.name: process plugin
273  * @tc.desc: process plugin test for report pss.
274  * @tc.type: FUNC
275  */
276 HWTEST_F(ProcessDataPluginTest, TestPluginReportPss, TestSize.Level1)
277 {
278     g_path = g_testPath + "/proc/";
279     processPlugin = std::make_shared<ProcessDataPlugin>();
280     processPlugin->SetPath(g_path);
281 
282     ProcessData processData;
283     ProcessConfig processConfig;
284     processConfig.set_report_process_tree(true);
285     processConfig.set_report_pss(true);
286     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
287 
288     for (int i = 0; i < PROCESS_NUM && i < processData.processesinfo().size(); i++) {
289         PssInfo pssinfo = processData.processesinfo()[i].pssinfo();
290         EXPECT_EQ(pssinfo.pss_info(), g_pssData[i].pssInfo);
291     }
292 
293     EXPECT_EQ(processPlugin->Stop(), 0);
294 }
295 
296 /**
297  * @tc.name: process plugin
298  * @tc.desc: process plugin test.
299  * @tc.type: FUNC
300  */
301 HWTEST_F(ProcessDataPluginTest, TestPluginReportAll, TestSize.Level1)
302 {
303     g_path = g_testPath + "/proc/";
304     processPlugin = std::make_shared<ProcessDataPlugin>();
305     processPlugin->SetPath(g_path);
306 
307     ProcessData processData;
308     ProcessConfig processConfig;
309     processConfig.set_report_process_tree(true);
310     processConfig.set_report_cpu(true);
311     processConfig.set_report_pss(true);
312     processConfig.set_report_diskio(true);
313     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
314 
315     std::vector<CpuData> cpuDataVec;
316     int64_t Hz = processPlugin->GetUserHz();
317     GetCpuData(cpuDataVec, Hz);
318     for (int i = 0; i < PROCESS_NUM && i < processData.processesinfo().size(); i++) {
319         ProcessInfo processesinfo = processData.processesinfo()[i];
320         CpuInfo cpuInfo = processData.processesinfo()[i].cpuinfo();
321         DiskioInfo diskinfo = processData.processesinfo()[i].diskinfo();
322         PssInfo pssinfo = processData.processesinfo()[i].pssinfo();
323         EXPECT_EQ(processesinfo.pid(), g_processStatus[i].pid);
324         EXPECT_STREQ(processesinfo.name().c_str(), g_processStatus[i].name.c_str());
325         EXPECT_EQ(processesinfo.ppid(), g_processStatus[i].ppid);
326         EXPECT_EQ(processesinfo.uid(), g_processStatus[i].uid);
327         EXPECT_FLOAT_EQ(cpuInfo.cpu_usage(), cpuDataVec[i].cpuUsage);
328         EXPECT_EQ(cpuInfo.thread_sum(), cpuDataVec[i].threadSum);
329         EXPECT_EQ(cpuInfo.cpu_time_ms(), cpuDataVec[i].cpuTimeMs);
330         EXPECT_EQ(diskinfo.rchar(), g_diskioData[i].rchar);
331         EXPECT_EQ(diskinfo.wchar(), g_diskioData[i].wchar);
332         EXPECT_EQ(diskinfo.syscr(), g_diskioData[i].syscr);
333         EXPECT_EQ(diskinfo.syscw(), g_diskioData[i].syscw);
334         EXPECT_EQ(diskinfo.rbytes(), g_diskioData[i].rbytes);
335         EXPECT_EQ(diskinfo.wbytes(), g_diskioData[i].wbytes);
336         EXPECT_EQ(diskinfo.cancelled_wbytes(), g_diskioData[i].cancelledWbytes);
337         EXPECT_EQ(pssinfo.pss_info(), g_pssData[i].pssInfo);
338     }
339 
340     EXPECT_EQ(processPlugin->Stop(), 0);
341 }
342 
343 /**
344  * @tc.name: process plugin
345  * @tc.desc: process plugin test for unusual path.
346  * @tc.type: FUNC
347  */
348 HWTEST_F(ProcessDataPluginTest, TestPluginUnusualPath, TestSize.Level1)
349 {
350     processPlugin = std::make_shared<ProcessDataPlugin>();
351     processPlugin->SetPath("123");
352 
353     ProcessData processData;
354     ProcessConfig processConfig;
355     processConfig.set_report_process_tree(true);
356     EXPECT_FALSE(PluginCpuinfoStub(processData, processConfig, false));
357 }
358 
359 
360 /**
361  * @tc.name: process plugin
362  * @tc.desc: process plugin test for buffer exception.
363  * @tc.type: FUNC
364  */
365 HWTEST_F(ProcessDataPluginTest, TestPluginBufferException, TestSize.Level1)
366 {
367     g_path = g_testPath + "/proc/";
368     processPlugin = std::make_shared<ProcessDataPlugin>();
369     processPlugin->SetPath(g_path);
370 
371     // 缓冲区异常
372     ProcessData processData;
373     ProcessConfig processConfig;
374     processConfig.set_report_process_tree(true);
375     EXPECT_FALSE(PluginCpuinfoStub(processData, processConfig, true));
376 }
377 
378 /**
379  * @tc.name: process plugin
380  * @tc.desc: process plugin registration test.
381  * @tc.type: FUNC
382  */
383 HWTEST_F(ProcessDataPluginTest, TestPluginRegister, TestSize.Level1)
384 {
385     void* handle = dlopen(SO_PATH.c_str(), RTLD_LAZY);
386     ASSERT_NE(handle, nullptr);
387     PluginModuleStruct* processPlugin = (PluginModuleStruct*)dlsym(handle, "g_pluginModule");
388     ASSERT_NE(processPlugin, nullptr);
389     EXPECT_STREQ(processPlugin->name, "process-plugin");
390     EXPECT_EQ(processPlugin->resultBufferSizeHint, BUF_SIZE);
391 
392     // Serialize config
393     ProcessConfig processConfig;
394     processConfig.set_report_process_tree(true);
395     int configLength = processConfig.ByteSizeLong();
396     ASSERT_GT(configLength, 0);
397     std::vector<uint8_t> configBuffer(configLength);
398     EXPECT_TRUE(processConfig.SerializeToArray(configBuffer.data(), configLength));
399 
400     // run plugin
401     std::vector<uint8_t> dataBuffer(processPlugin->resultBufferSizeHint);
402     EXPECT_EQ(processPlugin->callbacks->onPluginSessionStart(configBuffer.data(), configLength), RET_SUCC);
403     int len = processPlugin->callbacks->onPluginReportResult(dataBuffer.data(), processPlugin->resultBufferSizeHint);
404     ASSERT_GT(len, 0);
405     EXPECT_EQ(processPlugin->callbacks->onPluginSessionStop(), RET_SUCC);
406 
407     // 反序列化失败导致的start失败
408     EXPECT_EQ(processPlugin->callbacks->onPluginSessionStart(configBuffer.data(), configLength+1), RET_FAIL);
409 }
410 
411 /**
412  * @tc.name: process plugin
413  * @tc.desc: process plugin anomaly branch test.
414  * @tc.type: FUNC
415  */
416 HWTEST_F(ProcessDataPluginTest, TestPluginReportAnomaly, TestSize.Level1)
417 {
418     g_path = g_testPath + "/other/";
419     processPlugin = std::make_shared<ProcessDataPlugin>();
420     processPlugin->SetPath(g_path);
421 
422     ProcessData processData;
423     ProcessConfig processConfig;
424     processConfig.set_report_process_tree(true);
425     EXPECT_TRUE(PluginCpuinfoStub(processData, processConfig, false));
426 
427     EXPECT_EQ(processPlugin->Stop(), 0);
428 }
429 } // namespace
430