• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 <iostream>
17 #include <string>
18 
19 #include "report_protobuf_file.h"
20 #include "report_protobuf_file_test.h"
21 
22 using namespace Proto;
23 using namespace testing::ext;
24 using namespace std;
25 using namespace OHOS::HiviewDFX;
26 using namespace ::testing;
27 namespace OHOS {
28 namespace Developtools {
29 namespace HiPerf {
30 class ReportProtobufFileTest : public testing::Test {
31 public:
32     static void SetUpTestCase(void);
33     static void TearDownTestCase(void);
34     void SetUp();
35     void TearDown();
36     std::unique_ptr<ReportProtobufFileWriter> protobufOutputFileWriter_ = nullptr;
37     std::unique_ptr<ReportProtobufFileReader> protobufInputFileReader_ = nullptr;
38     std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
39     void PrepareSymbolsFile();
40 };
PrepareSymbolsFile()41 void ReportProtobufFileTest::PrepareSymbolsFile()
42 {
43     symbolsFiles_.clear();
44 
45     std::string userSymbol = "user_symbol";
46     std::unique_ptr<SymbolsFile> user = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
47     user->symbols_.emplace_back(0x1, 1u, "first_user_func", user->filePath_);
48     user->symbols_.emplace_back(0x2, 1u, "second_user_func", user->filePath_);
49     user->filePath_ = userSymbol;
50     symbolsFiles_.emplace_back(std::move(user));
51 
52     std::string userSymbol2 = "user_symbol2";
53     std::unique_ptr<SymbolsFile> user2 = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
54     user2->symbols_.emplace_back(0x1, 1u, "first_user2_func", user2->filePath_);
55     user2->symbols_.emplace_back(0x2, 1u, "second_user2_func", user2->filePath_);
56     user2->symbols_.emplace_back(0x3, 1u, "third_user2_func", user2->filePath_);
57     user2->filePath_ = userSymbol2;
58     symbolsFiles_.emplace_back(std::move(user2));
59 }
60 
SetUpTestCase()61 void ReportProtobufFileTest::SetUpTestCase() {}
62 
TearDownTestCase()63 void ReportProtobufFileTest::TearDownTestCase() {}
64 
SetUp()65 void ReportProtobufFileTest::SetUp()
66 {
67     protobufOutputFileWriter_ = std::make_unique<ReportProtobufFileWriter>();
68     protobufInputFileReader_ = std::make_unique<ReportProtobufFileReader>();
69     PrepareSymbolsFile();
70 }
TearDown()71 void ReportProtobufFileTest::TearDown() {}
72 
73 /**
74  * @tc.name: Create
75  * @tc.desc:
76  * @tc.type: FUNC
77  */
78 HWTEST_F(ReportProtobufFileTest, Create, TestSize.Level1)
79 {
80     std::string fileName = "perf.proto";
81     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
82     EXPECT_EQ(access(fileName.c_str(), F_OK), 0);
83 
84     std::string errorFileName = "!@#$%^";
85     EXPECT_EQ(protobufOutputFileWriter_->Create(fileName), false);
86     EXPECT_EQ(access(errorFileName.c_str(), F_OK), -1);
87 }
88 
89 /**
90  * @tc.name: Close
91  * @tc.desc:
92  * @tc.type: FUNC
93  */
94 HWTEST_F(ReportProtobufFileTest, Close, TestSize.Level1)
95 {
96     std::string fileName = "perf.proto";
97     EXPECT_EQ(protobufOutputFileWriter_->isOpen(), false);
98     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
99     EXPECT_EQ(protobufOutputFileWriter_->isOpen(), true);
100     protobufOutputFileWriter_->Close();
101     EXPECT_EQ(protobufOutputFileWriter_->isOpen(), false);
102 }
103 
104 /**
105  * @tc.name: ProcessRecord
106  * @tc.desc:
107  * @tc.type: FUNC
108  */
109 HWTEST_F(ReportProtobufFileTest, ProcessRecord, TestSize.Level1)
110 {
111     std::string fileName = "perf.proto";
112     class ReportProtobufFileWriterMock : public ReportProtobufFileWriter {
113     public:
114         MOCK_METHOD1(ProcessRecord, bool(const PerfRecordComm &));
115         MOCK_METHOD1(ProcessRecord, bool(const PerfRecordLost &));
116     } protobufOutputFileWriter;
117 
118     const PerfRecordComm comm(false, 2, 3, "dummy");
119     const PerfRecordLost lost(false, 1, 99);
120 
121     EXPECT_CALL(protobufOutputFileWriter, ProcessRecord(Matcher<const PerfRecordComm &>(_)))
122         .Times(1);
123     protobufOutputFileWriter.ProcessRecord(comm);
124 
125     EXPECT_CALL(protobufOutputFileWriter, ProcessRecord(Matcher<const PerfRecordLost &>(_)))
126         .Times(2);
127     protobufOutputFileWriter.ProcessRecord(lost);
128     protobufOutputFileWriter.ProcessRecord(lost);
129 }
130 
131 /**
132  * @tc.name: ProcessRecordPerfRecordLost
133  * @tc.desc:
134  * @tc.type: FUNC
135  */
136 HWTEST_F(ReportProtobufFileTest, ProcessRecordPerfRecordLost, TestSize.Level1)
137 {
138     const PerfRecordLost lost(false, 1, 99);
139 
140     protobufOutputFileWriter_->ProcessRecord(lost);
141     protobufOutputFileWriter_->ProcessRecord(lost);
142     EXPECT_EQ(protobufOutputFileWriter_->recordLost_, lost.data_.lost * 2);
143 }
144 
145 /**
146  * @tc.name: ProcessRecordPerfRecordComm
147  * @tc.desc:
148  * @tc.type: FUNC
149  */
150 HWTEST_F(ReportProtobufFileTest, ProcessRecordPerfRecordComm, TestSize.Level1)
151 {
152     int expectRecord = 0;
153     std::string fileName = "perf.proto";
154     const PerfRecordComm comm(false, 2, 3, "dummy");
155     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
156 
157     protobufOutputFileWriter_->ProcessRecord(comm);
158 
159     protobufOutputFileWriter_->Close();
160 
__anoncfc228cc0102(Proto::HiperfRecord &record) 161     auto protobufReadBack = [&](Proto::HiperfRecord &record) {
162         printf("record name %s %d\n", record.GetTypeName().c_str(), record.RecordType_case());
163         // the SampleStatistic always write in close.
164         // so there at least 2 record ,one is expect , one is statiistic
165         if (record.has_thread()) {
166             const VirtualThreadInfo &message = record.thread();
167             ASSERT_EQ(message.tid(), comm.data_.tid);
168             ASSERT_EQ(message.pid(), comm.data_.pid);
169             ASSERT_STREQ(message.name().c_str(), comm.data_.comm);
170             expectRecord++;
171         }
172     };
173     protobufInputFileReader_->Dump(fileName, protobufReadBack);
174 
175     EXPECT_EQ(expectRecord, 1);
176 }
177 
178 /**
179  * @tc.name: BeforeClose
180  * @tc.desc:
181  * @tc.type: FUNC
182  */
183 HWTEST_F(ReportProtobufFileTest, BeforeClose, TestSize.Level1)
184 {
185     int expectRecord = 0;
186     std::string fileName = "perf.proto";
187     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
188     protobufOutputFileWriter_->recordLost_ = 10;
189     protobufOutputFileWriter_->recordCount_ = 20;
190     protobufOutputFileWriter_->Close();
191 
__anoncfc228cc0202(Proto::HiperfRecord &record) 192     auto protobufReadBack = [&](Proto::HiperfRecord &record) {
193         printf("record name %s %d\n", record.GetTypeName().c_str(), record.RecordType_case());
194         // the SampleStatistic always write in close.
195         // so there at least 2 record ,one is expect , one is statiistic
196         if (record.has_statistic()) {
197             const SampleStatistic &message = record.statistic();
198             ASSERT_EQ(message.count(), protobufOutputFileWriter_->recordCount_);
199             ASSERT_EQ(message.lost(), protobufOutputFileWriter_->recordLost_);
200             expectRecord++;
201         }
202     };
203 
204     protobufInputFileReader_->Dump(fileName, protobufReadBack);
205 
206     EXPECT_EQ(expectRecord, 1);
207 }
208 
209 /**
210  * @tc.name: ProcessSymbolsFiles
211  * @tc.desc:
212  * @tc.type: FUNC
213  */
214 HWTEST_F(ReportProtobufFileTest, ProcessSymbolsFiles, TestSize.Level1)
215 {
216     unsigned int expectRecord = 0;
217     std::string fileName = "perf.proto";
218     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
219 
220     protobufOutputFileWriter_->ProcessSymbolsFiles(symbolsFiles_);
221     protobufOutputFileWriter_->Close();
222 
__anoncfc228cc0302(Proto::HiperfRecord &record) 223     auto protobufReadBack = [&](Proto::HiperfRecord &record) {
224         printf("record name %s %d\n", record.GetTypeName().c_str(), record.RecordType_case());
225         // the SampleStatistic always write in close.
226         // so there at least 2 record ,one is expect , one is statiistic
227         if (record.has_file()) {
228             expectRecord++;
229             const SymbolTableFile &message = record.file();
230             ASSERT_EQ(message.id() >= 0, true);
231             ASSERT_EQ(message.id() < symbolsFiles_.size(), true);
232             const std::unique_ptr<SymbolsFile> &symbolFile = symbolsFiles_.at(message.id());
233             ASSERT_STREQ(message.path().c_str(), symbolFile->filePath_.c_str());
234             ASSERT_EQ(static_cast<size_t>(message.function_name_size()),
235                       symbolFile->GetSymbols().size());
236             for (int i = 0; i < message.function_name_size(); i++) {
237                 EXPECT_STREQ(message.function_name(i).c_str(),
238                              symbolFile->GetSymbols().at(i).name_.data());
239             }
240         }
241     };
242 
243     protobufInputFileReader_->Dump(fileName, protobufReadBack);
244 
245     EXPECT_EQ(expectRecord, symbolsFiles_.size());
246 }
247 
248 /**
249  * @tc.name: ProcessReportInfo
250  * @tc.desc:
251  * @tc.type: FUNC
252  */
253 HWTEST_F(ReportProtobufFileTest, ProcessReportInfo, TestSize.Level1)
254 {
255     int expectRecord = 0;
256     std::string fileName = "perf.proto";
257     std::vector<std::string> configNames = {"config1", "config2", "config3"};
258     std::string workloadCmd = "workcommand";
259 
260     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
261     protobufOutputFileWriter_->ProcessReportInfo(configNames, workloadCmd);
262     protobufOutputFileWriter_->Close();
263 
__anoncfc228cc0402(Proto::HiperfRecord &record) 264     auto protobufReadBack = [&](Proto::HiperfRecord &record) {
265         printf("record name %s %d\n", record.GetTypeName().c_str(), record.RecordType_case());
266         // the SampleStatistic always write in close.
267         // so there at least 2 record ,one is expect , one is statiistic
268         if (record.has_info()) {
269             const ReportInfo &message = record.info();
270             ASSERT_EQ(message.config_name_size() > 0, true);
271             ASSERT_EQ(static_cast<size_t>(message.config_name_size()), configNames.size());
272             for (int i = 0; i < message.config_name_size(); i++) {
273                 EXPECT_STREQ(message.config_name(i).c_str(), configNames.at(i).c_str());
274             }
275             if (message.has_workload_cmd()) {
276                 EXPECT_STREQ(message.workload_cmd().c_str(), workloadCmd.c_str());
277             }
278             expectRecord++;
279         }
280     };
281     protobufInputFileReader_->Dump(fileName, protobufReadBack);
282 
283     EXPECT_EQ(expectRecord, 1);
284 }
285 
286 /**
287  * @tc.name: ProcessSampleRecord
288  * @tc.desc:
289  * @tc.type: FUNC
290  */
291 HWTEST_F(ReportProtobufFileTest, ProcessSampleRecord, TestSize.Level1)
292 {
293     int expectRecord = 0;
294     std::string fileName = "perf.proto";
295     PerfRecordSample sample(false, 1, 2, 100, 200u);
296     sample.callFrames_.emplace_back(0x1, 0x1234, "first_user_func", "user_symbol");
297     sample.callFrames_.emplace_back(0x2, 0x1234, "first_user2_func", "user_symbol2");
298     sample.callFrames_.emplace_back(0x3, 0x1234, "second_user2_func", "user_symbol2");
299 
300     sample.callFrames_.at(0).symbolFileIndex_ = 0;
301     sample.callFrames_.at(1).symbolFileIndex_ = 1;
302     sample.callFrames_.at(2).symbolFileIndex_ = 1;
303     sample.callFrames_.at(0).symbolIndex_ = 0;
304     sample.callFrames_.at(1).symbolIndex_ = 0;
305     sample.callFrames_.at(2).symbolIndex_ = 1;
306 
307     ASSERT_EQ(protobufOutputFileWriter_->Create(fileName), true);
308     protobufOutputFileWriter_->ProcessSampleRecord(sample, 0u, symbolsFiles_);
309 
310     protobufOutputFileWriter_->Close();
311 
__anoncfc228cc0502(Proto::HiperfRecord &record) 312     auto protobufReadBack = [&](Proto::HiperfRecord &record) {
313         printf("record name %s %d\n", record.GetTypeName().c_str(), record.RecordType_case());
314         // the SampleStatistic always write in close.
315         // so there at least 2 record ,one is expect , one is statiistic
316         if (record.has_sample()) {
317             const CallStackSample &message = record.sample();
318             ASSERT_EQ(message.has_time(), true);
319             ASSERT_EQ(message.time(), 200u);
320 
321             ASSERT_EQ(message.has_tid(), true);
322             ASSERT_EQ(message.tid(), 2u);
323 
324             ASSERT_EQ(message.callstackframe_size() > 0, true);
325             ASSERT_EQ(static_cast<size_t>(message.callstackframe_size()),
326                       sample.callFrames_.size());
327 
328             for (int i = 0; i < message.callstackframe_size(); i++) {
329                 auto &callframe = message.callstackframe(i);
330                 ASSERT_EQ(callframe.has_symbols_vaddr(), true);
331                 ASSERT_EQ(callframe.symbols_vaddr(), sample.callFrames_.at(i).vaddrInFile_);
332 
333                 ASSERT_EQ(callframe.has_symbols_file_id(), true);
334                 printf("symbols file id %d\n", callframe.symbols_file_id());
335                 ASSERT_EQ(callframe.symbols_file_id() < symbolsFiles_.size(), true);
336                 const std::unique_ptr<SymbolsFile> &symbolsFile =
337                     symbolsFiles_.at(callframe.symbols_file_id());
338 
339                 ASSERT_EQ(callframe.has_function_name_id(), true);
340                 printf("function id %d\n", callframe.function_name_id());
341                 ASSERT_EQ(callframe.function_name_id() >= 0, true);
342                 int funcNameId = callframe.function_name_id();
343                 ASSERT_EQ(static_cast<size_t>(funcNameId) < symbolsFile->GetSymbols().size(), true);
344                 ASSERT_STREQ(sample.callFrames_.at(i).symbolName_.data(),
345                              symbolsFile->GetSymbols().at(funcNameId).name_.data());
346             }
347             ASSERT_EQ(message.has_event_count(), true);
348             ASSERT_EQ(message.event_count(), 100u);
349 
350             ASSERT_EQ(message.has_config_name_id(), true);
351             ASSERT_EQ(message.config_name_id(), 0u);
352             expectRecord++;
353         }
354     };
355     protobufInputFileReader_->Dump(fileName, protobufReadBack);
356 
357     EXPECT_EQ(expectRecord, 1);
358 }
359 } // namespace HiPerf
360 } // namespace Developtools
361 } // namespace OHOS
362