blob: 7ab1e3645e26c22db24574c3946a2399850d0deb [file] [log] [blame]
/*
* 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<protos::pbzero::TrackEvent> track_event_;
internal::TrackEventIncrementalState incremental_state_;
EventContext context_;
};
using TestPayload = protos::pbzero::TestEvent::TestPayload;
TEST_F(TracedProtoTest, SingleInt_WriteField) {
protozero::HeapBuffered<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
WriteTracedProtoField(proto, TestPayload::kRepeatedInts,
std::vector<int>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
proto.AppendFrom(TestPayload::kRepeatedInts, std::vector<int>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
WriteTracedProtoField(proto, TestPayload::kStr,
std::vector<std::string>{"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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
proto.AppendFrom(TestPayload::kStr, std::vector<std::string>{"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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> message) const {
message->set_single_int(42);
auto dict = std::move(message).AddDebugAnnotations();
dict.Add("arg", "value");
}
};
struct Bar {};
} // namespace
template <>
struct TraceFormatTraits<Bar> {
static void WriteIntoTrace(
TracedProto<protos::pbzero::TestEvent::TestPayload> message,
const Bar&) {
message->set_single_string("value");
}
};
TEST_F(TracedProtoTest, SingleNestedMessage_Method) {
protozero::HeapBuffered<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> proto =
context().Wrap(event.get());
std::unique_ptr<Bar> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> proto =
context().Wrap(event.get());
std::unique_ptr<Bar> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> proto =
context().Wrap(event.get());
std::unique_ptr<Bar> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> proto =
context().Wrap(event.get());
std::unique_ptr<Bar> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
WriteTracedProtoField(proto, TestPayload::kNested,
std::vector<Foo>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
WriteTracedProtoField(proto, TestPayload::kNested,
std::vector<Bar>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
Bar bar;
std::vector<Bar*> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> 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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
proto.AppendFrom(TestPayload::kNested, std::vector<Foo>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
proto.AppendFrom(TestPayload::kNested, std::vector<Bar>{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<TestPayload> event;
perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get());
Bar bar;
std::vector<Bar*> 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<protos::pbzero::TestEvent> event;
perfetto::TracedProto<protos::pbzero::TestEvent> 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