Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: components/tracing/core/proto_zero_message_unittest.cc

Issue 2134683002: tracing v2: Add base class for zero-copy protobuf (ProtoZero) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@proto_utils
Patch Set: rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/tracing/core/proto_zero_message.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/tracing/core/proto_zero_message.h"
6
7 #include <limits>
8 #include <memory>
9 #include <vector>
10
11 #include "base/hash.h"
12 #include "components/tracing/core/proto_utils.h"
13 #include "components/tracing/test/fake_scattered_buffer.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace tracing {
17 namespace v2 {
18
19 const size_t kChunkSize = 16;
20 const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
21 const char kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'};
22 const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'};
23
24 class FakeMessage : public ProtoZeroMessage {
25 public:
26 };
27
28 class ProtoZeroMessageTest : public ::testing::Test {
29 public:
30 void SetUp() override {
31 buffer_.reset(new FakeScatteredBuffer(kChunkSize));
32 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
33 readback_pos_ = 0;
34 }
35
36 void TearDown() override {
37 // Check that none of the messages created by the text fixtures below did
38 // under/overflow their heap boundaries.
39 for (std::unique_ptr<uint8_t[]>& mem : messages_) {
40 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
41 EXPECT_STREQ(kEndWatermark,
42 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
43 sizeof(ProtoZeroMessage)));
44 mem.reset();
45 }
46 messages_.clear();
47 stream_writer_.reset();
48 buffer_.reset();
49 }
50
51 ProtoZeroMessage* NewMessage() {
52 std::unique_ptr<uint8_t[]> mem(
53 new uint8_t[sizeof(kStartWatermark) + sizeof(ProtoZeroMessage) +
54 sizeof(kEndWatermark)]);
55 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
56 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
57 memset(msg_start, 0, sizeof(ProtoZeroMessage));
58 memcpy(msg_start + sizeof(ProtoZeroMessage), kEndWatermark,
59 sizeof(kEndWatermark));
60 messages_.push_back(std::move(mem));
61 ProtoZeroMessage* msg = reinterpret_cast<ProtoZeroMessage*>(msg_start);
62 msg->Reset(stream_writer_.get());
63 return msg;
64 }
65
66 size_t GetNumSerializedBytes() {
67 if (buffer_->chunks().empty())
68 return 0;
69 return buffer_->chunks().size() * kChunkSize -
70 stream_writer_->bytes_available();
71 }
72
73 std::string GetNextSerializedBytes(size_t num_bytes) {
74 size_t old_readback_pos = readback_pos_;
75 readback_pos_ += num_bytes;
76 return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
77 }
78
79 static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) {
80 for (uint32_t i = 1; i <= 128; ++i)
81 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
82
83 if (depth < ProtoZeroMessage::kMaxNestingDepth) {
84 auto* child_msg = msg->BeginNestedMessage<FakeMessage>(1 + depth * 10);
85 BuildNestedMessages(depth + 1, child_msg);
86 }
87
88 for (uint32_t i = 129; i <= 256; ++i)
89 msg->AppendVarIntU32(i, 42);
90
91 if ((depth & 2) == 0)
92 msg->Finalize();
93 }
94
95 private:
96 std::unique_ptr<FakeScatteredBuffer> buffer_;
97 std::unique_ptr<ScatteredStreamWriter> stream_writer_;
98 std::vector<std::unique_ptr<uint8_t[]>> messages_;
99 size_t readback_pos_;
100 };
101
102 TEST_F(ProtoZeroMessageTest, BasicTypesNoNesting) {
103 ProtoZeroMessage* msg = NewMessage();
104 msg->AppendVarIntU32(1 /* field_id */, 0);
105 msg->AppendVarIntU32(2 /* field_id */, std::numeric_limits<uint32_t>::max());
106 msg->AppendVarIntU64(3 /* field_id */, 42);
107 msg->AppendVarIntU64(4 /* field_id */, std::numeric_limits<uint64_t>::max());
108 msg->AppendFloat(5 /* field_id */, 3.1415f);
109 msg->AppendDouble(6 /* field_id */, 3.14159265358979323846);
110 msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
111
112 // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
113 msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
114
115 EXPECT_EQ(72u, msg->Finalize());
116 EXPECT_EQ(72u, GetNumSerializedBytes());
117
118 // These lines match the serialization of the Append* calls above.
119 ASSERT_EQ("0800", GetNextSerializedBytes(2));
120 ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
121 ASSERT_EQ("182A", GetNextSerializedBytes(2));
122 ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
123 ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
124 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
125 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
126 ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
127 GetNextSerializedBytes(25));
128 }
129
130 TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) {
131 ProtoZeroMessage* root_msg = NewMessage();
132 root_msg->AppendVarIntU32(1 /* field_id */, 1);
133
134 FakeMessage* nested_msg =
135 root_msg->BeginNestedMessage<FakeMessage>(128 /* field_id */);
136 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
137 nested_msg->AppendVarIntU32(2 /* field_id */, 2);
138
139 nested_msg = root_msg->BeginNestedMessage<FakeMessage>(129 /* field_id */);
140 nested_msg->AppendVarIntU32(4 /* field_id */, 2);
141
142 root_msg->AppendVarIntU32(5 /* field_id */, 3);
143
144 // The expected size of the root message is supposed to be 20 bytes:
145 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
146 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
147 // 2 bytes for the varint field (id: 2) of the 1st nested message
148 // 6 bytes for the premable of the 2nd nested message
149 // 2 bytes for the varint field (id: 4) of the 2nd nested message.
150 // 2 bytes for the last varint (id : 5) field of the root message.
151 // Test also that finalization is idempontent and Finalize() can be safely
152 // called more than once without side effects.
153 for (int i = 0; i < 3; ++i) {
154 EXPECT_EQ(20u, root_msg->Finalize());
155 EXPECT_EQ(20u, GetNumSerializedBytes());
156 }
157
158 ASSERT_EQ("0801", GetNextSerializedBytes(2));
159
160 ASSERT_EQ("820882808000", GetNextSerializedBytes(6));
161 ASSERT_EQ("1002", GetNextSerializedBytes(2));
162
163 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
164 ASSERT_EQ("2002", GetNextSerializedBytes(2));
165
166 ASSERT_EQ("2803", GetNextSerializedBytes(2));
167 }
168
169 // Checks that the size field of root and nested messages is properly written
170 // on finalization.
171 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) {
172 ProtoZeroMessage* root_msg = NewMessage();
173 uint8_t root_msg_size[proto::kMessageLengthFieldSize];
174 root_msg->set_size_field(
175 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]});
176 root_msg->AppendVarIntU32(1, 0x42);
177
178 FakeMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeMessage>(2);
179 nested_msg_1->AppendVarIntU32(3, 0x43);
180
181 FakeMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeMessage>(4);
182 uint8_t buf200[200];
183 memset(buf200, 0x42, sizeof(buf200));
184 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
185
186 root_msg->inc_size_already_written(6);
187
188 // The value returned by Finalize() should be == the full size of |root_msg|.
189 EXPECT_EQ(217u, root_msg->Finalize());
190 EXPECT_EQ(217u, GetNumSerializedBytes());
191
192 // However the size written in the size field should take into account the
193 // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded
194 // in a rendundant varint encoding of kMessageLengthFieldSize bytes.
195 EXPECT_STREQ("\xD3\x81\x80\x00", reinterpret_cast<char*>(root_msg_size));
196
197 // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble.
198 GetNextSerializedBytes(3);
199
200 // Check that the size of |nested_msg_1| was backfilled. Its size is:
201 // 203 bytes for |nest_mesg_2| (see below) + 5 bytes for its preamble +
202 // 2 bytes for the 0x43 varint = 210 bytes.
203 EXPECT_EQ("D2818000", GetNextSerializedBytes(4));
204
205 // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble.
206 GetNextSerializedBytes(3);
207
208 // Check that the size of |nested_msg_2| was backfilled. Its size is:
209 // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes.
210 EXPECT_EQ("CB818000", GetNextSerializedBytes(4));
211 }
212
213 TEST_F(ProtoZeroMessageTest, StressTest) {
214 std::vector<ProtoZeroMessage*> nested_msgs;
215
216 ProtoZeroMessage* root_msg = NewMessage();
217 BuildNestedMessages(0, root_msg);
218 root_msg->Finalize();
219
220 // The main point of this test is to stress the code paths and test for
221 // unexpected crashes of the production code. The actual serialization is
222 // already covered in the other text fixtures. Keeping just a final smoke test
223 // here on the full buffer hash.
224 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
225 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size());
226 EXPECT_EQ(0x14BC1BA3u, buf_hash);
227 }
228
229 } // namespace v2
230 } // namespace tracing
OLDNEW
« no previous file with comments | « components/tracing/core/proto_zero_message.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698