• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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