blob: dd8ae76286aa1dd4096ecbbb859529efceffa002 [file] [log] [blame]
Primiano Tucci2a29ac72017-10-24 17:47:19 +01001/*
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 "protozero/protozero_message.h"
18
19#include <limits>
20#include <memory>
21#include <utility>
22#include <vector>
23
Primiano Tuccid7d1be02017-10-30 17:41:34 +000024#include "base/logging.h"
Primiano Tucci2a29ac72017-10-24 17:47:19 +010025#include "gtest/gtest.h"
26#include "protozero/src/test/fake_scattered_buffer.h"
27
28namespace protozero {
29
30namespace {
31
32const size_t kChunkSize = 16;
33const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
34const char kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'};
35const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'};
36
37class FakeRootMessage : public ProtoZeroMessage {};
38class FakeChildMessage : public ProtoZeroMessage {};
39
40uint32_t SimpleHash(const std::string& str) {
41 uint32_t hash = 5381;
42 for (char c : str)
43 hash = 33 * hash + static_cast<uint32_t>(c);
44 return hash;
45}
46
47class ProtoZeroMessageTest : public ::testing::Test {
48 public:
49 void SetUp() override {
50 buffer_.reset(new FakeScatteredBuffer(kChunkSize));
51 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
52 readback_pos_ = 0;
53 }
54
55 void TearDown() override {
56 // Check that none of the messages created by the text fixtures below did
57 // under/overflow their heap boundaries.
58 for (std::unique_ptr<uint8_t[]>& mem : messages_) {
59 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
60 EXPECT_STREQ(kEndWatermark,
61 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
62 sizeof(ProtoZeroMessage)));
63 mem.reset();
64 }
65 messages_.clear();
66 stream_writer_.reset();
67 buffer_.reset();
68 }
69
70 FakeRootMessage* NewMessage() {
71 std::unique_ptr<uint8_t[]> mem(
72 new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
73 sizeof(kEndWatermark)]);
74 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
75 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
76 memset(msg_start, 0, sizeof(FakeRootMessage));
77 memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
78 sizeof(kEndWatermark));
79 messages_.push_back(std::move(mem));
80 FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
81 msg->Reset(stream_writer_.get());
82 return msg;
83 }
84
85 size_t GetNumSerializedBytes() {
86 if (buffer_->chunks().empty())
87 return 0;
88 return buffer_->chunks().size() * kChunkSize -
89 stream_writer_->bytes_available();
90 }
91
92 std::string GetNextSerializedBytes(size_t num_bytes) {
93 size_t old_readback_pos = readback_pos_;
94 readback_pos_ += num_bytes;
95 return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
96 }
97
98 static void BuildNestedMessages(ProtoZeroMessage* msg, uint32_t depth = 0) {
99 for (uint32_t i = 1; i <= 128; ++i)
100 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
101
102 if (depth < ProtoZeroMessage::kMaxNestingDepth) {
103 auto* nested_msg =
104 msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
105 BuildNestedMessages(nested_msg, depth + 1);
106 }
107
108 for (uint32_t i = 129; i <= 256; ++i)
109 msg->AppendVarInt(i, 42);
110
111 if ((depth & 2) == 0)
112 msg->Finalize();
113 }
114
115 private:
116 std::unique_ptr<FakeScatteredBuffer> buffer_;
117 std::unique_ptr<ScatteredStreamWriter> stream_writer_;
118 std::vector<std::unique_ptr<uint8_t[]>> messages_;
119 size_t readback_pos_;
120};
121
122TEST_F(ProtoZeroMessageTest, BasicTypesNoNesting) {
123 ProtoZeroMessage* msg = NewMessage();
124 msg->AppendVarInt(1 /* field_id */, 0);
125 msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max());
126 msg->AppendVarInt(3 /* field_id */, 42);
127 msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max());
128 msg->AppendFixed(5 /* field_id */, 3.1415f /* float */);
129 msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */);
130 msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
131
132 // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
133 msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
134 msg->AppendSignedVarInt(3 /* field_id */, -21);
135
136 EXPECT_EQ(74u, msg->Finalize());
137 EXPECT_EQ(74u, GetNumSerializedBytes());
138
139 // These lines match the serialization of the Append* calls above.
140 ASSERT_EQ("0800", GetNextSerializedBytes(2));
141 ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
142 ASSERT_EQ("182A", GetNextSerializedBytes(2));
143 ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
144 ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
145 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
146 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
147 ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
148 GetNextSerializedBytes(25));
149 ASSERT_EQ("1829", GetNextSerializedBytes(2));
150}
151
152TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) {
153 ProtoZeroMessage* root_msg = NewMessage();
154 root_msg->AppendVarInt(1 /* field_id */, 1);
155
156 FakeChildMessage* nested_msg =
157 root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
158 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
159 nested_msg->AppendVarInt(2 /* field_id */, 2);
160
161 nested_msg =
162 root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
163 nested_msg->AppendVarInt(4 /* field_id */, 2);
164
165 root_msg->AppendVarInt(5 /* field_id */, 3);
166
167 // The expected size of the root message is supposed to be 20 bytes:
168 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
169 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
170 // 2 bytes for the varint field (id: 2) of the 1st nested message
171 // 6 bytes for the premable of the 2nd nested message
172 // 2 bytes for the varint field (id: 4) of the 2nd nested message.
173 // 2 bytes for the last varint (id : 5) field of the root message.
174 // Test also that finalization is idempontent and Finalize() can be safely
175 // called more than once without side effects.
176 for (int i = 0; i < 3; ++i) {
177 EXPECT_EQ(20u, root_msg->Finalize());
178 EXPECT_EQ(20u, GetNumSerializedBytes());
179 }
180
181 ASSERT_EQ("0801", GetNextSerializedBytes(2));
182
183 ASSERT_EQ("820882808000", GetNextSerializedBytes(6));
184 ASSERT_EQ("1002", GetNextSerializedBytes(2));
185
186 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
187 ASSERT_EQ("2002", GetNextSerializedBytes(2));
188
189 ASSERT_EQ("2803", GetNextSerializedBytes(2));
190}
191
192// Checks that the size field of root and nested messages is properly written
193// on finalization.
194TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) {
195 ProtoZeroMessage* root_msg = NewMessage();
196 uint8_t root_msg_size[proto_utils::kMessageLengthFieldSize] = {};
197 root_msg->set_size_field(
198 {&root_msg_size[0],
199 &root_msg_size[proto_utils::kMessageLengthFieldSize]});
200 root_msg->AppendVarInt(1, 0x42);
201
202 FakeChildMessage* nested_msg_1 =
203 root_msg->BeginNestedMessage<FakeChildMessage>(2);
204 nested_msg_1->AppendVarInt(3, 0x43);
205
206 FakeChildMessage* nested_msg_2 =
207 nested_msg_1->BeginNestedMessage<FakeChildMessage>(4);
208 uint8_t buf200[200];
209 memset(buf200, 0x42, sizeof(buf200));
210 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
211
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100212 // The value returned by Finalize() should be == the full size of |root_msg|.
213 EXPECT_EQ(217u, root_msg->Finalize());
214 EXPECT_EQ(217u, GetNumSerializedBytes());
215
216 // However the size written in the size field should take into account the
217 // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded
218 // in a rendundant varint encoding of kMessageLengthFieldSize bytes.
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000219 EXPECT_STREQ("\xD9\x81\x80\x00", reinterpret_cast<char*>(root_msg_size));
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100220
221 // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble.
222 GetNextSerializedBytes(3);
223
224 // Check that the size of |nested_msg_1| was backfilled. Its size is:
225 // 203 bytes for |nest_mesg_2| (see below) + 5 bytes for its preamble +
226 // 2 bytes for the 0x43 varint = 210 bytes.
227 EXPECT_EQ("D2818000", GetNextSerializedBytes(4));
228
229 // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble.
230 GetNextSerializedBytes(3);
231
232 // Check that the size of |nested_msg_2| was backfilled. Its size is:
233 // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes.
234 EXPECT_EQ("CB818000", GetNextSerializedBytes(4));
235}
236
237TEST_F(ProtoZeroMessageTest, StressTest) {
238 std::vector<ProtoZeroMessage*> nested_msgs;
239
240 ProtoZeroMessage* root_msg = NewMessage();
241 BuildNestedMessages(root_msg);
242 root_msg->Finalize();
243
244 // The main point of this test is to stress the code paths and test for
245 // unexpected crashes of the production code. The actual serialization is
246 // already covered in the other text fixtures. Keeping just a final smoke test
247 // here on the full buffer hash.
248 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
249 size_t buf_hash = SimpleHash(full_buf);
250 EXPECT_EQ(0xfd19cc0a, buf_hash);
251}
252
253TEST_F(ProtoZeroMessageTest, MessageHandle) {
254 FakeRootMessage* msg1 = NewMessage();
255 FakeRootMessage* msg2 = NewMessage();
256 FakeRootMessage* msg3 = NewMessage();
257 FakeRootMessage* ignored_msg = NewMessage();
258 uint8_t msg1_size[proto_utils::kMessageLengthFieldSize] = {};
259 uint8_t msg2_size[proto_utils::kMessageLengthFieldSize] = {};
260 uint8_t msg3_size[proto_utils::kMessageLengthFieldSize] = {};
261 msg1->set_size_field(
262 {&msg1_size[0], &msg1_size[proto_utils::kMessageLengthFieldSize]});
263 msg2->set_size_field(
264 {&msg2_size[0], &msg2_size[proto_utils::kMessageLengthFieldSize]});
265 msg3->set_size_field(
266 {&msg3_size[0], &msg3_size[proto_utils::kMessageLengthFieldSize]});
267
268 // Test that the handle going out of scope causes the finalization of the
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000269 // target message and triggers the optional callback.
270 size_t callback_arg = 0;
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100271 {
272 ProtoZeroMessageHandle<FakeRootMessage> handle1(msg1);
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000273 handle1.set_on_finalize([&callback_arg](size_t sz) { callback_arg = sz; });
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100274 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
275 ASSERT_EQ(0u, msg1_size[0]);
276 }
277 ASSERT_EQ(0x83u, msg1_size[0]);
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000278 ASSERT_EQ(3u, callback_arg);
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100279
280 // Test that the handle can be late initialized.
281 ProtoZeroMessageHandle<FakeRootMessage> handle2(ignored_msg);
282 handle2 = ProtoZeroMessageHandle<FakeRootMessage>(msg2);
283 handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
284 ASSERT_EQ(0u, msg2_size[0]); // |msg2| should not be finalized yet.
285
286 // Test that std::move works and does NOT cause finalization of the moved
287 // message.
288 ProtoZeroMessageHandle<FakeRootMessage> handle_swp(ignored_msg);
289 handle_swp = std::move(handle2);
290 ASSERT_EQ(0u, msg2_size[0]); // msg2 should be NOT finalized yet.
291 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
292
293 ProtoZeroMessageHandle<FakeRootMessage> handle3(msg3);
294 handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
295 ASSERT_EQ(0u, msg3_size[0]); // msg2 should be NOT finalized yet.
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000296 callback_arg = 0;
297 handle3.set_on_finalize([&callback_arg](size_t sz) { callback_arg = sz; });
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100298
299 // Both |handle3| and |handle_swp| point to a valid message (respectively,
300 // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
301 handle_swp = std::move(handle3);
302 ASSERT_EQ(0x89u, msg2_size[0]); // |msg2| should be finalized at this point.
303
304 // At this point writing into handle_swp should actually write into |msg3|.
305 ASSERT_EQ(msg3, &*handle_swp);
306 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
307 ProtoZeroMessageHandle<FakeRootMessage> another_handle(ignored_msg);
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000308 ASSERT_EQ(0u, callback_arg);
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100309 handle_swp = std::move(another_handle);
310 ASSERT_EQ(0x90u, msg3_size[0]); // |msg3| should be finalized at this point.
Primiano Tucci25aff4e2017-11-23 12:18:52 +0000311 ASSERT_EQ(0x10u, callback_arg);
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100312
313#if PROTOZERO_ENABLE_HANDLE_DEBUGGING()
Primiano Tuccid7d1be02017-10-30 17:41:34 +0000314 // In developer builds w/ PERFETTO_DCHECK on a finalized message should
315 // invalidate the handle, in order to early catch bugs in the client code.
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100316 FakeRootMessage* msg4 = NewMessage();
317 ProtoZeroMessageHandle<FakeRootMessage> handle4(msg4);
318 ASSERT_EQ(msg4, &*handle4);
319 msg4->Finalize();
320 ASSERT_EQ(nullptr, &*handle4);
321#endif
322
323 // Test also the behavior of handle with non-root (nested) messages.
324
325 ContiguousMemoryRange size_msg_2;
326 {
327 auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
328 ProtoZeroMessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
329 ContiguousMemoryRange size_msg_1 = nested_msg_1->size_field();
330 memset(size_msg_1.begin, 0, size_msg_1.size());
331 child_handle_1->AppendVarInt(1, 0x11);
332
333 auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
334 size_msg_2 = nested_msg_2->size_field();
335 memset(size_msg_2.begin, 0, size_msg_2.size());
336 ProtoZeroMessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
337 child_handle_2->AppendVarInt(2, 0xFF);
338
339 // |nested_msg_1| should not be finalized yet.
340 ASSERT_EQ(0u, size_msg_1.begin[0]);
341
342 // This move should cause |nested_msg_1| to be finalized, but not
343 // |nested_msg_2|, which will be finalized only after the current scope.
344 child_handle_1 = std::move(child_handle_2);
345 ASSERT_EQ(0x82u, size_msg_1.begin[0]);
346 ASSERT_EQ(0u, size_msg_2.begin[0]);
347 }
348 ASSERT_EQ(0x83u, size_msg_2.begin[0]);
349}
350
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000351TEST_F(ProtoZeroMessageTest, MoveMessageHandle) {
352 FakeRootMessage* msg = NewMessage();
353 uint8_t msg_size[proto_utils::kMessageLengthFieldSize] = {};
354 msg->set_size_field(
355 {&msg_size[0], &msg_size[proto_utils::kMessageLengthFieldSize]});
356
357 // Test that the handle going out of scope causes the finalization of the
358 // target message.
359 {
360 ProtoZeroMessageHandle<FakeRootMessage> handle1(msg);
361 ProtoZeroMessageHandle<FakeRootMessage> handle2{};
362 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
363 handle2 = std::move(handle1);
364 ASSERT_EQ(0u, msg_size[0]);
365 }
366 ASSERT_EQ(0x83u, msg_size[0]);
367}
368
Primiano Tucci2a29ac72017-10-24 17:47:19 +0100369} // namespace
370} // namespace protozero