/* * Copyright (C) 2021 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 "perfetto/tracing/traced_proto.h" #include "perfetto/test/traced_value_test_support.h" #include "perfetto/tracing/track_event.h" #include "protos/perfetto/trace/test_event.gen.h" #include "protos/perfetto/trace/test_event.pb.h" #include "protos/perfetto/trace/test_event.pbzero.h" #include "protos/perfetto/trace/track_event/track_event.gen.h" #include "protos/perfetto/trace/track_event/track_event.pb.h" #include "test/gtest_and_gmock.h" namespace perfetto { class TracedProtoTest : public ::testing::Test { public: TracedProtoTest() : context_(track_event_.get(), &incremental_state_) {} EventContext& context() { return context_; } private: protozero::HeapBuffered track_event_; internal::TrackEventIncrementalState incremental_state_; EventContext context_; }; using TestPayload = protos::pbzero::TestEvent::TestPayload; TEST_F(TracedProtoTest, SingleInt_WriteField) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kSingleInt, 42); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_TRUE(result.has_single_int()); EXPECT_EQ(result.single_int(), 42); } TEST_F(TracedProtoTest, SingleInt_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.Set(TestPayload::kSingleInt, 42); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_TRUE(result.has_single_int()); EXPECT_EQ(result.single_int(), 42); } TEST_F(TracedProtoTest, RepeatedInt_WriteField) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kRepeatedInts, std::vector{1, 2, 3}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1, 2, 3)); } TEST_F(TracedProtoTest, RepeatedInt_AppendValue) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendValue(TestPayload::kRepeatedInts, 1); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1)); } TEST_F(TracedProtoTest, RepeatedInt_AppendFrom) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendFrom(TestPayload::kRepeatedInts, std::vector{1, 2, 3}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1, 2, 3)); } TEST_F(TracedProtoTest, SingleString_WriteField) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kSingleString, "foo"); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_TRUE(result.has_single_string()); EXPECT_EQ(result.single_string(), "foo"); } TEST_F(TracedProtoTest, SingleString_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.Set(TestPayload::kSingleString, "foo"); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_TRUE(result.has_single_string()); EXPECT_EQ(result.single_string(), "foo"); } TEST_F(TracedProtoTest, RepeatedString_WriteField) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kStr, std::vector{"foo", "bar"}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.str(), ::testing::ElementsAre("foo", "bar")); } TEST_F(TracedProtoTest, RepeatedString_AppendFrom) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendFrom(TestPayload::kStr, std::vector{"foo", "bar"}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.str(), ::testing::ElementsAre("foo", "bar")); } TEST_F(TracedProtoTest, RepeatedString_AppendValue) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendValue(TestPayload::kStr, "foo"); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_THAT(result.str(), ::testing::ElementsAre("foo")); } namespace { struct Foo { void WriteIntoTrace(TracedProto message) const { message->set_single_int(42); auto dict = std::move(message).AddDebugAnnotations(); dict.Add("arg", "value"); } }; struct Bar {}; } // namespace template <> struct TraceFormatTraits { static void WriteIntoTrace( TracedProto message, const Bar&) { message->set_single_string("value"); } }; TEST_F(TracedProtoTest, SingleNestedMessage_Method) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_int(), 42); } TEST_F(TracedProtoTest, SingleNestedMessage_TraceFormatTraits) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Bar()); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_Pointer) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); Bar bar; WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, &bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_UniquePtr) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); std::unique_ptr bar(new Bar); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_EmptyUniquePtr) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); std::unique_ptr bar; WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_FALSE(result.payload().has_single_string()); } TEST_F(TracedProtoTest, SingleNestedMessage_Nullptr) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, nullptr); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_FALSE(result.payload().has_single_string()); } TEST_F(TracedProtoTest, SingleNestedMessage_Method_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_int(), 42); } TEST_F(TracedProtoTest, SingleNestedMessage_TraceFormatTraits_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.Set(protos::pbzero::TestEvent::kPayload, Bar()); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_Pointer_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); Bar bar; proto.Set(protos::pbzero::TestEvent::kPayload, &bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_UniquePtr_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); std::unique_ptr bar(new Bar); proto.Set(protos::pbzero::TestEvent::kPayload, bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.payload().single_string(), "value"); } TEST_F(TracedProtoTest, SingleNestedMessage_EmptyUniquePtr_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); std::unique_ptr bar; proto.Set(protos::pbzero::TestEvent::kPayload, bar); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_FALSE(result.payload().has_single_string()); } TEST_F(TracedProtoTest, SingleNestedMessage_Nullptr_Set) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.Set(protos::pbzero::TestEvent::kPayload, nullptr); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); EXPECT_FALSE(result.payload().has_single_string()); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Method) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kNested, std::vector{Foo(), Foo()}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_int(), 42); EXPECT_EQ(result.nested(1).single_int(), 42); } TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, TestPayload::kNested, std::vector{Bar(), Bar()}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_string(), "value"); EXPECT_EQ(result.nested(1).single_string(), "value"); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); Bar bar; std::vector bars; bars.push_back(&bar); bars.push_back(nullptr); WriteTracedProtoField(proto, TestPayload::kNested, bars); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_string(), "value"); EXPECT_FALSE(result.nested(1).has_single_string()); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Method_AppendValue) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendValue(TestPayload::kNested, Foo()); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 1); EXPECT_EQ(result.nested(0).single_int(), 42); } TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits_AppendValue) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendValue(TestPayload::kNested, Bar()); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 1); EXPECT_EQ(result.nested(0).single_string(), "value"); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer_AppendValue) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); Bar bar; proto.AppendValue(TestPayload::kNested, &bar); proto.AppendValue(TestPayload::kNested, nullptr); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_string(), "value"); EXPECT_FALSE(result.nested(1).has_single_string()); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Method_AppendFrom) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendFrom(TestPayload::kNested, std::vector{Foo(), Foo()}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_int(), 42); EXPECT_EQ(result.nested(1).single_int(), 42); } TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits_AppendFrom) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); proto.AppendFrom(TestPayload::kNested, std::vector{Bar(), Bar()}); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_string(), "value"); EXPECT_EQ(result.nested(1).single_string(), "value"); } TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer_AppendFrom) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); Bar bar; std::vector bars; bars.push_back(&bar); bars.push_back(nullptr); proto.AppendFrom(TestPayload::kNested, bars); protos::TestEvent::TestPayload result; result.ParseFromString(event.SerializeAsString()); EXPECT_EQ(result.nested_size(), 2); EXPECT_EQ(result.nested(0).single_string(), "value"); EXPECT_FALSE(result.nested(1).has_single_string()); } TEST_F(TracedProtoTest, WriteDebugAnnotations) { protozero::HeapBuffered event; perfetto::TracedProto proto = context().Wrap(event.get()); WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); protos::TestEvent result; result.ParseFromString(event.SerializeAsString()); protos::DebugAnnotation dict; for (const auto& annotation : result.payload().debug_annotations()) { *dict.add_dict_entries() = annotation; } EXPECT_EQ(internal::DebugAnnotationToString(dict.SerializeAsString()), "{arg:value}"); } } // namespace perfetto