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