blob: d074e796c12db2c310de944bd417d4715d011d7e [file] [log] [blame]
Alexander Timin97d87852021-05-17 18:01:33 +00001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "src/trace_processor/util/debug_annotation_parser.h"
18
19#include "perfetto/ext/base/string_view.h"
20#include "perfetto/protozero/scattered_heap_buffer.h"
Primiano Tucci3264b592021-11-08 18:20:51 +000021#include "perfetto/trace_processor/trace_blob_view.h"
Alexander Timin97d87852021-05-17 18:01:33 +000022#include "protos/perfetto/common/descriptor.pbzero.h"
23#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
24#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
25#include "src/protozero/test/example_proto/test_messages.pbzero.h"
26#include "src/trace_processor/test_messages.descriptor.h"
27#include "src/trace_processor/util/interned_message_view.h"
28#include "src/trace_processor/util/proto_to_args_parser.h"
Alexander Timin97d87852021-05-17 18:01:33 +000029#include "test/gtest_and_gmock.h"
30
31#include <sstream>
32
33namespace perfetto {
34namespace trace_processor {
35namespace util {
36namespace {
37
38base::Status ParseDebugAnnotation(
39 DebugAnnotationParser& parser,
40 protozero::HeapBuffered<protos::pbzero::DebugAnnotation>& msg,
41 ProtoToArgsParser::Delegate& delegate) {
42 std::vector<uint8_t> data = msg.SerializeAsArray();
43 return parser.Parse(protozero::ConstBytes{data.data(), data.size()},
44 delegate);
45}
46
47class DebugAnnotationParserTest : public ::testing::Test,
48 public ProtoToArgsParser::Delegate {
49 protected:
50 DebugAnnotationParserTest() {}
51
52 const std::vector<std::string>& args() const { return args_; }
53
54 private:
55 using Key = ProtoToArgsParser::Key;
56
57 void AddInteger(const Key& key, int64_t value) override {
58 std::stringstream ss;
59 ss << key.flat_key << " " << key.key << " " << value;
60 args_.push_back(ss.str());
61 }
62
63 void AddUnsignedInteger(const Key& key, uint64_t value) override {
64 std::stringstream ss;
65 ss << key.flat_key << " " << key.key << " " << value;
66 args_.push_back(ss.str());
67 }
68
69 void AddString(const Key& key, const protozero::ConstChars& value) override {
70 std::stringstream ss;
71 ss << key.flat_key << " " << key.key << " " << value.ToStdString();
72 args_.push_back(ss.str());
73 }
74
75 void AddDouble(const Key& key, double value) override {
76 std::stringstream ss;
77 ss << key.flat_key << " " << key.key << " " << value;
78 args_.push_back(ss.str());
79 }
80
81 void AddPointer(const Key& key, const void* value) override {
82 std::stringstream ss;
83 ss << key.flat_key << " " << key.key << " " << std::hex
84 << reinterpret_cast<uintptr_t>(value) << std::dec;
85 args_.push_back(ss.str());
86 }
87
88 void AddBoolean(const Key& key, bool value) override {
89 std::stringstream ss;
90 ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
91 args_.push_back(ss.str());
92 }
93
94 bool AddJson(const Key& key, const protozero::ConstChars& value) override {
95 std::stringstream ss;
96 ss << key.flat_key << " " << key.key << " " << std::hex
97 << value.ToStdString() << std::dec;
98 args_.push_back(ss.str());
99 return true;
100 }
101
Alexander Timin76778252021-10-04 13:24:46 +0000102 void AddNull(const Key& key) override {
103 std::stringstream ss;
104 ss << key.flat_key << " " << key.key << " [NULL]";
105 args_.push_back(ss.str());
106 }
107
Alexander Timin97d87852021-05-17 18:01:33 +0000108 size_t GetArrayEntryIndex(const std::string& array_key) final {
109 return array_indices_[array_key];
110 }
111
112 size_t IncrementArrayEntryIndex(const std::string& array_key) final {
113 return ++array_indices_[array_key];
114 }
115
116 InternedMessageView* GetInternedMessageView(uint32_t, uint64_t) override {
117 return nullptr;
118 }
119
120 std::vector<std::string> args_;
121 std::map<std::string, size_t> array_indices_;
122};
123
124// This test checks that in when an array is nested inside a dict which is
125// nested inside an array which is nested inside a dict, flat keys and non-flat
126// keys are parsed correctly.
127TEST_F(DebugAnnotationParserTest, DeeplyNestedDictsAndArrays) {
128 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
129
130 msg->set_name("root");
131 auto* dict1 = msg->add_dict_entries();
132 dict1->set_name("k1");
133 auto* array1 = dict1->add_array_values();
134 auto* dict2 = array1->add_dict_entries();
135 dict2->set_name("k2");
136 auto* array2 = dict2->add_array_values();
137 array2->set_int_value(42);
138
139 DescriptorPool pool;
140 auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
141 kTestMessagesDescriptor.size());
142 EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
143 << status.message();
144
145 ProtoToArgsParser args_parser(pool);
146 DebugAnnotationParser parser(args_parser);
147
148 status = ParseDebugAnnotation(parser, msg, *this);
149 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
150 << status.message();
151
152 EXPECT_THAT(args(), testing::ElementsAre("root.k1.k2 root.k1[0].k2[0] 42"));
153}
154
155// This test checks that array indexes are correctly merged across messages.
156TEST_F(DebugAnnotationParserTest, MergeArrays) {
157 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg1;
158 msg1->set_name("root");
159 auto* item1 = msg1->add_array_values();
160 item1->set_int_value(1);
161
162 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg2;
163 msg2->set_name("root");
164 auto* item2 = msg1->add_array_values();
165 item2->set_int_value(2);
166
167 DescriptorPool pool;
168 ProtoToArgsParser args_parser(pool);
169 DebugAnnotationParser parser(args_parser);
170
171 base::Status status = ParseDebugAnnotation(parser, msg1, *this);
172 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
173 << status.message();
174
175 status = ParseDebugAnnotation(parser, msg2, *this);
176 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
177 << status.message();
178
179 EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 2"));
180}
181
182// This test checks that nested empty dictionaries / arrays do not cause array
183// index to be incremented.
184TEST_F(DebugAnnotationParserTest, EmptyArrayIndexIsSkipped) {
185 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
186 msg->set_name("root");
187
188 msg->add_array_values()->set_int_value(1);
189
190 // Empty item.
191 msg->add_array_values();
192
193 msg->add_array_values()->set_int_value(3);
194
195 // Empty dict.
196 msg->add_array_values()->add_dict_entries()->set_name("key1");
197
198 auto* nested_dict_entry = msg->add_array_values()->add_dict_entries();
199 nested_dict_entry->set_name("key2");
200 nested_dict_entry->set_string_value("value");
201
202 msg->add_array_values()->set_int_value(5);
203
204 DescriptorPool pool;
205 ProtoToArgsParser args_parser(pool);
206 DebugAnnotationParser parser(args_parser);
207
208 base::Status status = ParseDebugAnnotation(parser, msg, *this);
209 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
210 << status.message();
211
212 EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 3",
213 "root.key2 root[3].key2 value",
214 "root root[4] 5"));
215}
216
217TEST_F(DebugAnnotationParserTest, NestedArrays) {
218 protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
219 msg->set_name("root");
220 auto* item1 = msg->add_array_values();
221 item1->add_array_values()->set_int_value(1);
222 item1->add_array_values()->set_int_value(2);
223 auto* item2 = msg->add_array_values();
224 item2->add_array_values()->set_int_value(3);
225 item2->add_array_values()->set_int_value(4);
226
227 DescriptorPool pool;
228 ProtoToArgsParser args_parser(pool);
229 DebugAnnotationParser parser(args_parser);
230
231 base::Status status = ParseDebugAnnotation(parser, msg, *this);
232 EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
233 << status.message();
234
235 EXPECT_THAT(args(),
236 testing::ElementsAre("root root[0][0] 1", "root root[0][1] 2",
237 "root root[1][0] 3", "root root[1][1] 4"));
238}
239
240} // namespace
241} // namespace util
242} // namespace trace_processor
243} // namespace perfetto