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