1 /*
2 * Copyright (C) 2017 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 "perfetto/ext/tracing/core/trace_packet.h"
18
19 #include <string>
20
21 #include "protos/perfetto/trace/test_event.gen.h"
22 #include "protos/perfetto/trace/trace.gen.h"
23 #include "protos/perfetto/trace/trace_packet.gen.h"
24 #include "test/gtest_and_gmock.h"
25
26 namespace perfetto {
27 namespace {
28
TEST(TracePacketTest,Simple)29 TEST(TracePacketTest, Simple) {
30 protos::gen::TracePacket proto;
31 proto.mutable_for_testing()->set_str("string field");
32 std::string ser_buf = proto.SerializeAsString();
33 TracePacket tp;
34 tp.AddSlice(ser_buf.data(), ser_buf.size());
35 auto slice = tp.slices().begin();
36 ASSERT_NE(tp.slices().end(), slice);
37 ASSERT_EQ(ser_buf.data(), slice->start);
38 ASSERT_EQ(ser_buf.size(), slice->size);
39 ASSERT_EQ(tp.slices().end(), ++slice);
40
41 protos::gen::TracePacket decoded_packet;
42 ASSERT_TRUE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
43 ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
44 }
45
TEST(TracePacketTest,Sliced)46 TEST(TracePacketTest, Sliced) {
47 protos::gen::TracePacket proto;
48 proto.mutable_for_testing()->set_str(
49 "this is an arbitrarily long string ........................");
50 std::string ser_buf = proto.SerializeAsString();
51 TracePacket tp;
52 tp.AddSlice({ser_buf.data(), 3});
53 tp.AddSlice({ser_buf.data() + 3, 5});
54 tp.AddSlice({ser_buf.data() + 3 + 5, ser_buf.size() - 3 - 5});
55 ASSERT_EQ(ser_buf.size(), tp.size());
56
57 auto slice = tp.slices().begin();
58 ASSERT_NE(tp.slices().end(), slice);
59 ASSERT_EQ(ser_buf.data(), slice->start);
60 ASSERT_EQ(3u, slice->size);
61
62 ASSERT_NE(tp.slices().end(), ++slice);
63 ASSERT_EQ(ser_buf.data() + 3, slice->start);
64 ASSERT_EQ(5u, slice->size);
65
66 ASSERT_NE(tp.slices().end(), ++slice);
67 ASSERT_EQ(ser_buf.data() + 3 + 5, slice->start);
68 ASSERT_EQ(ser_buf.size() - 3 - 5, slice->size);
69
70 ASSERT_EQ(tp.slices().end(), ++slice);
71
72 protos::gen::TracePacket decoded_packet;
73 ASSERT_TRUE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
74 ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
75 }
76
TEST(TracePacketTest,Corrupted)77 TEST(TracePacketTest, Corrupted) {
78 protos::gen::TracePacket proto;
79 proto.mutable_for_testing()->set_str("string field");
80 std::string ser_buf = proto.SerializeAsString();
81 TracePacket tp;
82 tp.AddSlice({ser_buf.data(), ser_buf.size() - 2}); // corrupted.
83 protos::gen::TracePacket decoded_packet;
84 ASSERT_FALSE(decoded_packet.ParseFromString(tp.GetRawBytesForTesting()));
85 }
86
87 // Tests that the GetProtoPreamble() logic returns a valid preamble that allows
88 // to encode a TracePacket as a field of the root trace.proto message.
TEST(TracePacketTest,GetProtoPreamble)89 TEST(TracePacketTest, GetProtoPreamble) {
90 char* preamble;
91 size_t preamble_size;
92
93 // Test empty packet.
94 TracePacket tp;
95 std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
96 ASSERT_EQ(2u, preamble_size);
97 ASSERT_EQ(0, preamble[1]);
98
99 // Test packet with one slice.
100 protos::gen::TracePacket tp_proto;
101 char payload[257];
102 for (size_t i = 0; i < sizeof(payload) - 1; i++)
103 payload[i] = 'a' + (i % 16);
104 payload[sizeof(payload) - 1] = '\0';
105 tp_proto.mutable_for_testing()->set_str(payload);
106 std::string ser_buf = tp_proto.SerializeAsString();
107 tp.AddSlice({ser_buf.data(), ser_buf.size()});
108
109 std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
110 ASSERT_EQ(3u, preamble_size);
111
112 // Verify that the content is actually parsable using libprotobuf.
113 char buf[512];
114 memcpy(buf, preamble, preamble_size);
115 ASSERT_EQ(1u, tp.slices().size());
116 memcpy(&buf[preamble_size], tp.slices()[0].start, tp.slices()[0].size);
117 protos::gen::Trace trace;
118 ASSERT_TRUE(trace.ParseFromArray(buf, preamble_size + tp.size()));
119 ASSERT_EQ(1, trace.packet_size());
120 ASSERT_EQ(payload, trace.packet()[0].for_testing().str());
121 }
122
TEST(TracePacketTest,MoveOperators)123 TEST(TracePacketTest, MoveOperators) {
124 char buf1[5]{};
125 char buf2[7]{};
126
127 TracePacket tp;
128 tp.AddSlice(buf1, sizeof(buf1));
129 tp.AddSlice(buf2, sizeof(buf2));
130 tp.AddSlice(Slice::Allocate(11));
131
132 TracePacket moved_tp(std::move(tp));
133 ASSERT_EQ(0u, tp.size());
134 ASSERT_TRUE(tp.slices().empty());
135 ASSERT_EQ(3u, moved_tp.slices().size());
136 ASSERT_EQ(5u + 7u + 11u, moved_tp.size());
137
138 TracePacket moved_tp_2;
139 moved_tp_2 = std::move(moved_tp);
140 ASSERT_EQ(0u, moved_tp.size());
141 ASSERT_TRUE(moved_tp.slices().empty());
142 ASSERT_EQ(3u, moved_tp_2.slices().size());
143 ASSERT_EQ(5u + 7u + 11u, moved_tp_2.size());
144 }
145
146 } // namespace
147 } // namespace perfetto
148