1 /*
2 * Copyright (C) 2025 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 <gtest/gtest.h>
17 #include <string>
18 #include <sys/stat.h>
19 #include <thread>
20 #include <unistd.h>
21
22 #include "hitrace_dump.h"
23 #include "trace_dump_executor.h"
24 #include "trace_dump_pipe.h"
25
26 using namespace testing::ext;
27 using namespace std;
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace Hitrace {
32 namespace {
33 static const char* const TEST_TRACE_TEMP_FILE = "/data/local/tmp/test_trace_file";
34 constexpr int BYTE_PER_MB = 1024 * 1024;
35 }
36
37 class TraceDumpExecutorTest : public testing::Test {
38 public:
SetUpTestCase(void)39 static void SetUpTestCase(void) {}
TearDownTestCase(void)40 static void TearDownTestCase(void) {}
SetUp()41 void SetUp() {}
TearDown()42 void TearDown() {}
43 };
44
45 namespace {
GetFileSize(const std::string & file)46 static off_t GetFileSize(const std::string& file)
47 {
48 struct stat fileStat;
49 if (stat(file.c_str(), &fileStat) != 0) {
50 GTEST_LOG_(ERROR) << "Failed to get file size of " << file;
51 return 0;
52 }
53 return fileStat.st_size;
54 }
55
56 /**
57 * @tc.name: TraceDumpExecutorTest001
58 * @tc.desc: Test TraceDumpExecutor class StartDumpTraceLoop/StopDumpTraceLoop function.
59 * @tc.type: FUNC
60 */
61 HWTEST_F(TraceDumpExecutorTest, TraceDumpExecutorTest001, TestSize.Level2)
62 {
63 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
64 std::string appArgs = "tags:sched,binder,ohos bufferSize:102400 overwrite:1";
65 ASSERT_EQ(OpenTrace(appArgs), TraceErrorCode::SUCCESS);
66 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
67 EXPECT_TRUE(traceDumpExecutor.PreCheckDumpTraceLoopStatus());
68 TraceDumpParam param = {
69 TraceDumpType::TRACE_RECORDING,
70 "",
71 0,
72 0,
73 0,
74 std::numeric_limits<uint64_t>::max()
75 };
__anon61b822220302(const TraceDumpParam& param) 76 auto it = [&traceDumpExecutor](const TraceDumpParam& param) {
77 EXPECT_TRUE(traceDumpExecutor.StartDumpTraceLoop(param));
78 };
79 std::thread traceLoopThread(it, param);
80 sleep(3);
81 auto list = traceDumpExecutor.StopDumpTraceLoop();
82 EXPECT_GT(list.size(), 0);
83 for (const auto& filename : list) {
84 GTEST_LOG_(INFO) << filename;
85 EXPECT_GT(GetFileSize(filename), 0);
86 }
87 traceLoopThread.join();
88 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
89 }
90
91 /**
92 * @tc.name: TraceDumpExecutorTest002
93 * @tc.desc: Test TraceDumpExecutor class StartDumpTraceLoop/StopDumpTraceLoop function.
94 * @tc.type: FUNC
95 */
96 HWTEST_F(TraceDumpExecutorTest, TraceDumpExecutorTest002, TestSize.Level2)
97 {
98 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
99 std::string appArgs = "tags:sched,binder,ohos bufferSize:102400 overwrite:1";
100 ASSERT_EQ(OpenTrace(appArgs), TraceErrorCode::SUCCESS);
101 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
102 EXPECT_TRUE(traceDumpExecutor.PreCheckDumpTraceLoopStatus());
103 TraceDumpParam param = {
104 TraceDumpType::TRACE_RECORDING,
105 TEST_TRACE_TEMP_FILE,
106 0,
107 0,
108 0,
109 std::numeric_limits<uint64_t>::max()
110 };
__anon61b822220402(const TraceDumpParam& param) 111 auto it = [&traceDumpExecutor](const TraceDumpParam& param) {
112 EXPECT_TRUE(traceDumpExecutor.StartDumpTraceLoop(param));
113 };
114 std::thread traceLoopThread(it, param);
115 sleep(3);
116 EXPECT_GT(traceDumpExecutor.StopDumpTraceLoop().size(), 0);
117 traceLoopThread.join();
118 EXPECT_GT(GetFileSize(TEST_TRACE_TEMP_FILE), 0);
119 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
120 if (remove(TEST_TRACE_TEMP_FILE) != 0) {
121 GTEST_LOG_(WARNING) << "Delete test trace file failed.";
122 }
123 }
124
125 /**
126 * @tc.name: TraceDumpExecutorTest003
127 * @tc.desc: Test TraceDumpExecutor class DumpTrace function.
128 * @tc.type: FUNC
129 */
130 HWTEST_F(TraceDumpExecutorTest, TraceDumpExecutorTest003, TestSize.Level2)
131 {
132 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
133 std::string appArgs = "tags:sched,binder,ohos bufferSize:102400 overwrite:1";
134 ASSERT_EQ(OpenTrace(appArgs), TraceErrorCode::SUCCESS);
135 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
136 TraceDumpParam param = {
137 TraceDumpType::TRACE_SNAPSHOT,
138 "",
139 0,
140 0,
141 0,
142 std::numeric_limits<uint64_t>::max()
143 };
144 auto ret = traceDumpExecutor.DumpTrace(param);
145 EXPECT_EQ(ret.code, TraceErrorCode::SUCCESS);
146 GTEST_LOG_(INFO) << "snapshot file: " << ret.outputFile;
147 EXPECT_GT(GetFileSize(ret.outputFile), 0);
148 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
149 }
150
151 /**
152 * @tc.name: TraceDumpExecutorTest004
153 * @tc.desc: Test TraceDumpExecutor class StartCacheTraceLoop/StopCacheTraceLoop function.
154 * @tc.type: FUNC
155 */
156 HWTEST_F(TraceDumpExecutorTest, TraceDumpExecutorTest004, TestSize.Level2)
157 {
158 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
159 std::string appArgs = "tags:sched,binder,ohos bufferSize:102400 overwrite:1";
160 ASSERT_EQ(OpenTrace(appArgs), TraceErrorCode::SUCCESS);
161 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
162 traceDumpExecutor.ClearCacheTraceFiles();
163 EXPECT_TRUE(traceDumpExecutor.PreCheckDumpTraceLoopStatus());
164 TraceDumpParam param = {
165 TraceDumpType::TRACE_CACHE,
166 "",
167 0, // file limit
168 0, // file size
169 0, // trace start time
170 std::numeric_limits<uint64_t>::max() // trace end time
171 };
__anon61b822220502(const TraceDumpParam& param) 172 auto it = [&traceDumpExecutor](const TraceDumpParam& param) {
173 EXPECT_TRUE(traceDumpExecutor.StartCacheTraceLoop(param, 50 * BYTE_PER_MB, 5)); // 50 : file size 5 : slice
174 };
175 std::thread traceLoopThread(it, param);
176 sleep(8); // 8 : 8 seconds
177 traceDumpExecutor.StopCacheTraceLoop();
178 traceLoopThread.join();
179 auto list = traceDumpExecutor.GetCacheTraceFiles();
180 EXPECT_EQ(list.size(), 2); // 2 : should have 2 files
181 for (const auto& file : list) {
182 GTEST_LOG_(INFO) << file.filename;
183 EXPECT_GT(GetFileSize(file.filename), 0);
184 }
185 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
186 }
187
188 /**
189 * @tc.name: TraceDumpExecutorTest005
190 * @tc.desc: Test TraceDumpExecutor class StartCacheTraceLoop/StopCacheTraceLoop function.
191 * @tc.type: FUNC
192 */
193 HWTEST_F(TraceDumpExecutorTest, TraceDumpExecutorTest005, TestSize.Level2)
194 {
195 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
196 std::string appArgs = "tags:sched,binder,ohos bufferSize:102400 overwrite:1";
197 ASSERT_EQ(OpenTrace(appArgs), TraceErrorCode::SUCCESS);
198 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
199 traceDumpExecutor.ClearCacheTraceFiles();
200 EXPECT_TRUE(traceDumpExecutor.PreCheckDumpTraceLoopStatus());
201 TraceDumpParam param = {
202 TraceDumpType::TRACE_CACHE,
203 "",
204 0, // file limit
205 0, // file size
206 0, // trace start time
207 std::numeric_limits<uint64_t>::max() // trace end time
208 };
__anon61b822220602(const TraceDumpParam& param) 209 auto it = [&traceDumpExecutor](const TraceDumpParam& param) {
210 EXPECT_TRUE(traceDumpExecutor.StartCacheTraceLoop(param, 50 * BYTE_PER_MB, 5)); // 50 : file size 5 : slice
211 };
212 std::thread traceLoopThread(it, param);
213 sleep(7);
214 auto list1 = traceDumpExecutor.GetCacheTraceFiles();
215 EXPECT_GE(list1.size(), 2); // 2 : should have 2 files
216 for (const auto& file : list1) {
217 GTEST_LOG_(INFO) << file.filename;
218 EXPECT_GT(GetFileSize(file.filename), 0);
219 }
220 sleep(1);
221 traceDumpExecutor.StopCacheTraceLoop();
222 auto list2 = traceDumpExecutor.GetCacheTraceFiles();
223 EXPECT_GE(list2.size(), 3); // 3 : should have 3 files
224 for (const auto& file : list2) {
225 GTEST_LOG_(INFO) << file.filename;
226 EXPECT_GT(GetFileSize(file.filename), 0);
227 }
228 traceLoopThread.join();
229 ASSERT_EQ(CloseTrace(), TraceErrorCode::SUCCESS);
230 }
231
232 /**
233 * @tc.name: TraceDumpPipeTest001
234 * @tc.desc: Test TraceDumpExecutor class trace task pipe
235 * @tc.type: FUNC
236 */
237 HWTEST_F(TraceDumpExecutorTest, TraceDumpPipeTest001, TestSize.Level2)
238 {
239 HitraceDumpPipe::ClearTraceDumpPipe();
240 ASSERT_TRUE(HitraceDumpPipe::InitTraceDumpPipe());
241 pid_t pid = fork();
242 if (pid < 0) {
243 FAIL() << "Failed to fork process.";
244 } else if (pid == 0) {
245 auto dumpPipe2 = std::make_shared<HitraceDumpPipe>(false);
246 TraceDumpTask task;
247 EXPECT_TRUE(dumpPipe2->ReadTraceTask(1000, task));
248 EXPECT_EQ(task.status, TraceDumpStatus::READ_DONE);
249 _exit(0);
250 }
251 auto dumpPipe1 = std::make_shared<HitraceDumpPipe>(true);
252 TraceDumpTask task = {
253 .status = TraceDumpStatus::READ_DONE,
254 };
255 EXPECT_TRUE(dumpPipe1->SubmitTraceDumpTask(task));
256 waitpid(pid, nullptr, 0);
257 HitraceDumpPipe::ClearTraceDumpPipe();
258 }
259
260 /**
261 * @tc.name: TraceDumpPipeTest002
262 * @tc.desc: Test TraceDumpExecutor class sync dump pipe
263 * @tc.type: FUNC
264 */
265 HWTEST_F(TraceDumpExecutorTest, TraceDumpPipeTest002, TestSize.Level2)
266 {
267 HitraceDumpPipe::ClearTraceDumpPipe();
268 ASSERT_TRUE(HitraceDumpPipe::InitTraceDumpPipe());
269 pid_t pid = fork();
270 if (pid < 0) {
271 FAIL() << "Failed to fork process.";
272 } else if (pid == 0) {
273 auto dumpPipe2 = std::make_shared<HitraceDumpPipe>(false);
274 TraceDumpTask task = {
275 .status = TraceDumpStatus::READ_DONE,
276 };
277 EXPECT_TRUE(dumpPipe2->WriteSyncReturn(task));
278 _exit(0);
279 }
280 auto dumpPipe1 = std::make_shared<HitraceDumpPipe>(true);
281 TraceDumpTask task;
282 EXPECT_TRUE(dumpPipe1->ReadSyncDumpRet(1, task));
283 EXPECT_EQ(task.status, TraceDumpStatus::READ_DONE);
284 waitpid(pid, nullptr, 0);
285 HitraceDumpPipe::ClearTraceDumpPipe();
286 }
287
288 /**
289 * @tc.name: TraceDumpPipeTest003
290 * @tc.desc: Test TraceDumpExecutor class async dump pipe
291 * @tc.type: FUNC
292 */
293 HWTEST_F(TraceDumpExecutorTest, TraceDumpPipeTest003, TestSize.Level2)
294 {
295 HitraceDumpPipe::ClearTraceDumpPipe();
296 ASSERT_TRUE(HitraceDumpPipe::InitTraceDumpPipe());
297 pid_t pid = fork();
298 if (pid < 0) {
299 FAIL() << "Failed to fork process.";
300 } else if (pid == 0) {
301 auto dumpPipe2 = std::make_shared<HitraceDumpPipe>(false);
302 TraceDumpTask task = {
303 .status = TraceDumpStatus::FINISH,
304 };
305 EXPECT_TRUE(dumpPipe2->WriteAsyncReturn(task));
306 _exit(0);
307 }
308 auto dumpPipe1 = std::make_shared<HitraceDumpPipe>(true);
309 TraceDumpTask task;
310 EXPECT_TRUE(dumpPipe1->ReadAsyncDumpRet(1, task));
311 EXPECT_EQ(task.status, TraceDumpStatus::FINISH);
312 waitpid(pid, nullptr, 0);
313 HitraceDumpPipe::ClearTraceDumpPipe();
314 }
315
316 /**
317 * @tc.name: TraceDumpPipeTest004
318 * @tc.desc: Test TraceDumpExecutor class trace task pipe
319 * @tc.type: FUNC
320 */
321 HWTEST_F(TraceDumpExecutorTest, TraceDumpPipeTest004, TestSize.Level2)
322 {
323 HitraceDumpPipe::ClearTraceDumpPipe();
324 ASSERT_TRUE(HitraceDumpPipe::InitTraceDumpPipe());
325 pid_t pid = fork();
326 if (pid < 0) {
327 FAIL() << "Failed to fork process.";
328 } else if (pid == 0) {
329 auto dumpPipe2 = std::make_shared<HitraceDumpPipe>(false);
330 TraceDumpTask task1;
331 EXPECT_TRUE(dumpPipe2->ReadTraceTask(1000, task1));
332 EXPECT_EQ(task1.status, TraceDumpStatus::READ_DONE);
333 TraceDumpTask task2;
334 EXPECT_TRUE(dumpPipe2->ReadTraceTask(1000, task2));
335 EXPECT_EQ(task2.status, TraceDumpStatus::READ_DONE);
336 _exit(0);
337 }
338
__anon61b822220702() 339 auto submitTask = []() {
340 auto dumpPipe = std::make_shared<HitraceDumpPipe>(true);
341 TraceDumpTask task = {
342 .status = TraceDumpStatus::READ_DONE,
343 };
344 EXPECT_TRUE(dumpPipe->SubmitTraceDumpTask(task));
345 };
346
347 std::thread submitTaskThread(submitTask);
348 std::thread submitTaskThread2(submitTask);
349 submitTaskThread.join();
350 submitTaskThread2.join();
351 waitpid(pid, nullptr, 0);
352 HitraceDumpPipe::ClearTraceDumpPipe();
353 }
354
355 /**
356 * @tc.name: TraceDumpTaskTest001
357 * @tc.desc: Test TraceDumpExecutor class task management functions
358 * @tc.type: FUNC
359 */
360 HWTEST_F(TraceDumpExecutorTest, TraceDumpTaskTest001, TestSize.Level2)
361 {
362 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
363
364 // Test IsTraceDumpTaskEmpty and GetTraceDumpTaskCount when empty
365 EXPECT_TRUE(traceDumpExecutor.IsTraceDumpTaskEmpty());
366 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 0);
367
368 // Test AddTraceDumpTask
369 TraceDumpTask task1 = {
370 .time = 1000,
371 .status = TraceDumpStatus::START,
372 .code = TraceErrorCode::UNSET,
373 };
374 traceDumpExecutor.AddTraceDumpTask(task1);
375 EXPECT_FALSE(traceDumpExecutor.IsTraceDumpTaskEmpty());
376 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 1);
377
378 // Test UpdateTraceDumpTask
379 task1.status = TraceDumpStatus::READ_DONE;
380 task1.code = TraceErrorCode::SUCCESS;
381 EXPECT_TRUE(traceDumpExecutor.UpdateTraceDumpTask(task1));
382
383 // Test RemoveTraceDumpTask
384 traceDumpExecutor.RemoveTraceDumpTask(task1.time);
385 EXPECT_TRUE(traceDumpExecutor.IsTraceDumpTaskEmpty());
386 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 0);
387 }
388
389 /**
390 * @tc.name: TraceDumpTaskTest002
391 * @tc.desc: Test TraceDumpExecutor class multiple tasks management
392 * @tc.type: FUNC
393 */
394 HWTEST_F(TraceDumpExecutorTest, TraceDumpTaskTest002, TestSize.Level2)
395 {
396 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
397
398 // Add multiple tasks
399 TraceDumpTask task1 = {
400 .time = 1000,
401 .status = TraceDumpStatus::START,
402 .code = TraceErrorCode::UNSET,
403 };
404 TraceDumpTask task2 = {
405 .time = 2000,
406 .status = TraceDumpStatus::START,
407 .code = TraceErrorCode::UNSET,
408 };
409
410 traceDumpExecutor.AddTraceDumpTask(task1);
411 traceDumpExecutor.AddTraceDumpTask(task2);
412 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 2);
413
414 // Update first task
415 task1.status = TraceDumpStatus::READ_DONE;
416 EXPECT_TRUE(traceDumpExecutor.UpdateTraceDumpTask(task1));
417
418 // Remove first task
419 traceDumpExecutor.RemoveTraceDumpTask(task1.time);
420 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 1);
421
422 // Remove second task
423 traceDumpExecutor.RemoveTraceDumpTask(task2.time);
424 EXPECT_TRUE(traceDumpExecutor.IsTraceDumpTaskEmpty());
425 }
426
427 /**
428 * @tc.name: TraceDumpTaskTest003
429 * @tc.desc: Test TraceDumpExecutor class task update with invalid data
430 * @tc.type: FUNC
431 */
432 HWTEST_F(TraceDumpExecutorTest, TraceDumpTaskTest003, TestSize.Level2)
433 {
434 TraceDumpExecutor& traceDumpExecutor = TraceDumpExecutor::GetInstance();
435
436 // Add a task
437 TraceDumpTask task = {
438 .time = 1000,
439 .status = TraceDumpStatus::START,
440 .code = TraceErrorCode::UNSET,
441 };
442 traceDumpExecutor.AddTraceDumpTask(task);
443
444 // Try to update non-existent task
445 TraceDumpTask invalidTask = {
446 .time = 9999,
447 .status = TraceDumpStatus::READ_DONE,
448 .code = TraceErrorCode::SUCCESS,
449 };
450 EXPECT_FALSE(traceDumpExecutor.UpdateTraceDumpTask(invalidTask));
451
452 // Remove non-existent task
453 traceDumpExecutor.RemoveTraceDumpTask(9999);
454 EXPECT_EQ(traceDumpExecutor.GetTraceDumpTaskCount(), 1);
455
456 // Clean up
457 traceDumpExecutor.RemoveTraceDumpTask(task.time);
458 EXPECT_TRUE(traceDumpExecutor.IsTraceDumpTaskEmpty());
459 }
460 } // namespace
461 } // namespace Hitrace
462 } // namespace HiviewDFX
463 } // namespace OHOS