• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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/metrics/metrics.h"
18 
19 #include <vector>
20 
21 #include "protos/perfetto/common/descriptor.pbzero.h"
22 #include "test/gtest_and_gmock.h"
23 
24 namespace perfetto {
25 namespace trace_processor {
26 namespace metrics {
27 
28 namespace {
29 
RunTemplateReplace(const std::string & str,std::unordered_map<std::string,std::string> subs)30 std::string RunTemplateReplace(
31     const std::string& str,
32     std::unordered_map<std::string, std::string> subs) {
33   std::string out;
34   EXPECT_EQ(TemplateReplace(str, subs, &out), 0);
35   return out;
36 }
37 
TEST(MetricsTest,TemplateReplace)38 TEST(MetricsTest, TemplateReplace) {
39   auto res = RunTemplateReplace("no templates here", {});
40   ASSERT_EQ(res, "no templates here");
41 
42   res = RunTemplateReplace("{{justtemplate}}", {{"justtemplate", "result"}});
43   ASSERT_EQ(res, "result");
44 
45   res = RunTemplateReplace("{{temp1}} {{temp2}}!",
46                            {{"temp1", "hello"}, {"temp2", "world"}});
47   ASSERT_EQ(res, "hello world!");
48 
49   std::string unused;
50   ASSERT_NE(TemplateReplace("{{missing}}", {{}}, &unused), 0);
51 }
52 
53 class ProtoBuilderTest : public ::testing::Test {
54  protected:
55   template <bool repeated>
DecodeSingleFieldProto(const std::vector<uint8_t> & result_ser)56   protozero::TypedProtoDecoder<1, repeated> DecodeSingleFieldProto(
57       const std::vector<uint8_t>& result_ser) {
58     protos::pbzero::ProtoBuilderResult::Decoder result(result_ser.data(),
59                                                        result_ser.size());
60     protozero::ConstBytes single_ser = result.single();
61     protos::pbzero::SingleBuilderResult::Decoder single(single_ser.data,
62                                                         single_ser.size);
63 
64     protozero::ConstBytes proto_ser = single.protobuf();
65     return protozero::TypedProtoDecoder<1, repeated>(proto_ser.data,
66                                                      proto_ser.size);
67   }
68 };
69 
TEST_F(ProtoBuilderTest,AppendLong)70 TEST_F(ProtoBuilderTest, AppendLong) {
71   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
72 
73   // Create the descriptor version of the following message:
74   // message TestProto {
75   //   optional int64 int_value = 1;
76   // }
77   DescriptorPool pool;
78   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
79                              ".perfetto.protos.TestProto",
80                              ProtoDescriptor::Type::kMessage, std::nullopt);
81   descriptor.AddField(FieldDescriptor(
82       "int_value", 1, FieldDescriptorProto::TYPE_INT64, "", false, false));
83 
84   ProtoBuilder builder(&pool, &descriptor);
85   ASSERT_TRUE(builder.AppendLong("int_value", 12345).ok());
86 
87   auto result_ser = builder.SerializeToProtoBuilderResult();
88   auto proto = DecodeSingleFieldProto<false>(result_ser);
89   const protozero::Field& int_field = proto.Get(1);
90   ASSERT_EQ(int_field.as_int64(), 12345);
91 }
92 
TEST_F(ProtoBuilderTest,AppendDouble)93 TEST_F(ProtoBuilderTest, AppendDouble) {
94   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
95 
96   // Create the descriptor version of the following message:
97   // message TestProto {
98   //   optional double double_value = 1;
99   // }
100   DescriptorPool pool;
101   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
102                              ".perfetto.protos.TestProto",
103                              ProtoDescriptor::Type::kMessage, std::nullopt);
104   descriptor.AddField(FieldDescriptor(
105       "double_value", 1, FieldDescriptorProto::TYPE_DOUBLE, "", false, false));
106 
107   ProtoBuilder builder(&pool, &descriptor);
108   ASSERT_TRUE(builder.AppendDouble("double_value", 1.2345).ok());
109 
110   auto result_ser = builder.SerializeToProtoBuilderResult();
111   auto proto = DecodeSingleFieldProto<false>(result_ser);
112   const protozero::Field& db_field = proto.Get(1);
113   ASSERT_DOUBLE_EQ(db_field.as_double(), 1.2345);
114 }
115 
TEST_F(ProtoBuilderTest,AppendString)116 TEST_F(ProtoBuilderTest, AppendString) {
117   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
118 
119   // Create the descriptor version of the following message:
120   // message TestProto {
121   //   optional string string_value = 1;
122   // }
123   DescriptorPool pool;
124   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
125                              ".perfetto.protos.TestProto",
126                              ProtoDescriptor::Type::kMessage, std::nullopt);
127   descriptor.AddField(FieldDescriptor(
128       "string_value", 1, FieldDescriptorProto::TYPE_STRING, "", false, false));
129 
130   ProtoBuilder builder(&pool, &descriptor);
131   ASSERT_TRUE(builder.AppendString("string_value", "hello world!").ok());
132 
133   auto result_ser = builder.SerializeToProtoBuilderResult();
134   auto proto = DecodeSingleFieldProto<false>(result_ser);
135   const protozero::Field& str_field = proto.Get(1);
136   ASSERT_EQ(str_field.as_std_string(), "hello world!");
137 }
138 
TEST_F(ProtoBuilderTest,AppendNested)139 TEST_F(ProtoBuilderTest, AppendNested) {
140   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
141 
142   // Create the descriptor version of the following message:
143   // message TestProto {
144   //   message NestedProto {
145   //     optional int64 nested_int_value = 1;
146   //   }
147   //   optional NestedProto nested_value = 1;
148   // }
149   DescriptorPool pool;
150   ProtoDescriptor nested("file.proto", ".perfetto.protos",
151                          ".perfetto.protos.TestProto.NestedProto",
152                          ProtoDescriptor::Type::kMessage, std::nullopt);
153   nested.AddField(FieldDescriptor("nested_int_value", 1,
154                                   FieldDescriptorProto::TYPE_INT64, "", false,
155                                   false));
156 
157   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
158                              ".perfetto.protos.TestProto",
159                              ProtoDescriptor::Type::kMessage, std::nullopt);
160   auto field =
161       FieldDescriptor("nested_value", 1, FieldDescriptorProto::TYPE_MESSAGE,
162                       ".perfetto.protos.TestProto.NestedProto", false, false);
163   field.set_resolved_type_name(".perfetto.protos.TestProto.NestedProto");
164   descriptor.AddField(field);
165 
166   ProtoBuilder nest_builder(&pool, &nested);
167   ASSERT_TRUE(nest_builder.AppendLong("nested_int_value", 789).ok());
168 
169   auto nest_ser = nest_builder.SerializeToProtoBuilderResult();
170 
171   ProtoBuilder builder(&pool, &descriptor);
172   ASSERT_TRUE(
173       builder.AppendBytes("nested_value", nest_ser.data(), nest_ser.size())
174           .ok());
175 
176   auto result_ser = builder.SerializeToProtoBuilderResult();
177   auto proto = DecodeSingleFieldProto<false>(result_ser);
178   const protozero::Field& nest_field = proto.Get(1);
179   ASSERT_EQ(nest_field.type(),
180             protozero::proto_utils::ProtoWireType::kLengthDelimited);
181 
182   protozero::ConstBytes nest_bytes = nest_field.as_bytes();
183   protozero::TypedProtoDecoder<1, false> nest(nest_bytes.data, nest_bytes.size);
184 
185   const protozero::Field& nest_int_field = nest.Get(1);
186   ASSERT_EQ(nest_int_field.type(),
187             protozero::proto_utils::ProtoWireType::kVarInt);
188   ASSERT_EQ(nest_int_field.as_int64(), 789);
189 }
190 
TEST_F(ProtoBuilderTest,AppendRepeatedPrimitive)191 TEST_F(ProtoBuilderTest, AppendRepeatedPrimitive) {
192   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
193 
194   // Create the descriptor version of the following message:
195   // message TestProto {
196   //   repeated int64 int_value = 1;
197   // }
198   DescriptorPool pool;
199   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
200                              ".perfetto.protos.TestProto",
201                              ProtoDescriptor::Type::kMessage, std::nullopt);
202   descriptor.AddField(FieldDescriptor(
203       "rep_int_value", 1, FieldDescriptorProto::TYPE_INT64, "", true, false));
204 
205   RepeatedFieldBuilder rep_builder;
206   rep_builder.AddLong(1234);
207   rep_builder.AddLong(5678);
208 
209   std::vector<uint8_t> rep_ser = rep_builder.SerializeToProtoBuilderResult();
210 
211   ProtoBuilder builder(&pool, &descriptor);
212   ASSERT_TRUE(
213       builder.AppendBytes("rep_int_value", rep_ser.data(), rep_ser.size())
214           .ok());
215 
216   auto result_ser = builder.SerializeToProtoBuilderResult();
217   auto proto = DecodeSingleFieldProto<true>(result_ser);
218   auto it = proto.GetRepeated<int64_t>(1);
219   ASSERT_EQ(*it, 1234);
220   ASSERT_EQ(*++it, 5678);
221   ASSERT_FALSE(++it);
222 }
223 
TEST_F(ProtoBuilderTest,AppendEnums)224 TEST_F(ProtoBuilderTest, AppendEnums) {
225   using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
226 
227   // Create the descriptor version of the following enum and message:
228   // enum TestEnum {
229   //   FIRST = 1,
230   //   SECOND = 2,
231   //   THIRD = 3
232   // }
233   // message TestMessage {
234   //   optional TestEnum enum_value = 1;
235   // }
236   DescriptorPool pool;
237   ProtoDescriptor enum_descriptor("file.proto", ".perfetto.protos",
238                                   ".perfetto.protos.TestEnum",
239                                   ProtoDescriptor::Type::kEnum, std::nullopt);
240   enum_descriptor.AddEnumValue(1, "FIRST");
241   enum_descriptor.AddEnumValue(2, "SECOND");
242   enum_descriptor.AddEnumValue(3, "THIRD");
243   pool.AddProtoDescriptorForTesting(enum_descriptor);
244 
245   ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
246                              ".perfetto.protos.TestMessage",
247                              ProtoDescriptor::Type::kMessage, std::nullopt);
248   FieldDescriptor enum_field("enum_value", 1, FieldDescriptorProto::TYPE_ENUM,
249                              ".perfetto.protos.TestEnum", false, false);
250   enum_field.set_resolved_type_name(".perfetto.protos.TestEnum");
251   descriptor.AddField(enum_field);
252   pool.AddProtoDescriptorForTesting(descriptor);
253 
254   ProtoBuilder value_builder(&pool, &descriptor);
255   ASSERT_FALSE(value_builder.AppendLong("enum_value", 4).ok());
256   ASSERT_TRUE(value_builder.AppendLong("enum_value", 3).ok());
257   ASSERT_FALSE(value_builder.AppendLong("enum_value", 6).ok());
258 
259   auto value_proto = DecodeSingleFieldProto<false>(
260       value_builder.SerializeToProtoBuilderResult());
261   ASSERT_EQ(value_proto.Get(1).as_int32(), 3);
262 
263   ProtoBuilder str_builder(&pool, &descriptor);
264   ASSERT_FALSE(str_builder.AppendString("enum_value", "FOURTH").ok());
265   ASSERT_TRUE(str_builder.AppendString("enum_value", "SECOND").ok());
266   ASSERT_FALSE(str_builder.AppendString("enum_value", "OTHER").ok());
267 
268   auto str_proto = DecodeSingleFieldProto<false>(
269       str_builder.SerializeToProtoBuilderResult());
270   ASSERT_EQ(str_proto.Get(1).as_int32(), 2);
271 }
272 
273 }  // namespace
274 
275 }  // namespace metrics
276 }  // namespace trace_processor
277 }  // namespace perfetto
278