/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/trace_processor/metrics/metrics.h" #include #include "protos/perfetto/common/descriptor.pbzero.h" #include "test/gtest_and_gmock.h" namespace perfetto { namespace trace_processor { namespace metrics { namespace { std::string RunTemplateReplace( const std::string& str, std::unordered_map subs) { std::string out; EXPECT_EQ(TemplateReplace(str, subs, &out), 0); return out; } TEST(MetricsTest, TemplateReplace) { auto res = RunTemplateReplace("no templates here", {}); ASSERT_EQ(res, "no templates here"); res = RunTemplateReplace("{{justtemplate}}", {{"justtemplate", "result"}}); ASSERT_EQ(res, "result"); res = RunTemplateReplace("{{temp1}} {{temp2}}!", {{"temp1", "hello"}, {"temp2", "world"}}); ASSERT_EQ(res, "hello world!"); std::string unused; ASSERT_NE(TemplateReplace("{{missing}}", {{}}, &unused), 0); } class ProtoBuilderTest : public ::testing::Test { protected: template protozero::TypedProtoDecoder<1, repeated> DecodeSingleFieldProto( const std::vector& result_ser) { protos::pbzero::ProtoBuilderResult::Decoder result(result_ser.data(), result_ser.size()); protozero::ConstBytes single_ser = result.single(); protos::pbzero::SingleBuilderResult::Decoder single(single_ser.data, single_ser.size); protozero::ConstBytes proto_ser = single.protobuf(); return protozero::TypedProtoDecoder<1, repeated>(proto_ser.data, proto_ser.size); } }; TEST_F(ProtoBuilderTest, AppendLong) { using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; // Create the descriptor version of the following message: // message TestProto { // optional int64 int_value = 1; // } ProtoDescriptor descriptor(".perfetto.protos", ".perfetto.protos.TestProto", ProtoDescriptor::Type::kMessage, base::nullopt); descriptor.AddField(FieldDescriptor( "int_value", 1, FieldDescriptorProto::TYPE_INT64, "", false)); ProtoBuilder builder(&descriptor); ASSERT_TRUE(builder.AppendLong("int_value", 12345).ok()); auto result_ser = builder.SerializeToProtoBuilderResult(); auto proto = DecodeSingleFieldProto(result_ser); const protozero::Field& int_field = proto.Get(1); ASSERT_EQ(int_field.as_int64(), 12345); } TEST_F(ProtoBuilderTest, AppendDouble) { using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; // Create the descriptor version of the following message: // message TestProto { // optional double double_value = 1; // } ProtoDescriptor descriptor(".perfetto.protos", ".perfetto.protos.TestProto", ProtoDescriptor::Type::kMessage, base::nullopt); descriptor.AddField(FieldDescriptor( "double_value", 1, FieldDescriptorProto::TYPE_DOUBLE, "", false)); ProtoBuilder builder(&descriptor); ASSERT_TRUE(builder.AppendDouble("double_value", 1.2345).ok()); auto result_ser = builder.SerializeToProtoBuilderResult(); auto proto = DecodeSingleFieldProto(result_ser); const protozero::Field& db_field = proto.Get(1); ASSERT_DOUBLE_EQ(db_field.as_double(), 1.2345); } TEST_F(ProtoBuilderTest, AppendString) { using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; // Create the descriptor version of the following message: // message TestProto { // optional string string_value = 1; // } ProtoDescriptor descriptor(".perfetto.protos", ".perfetto.protos.TestProto", ProtoDescriptor::Type::kMessage, base::nullopt); descriptor.AddField(FieldDescriptor( "string_value", 1, FieldDescriptorProto::TYPE_STRING, "", false)); ProtoBuilder builder(&descriptor); ASSERT_TRUE(builder.AppendString("string_value", "hello world!").ok()); auto result_ser = builder.SerializeToProtoBuilderResult(); auto proto = DecodeSingleFieldProto(result_ser); const protozero::Field& str_field = proto.Get(1); ASSERT_EQ(str_field.as_std_string(), "hello world!"); } TEST_F(ProtoBuilderTest, AppendNested) { using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; // Create the descriptor version of the following message: // message TestProto { // message NestedProto { // optional int64 nested_int_value = 1; // } // optional NestedProto nested_value = 1; // } ProtoDescriptor nested(".perfetto.protos", ".perfetto.protos.TestProto.NestedProto", ProtoDescriptor::Type::kMessage, base::nullopt); nested.AddField(FieldDescriptor("nested_int_value", 1, FieldDescriptorProto::TYPE_INT64, "", false)); ProtoDescriptor descriptor(".perfetto.protos", ".perfetto.protos.TestProto", ProtoDescriptor::Type::kMessage, base::nullopt); auto field = FieldDescriptor("nested_value", 1, FieldDescriptorProto::TYPE_MESSAGE, ".perfetto.protos.TestProto.NestedProto", false); field.set_resolved_type_name(".perfetto.protos.TestProto.NestedProto"); descriptor.AddField(field); ProtoBuilder nest_builder(&nested); ASSERT_TRUE(nest_builder.AppendLong("nested_int_value", 789).ok()); auto nest_ser = nest_builder.SerializeToProtoBuilderResult(); ProtoBuilder builder(&descriptor); ASSERT_TRUE( builder.AppendBytes("nested_value", nest_ser.data(), nest_ser.size()) .ok()); auto result_ser = builder.SerializeToProtoBuilderResult(); auto proto = DecodeSingleFieldProto(result_ser); const protozero::Field& nest_field = proto.Get(1); ASSERT_EQ(nest_field.type(), protozero::proto_utils::ProtoWireType::kLengthDelimited); protozero::ConstBytes nest_bytes = nest_field.as_bytes(); protozero::TypedProtoDecoder<1, false> nest(nest_bytes.data, nest_bytes.size); const protozero::Field& nest_int_field = nest.Get(1); ASSERT_EQ(nest_int_field.type(), protozero::proto_utils::ProtoWireType::kVarInt); ASSERT_EQ(nest_int_field.as_int64(), 789); } TEST_F(ProtoBuilderTest, AppendRepeatedPrimitive) { using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; // Create the descriptor version of the following message: // message TestProto { // repeated int64 int_value = 1; // } ProtoDescriptor descriptor(".perfetto.protos", ".perfetto.protos.TestProto", ProtoDescriptor::Type::kMessage, base::nullopt); descriptor.AddField(FieldDescriptor( "rep_int_value", 1, FieldDescriptorProto::TYPE_INT64, "", true)); RepeatedFieldBuilder rep_builder; rep_builder.AddLong(1234); rep_builder.AddLong(5678); std::vector rep_ser = rep_builder.SerializeToProtoBuilderResult(); ProtoBuilder builder(&descriptor); ASSERT_TRUE( builder.AppendBytes("rep_int_value", rep_ser.data(), rep_ser.size()) .ok()); auto result_ser = builder.SerializeToProtoBuilderResult(); auto proto = DecodeSingleFieldProto(result_ser); auto it = proto.GetRepeated(1); ASSERT_EQ(*it, 1234); ASSERT_EQ(*++it, 5678); ASSERT_FALSE(++it); } } // namespace } // namespace metrics } // namespace trace_processor } // namespace perfetto