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/util/protozero_to_text.h"
18 
19 #include "perfetto/protozero/scattered_heap_buffer.h"
20 #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
21 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
22 #include "src/trace_processor/importers/track_event.descriptor.h"
23 #include "src/trace_processor/util/descriptors.h"
24 #include "test/gtest_and_gmock.h"
25 
26 namespace perfetto {
27 namespace trace_processor {
28 namespace protozero_to_text {
29 
30 namespace {
31 
32 constexpr size_t kChunkSize = 42;
33 
34 using ::testing::_;
35 using ::testing::Eq;
36 
TEST(ProtozeroToTextTest,TrackEventBasic)37 TEST(ProtozeroToTextTest, TrackEventBasic) {
38   using perfetto::protos::pbzero::TrackEvent;
39   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
40   msg->set_track_uuid(4);
41   msg->set_timestamp_delta_us(3);
42   auto binary_proto = msg.SerializeAsArray();
43   EXPECT_EQ(
44       "track_uuid: 4\ntimestamp_delta_us: 3",
45       DebugTrackEventProtozeroToText(
46           ".perfetto.protos.TrackEvent",
47           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
48   EXPECT_EQ(
49       "track_uuid: 4 timestamp_delta_us: 3",
50       ShortDebugTrackEventProtozeroToText(
51           ".perfetto.protos.TrackEvent",
52           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
53 }
54 
TEST(ProtozeroToTextTest,TrackEventNestedMsg)55 TEST(ProtozeroToTextTest, TrackEventNestedMsg) {
56   using perfetto::protos::pbzero::TrackEvent;
57   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
58   msg->set_track_uuid(4);
59   auto* state = msg->set_cc_scheduler_state();
60   state->set_deadline_us(7);
61   auto* machine = state->set_state_machine();
62   auto* minor_state = machine->set_minor_state();
63   minor_state->set_commit_count(8);
64   state->set_observing_begin_frame_source(true);
65   msg->set_timestamp_delta_us(3);
66   auto binary_proto = msg.SerializeAsArray();
67 
68   EXPECT_EQ(
69       R"(track_uuid: 4
70 cc_scheduler_state: {
71   deadline_us: 7
72   state_machine: {
73     minor_state: {
74       commit_count: 8
75     }
76   }
77   observing_begin_frame_source: true
78 }
79 timestamp_delta_us: 3)",
80       DebugTrackEventProtozeroToText(
81           ".perfetto.protos.TrackEvent",
82           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
83 
84   EXPECT_EQ(
85       "track_uuid: 4 cc_scheduler_state: { deadline_us: 7 state_machine: { "
86       "minor_state: { commit_count: 8 } } observing_begin_frame_source: true } "
87       "timestamp_delta_us: 3",
88       ShortDebugTrackEventProtozeroToText(
89           ".perfetto.protos.TrackEvent",
90           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
91 }
92 
TEST(ProtozeroToTextTest,TrackEventEnumNames)93 TEST(ProtozeroToTextTest, TrackEventEnumNames) {
94   using perfetto::protos::pbzero::TrackEvent;
95   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
96   msg->set_type(TrackEvent::TYPE_SLICE_BEGIN);
97   auto binary_proto = msg.SerializeAsArray();
98   EXPECT_EQ(
99       "type: TYPE_SLICE_BEGIN",
100       DebugTrackEventProtozeroToText(
101           ".perfetto.protos.TrackEvent",
102           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
103   EXPECT_EQ(
104       "type: TYPE_SLICE_BEGIN",
105       DebugTrackEventProtozeroToText(
106           ".perfetto.protos.TrackEvent",
107           protozero::ConstBytes{binary_proto.data(), binary_proto.size()}));
108 }
109 
TEST(ProtozeroToTextTest,CustomDescriptorPoolBasic)110 TEST(ProtozeroToTextTest, CustomDescriptorPoolBasic) {
111   using perfetto::protos::pbzero::TrackEvent;
112   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
113   msg->set_track_uuid(4);
114   msg->set_timestamp_delta_us(3);
115   auto binary_proto = msg.SerializeAsArray();
116   DescriptorPool pool;
117   auto status = pool.AddFromFileDescriptorSet(kTrackEventDescriptor.data(),
118                                               kTrackEventDescriptor.size());
119   ASSERT_TRUE(status.ok());
120   EXPECT_EQ("track_uuid: 4\ntimestamp_delta_us: 3",
121             ProtozeroToText(pool, ".perfetto.protos.TrackEvent", binary_proto,
122                             kIncludeNewLines));
123   EXPECT_EQ("track_uuid: 4 timestamp_delta_us: 3",
124             ProtozeroToText(pool, ".perfetto.protos.TrackEvent", binary_proto,
125                             kSkipNewLines));
126 }
127 
TEST(ProtozeroToTextTest,CustomDescriptorPoolNestedMsg)128 TEST(ProtozeroToTextTest, CustomDescriptorPoolNestedMsg) {
129   using perfetto::protos::pbzero::TrackEvent;
130   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
131   msg->set_track_uuid(4);
132   auto* state = msg->set_cc_scheduler_state();
133   state->set_deadline_us(7);
134   auto* machine = state->set_state_machine();
135   auto* minor_state = machine->set_minor_state();
136   minor_state->set_commit_count(8);
137   state->set_observing_begin_frame_source(true);
138   msg->set_timestamp_delta_us(3);
139   auto binary_proto = msg.SerializeAsArray();
140 
141   DescriptorPool pool;
142   auto status = pool.AddFromFileDescriptorSet(kTrackEventDescriptor.data(),
143                                               kTrackEventDescriptor.size());
144   ASSERT_TRUE(status.ok());
145 
146   EXPECT_EQ(
147       R"(track_uuid: 4
148 cc_scheduler_state: {
149   deadline_us: 7
150   state_machine: {
151     minor_state: {
152       commit_count: 8
153     }
154   }
155   observing_begin_frame_source: true
156 }
157 timestamp_delta_us: 3)",
158       ProtozeroToText(pool, ".perfetto.protos.TrackEvent", binary_proto,
159                       kIncludeNewLines));
160 
161   EXPECT_EQ(
162       "track_uuid: 4 cc_scheduler_state: { deadline_us: 7 state_machine: { "
163       "minor_state: { commit_count: 8 } } observing_begin_frame_source: true } "
164       "timestamp_delta_us: 3",
165       ProtozeroToText(pool, ".perfetto.protos.TrackEvent", binary_proto,
166                       kSkipNewLines));
167 }
168 
TEST(ProtozeroToTextTest,EnumToString)169 TEST(ProtozeroToTextTest, EnumToString) {
170   using perfetto::protos::pbzero::TrackEvent;
171   EXPECT_EQ("TYPE_SLICE_END",
172             ProtozeroEnumToText(".perfetto.protos.TrackEvent.Type",
173                                 TrackEvent::TYPE_SLICE_END));
174 }
175 
TEST(ProtozeroToTextTest,UnknownField)176 TEST(ProtozeroToTextTest, UnknownField) {
177   using perfetto::protos::pbzero::TrackEvent;
178   // Wrong type to force unknown field:
179   const auto type = ".perfetto.protos.ChromeCompositorSchedulerState";
180   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
181   auto* state = msg->set_cc_scheduler_state();
182   state->set_deadline_us(7);
183   auto* machine = state->set_state_machine();
184   auto* minor_state = machine->set_minor_state();
185   minor_state->set_commit_count(8);
186   auto bytes = msg.SerializeAsArray();
187 
188   DescriptorPool pool;
189   auto status = pool.AddFromFileDescriptorSet(kTrackEventDescriptor.data(),
190                                               kTrackEventDescriptor.size());
191   ASSERT_TRUE(status.ok());
192   ASSERT_EQ(ProtozeroToText(pool, type, bytes, kIncludeNewLines),
193             "# Ignoring unknown field with id: 24");
194 }
195 
TEST(ProtozeroToTextTest,StringField)196 TEST(ProtozeroToTextTest, StringField) {
197   using perfetto::protos::pbzero::TrackEvent;
198   // Wrong type to force unknown field:
199   const auto type = ".perfetto.protos.TrackEvent";
200   protozero::HeapBuffered<TrackEvent> msg{kChunkSize, kChunkSize};
201   msg->add_categories(R"(Hello, "World")");
202   auto bytes = msg.SerializeAsArray();
203 
204   DescriptorPool pool;
205   auto status = pool.AddFromFileDescriptorSet(kTrackEventDescriptor.data(),
206                                               kTrackEventDescriptor.size());
207   ASSERT_TRUE(status.ok());
208   ASSERT_EQ(ProtozeroToText(pool, type, bytes, kIncludeNewLines),
209             "categories: \"Hello, \\\"World\\\"\"");
210 }
211 
TEST(ProtozeroToTextTest,BytesField)212 TEST(ProtozeroToTextTest, BytesField) {
213   EXPECT_EQ(BytesToHexEncodedStringForTesting("abc"), R"(\x61\x62\x63)");
214 }
215 
216 }  // namespace
217 }  // namespace protozero_to_text
218 }  // namespace trace_processor
219 }  // namespace perfetto
220