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