Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 ProtoZeroMessageTest : public ::testing::Test { | |
| 25 public: | |
| 26 void SetUp() override { | |
| 27 buffer_.reset(new FakeScatteredBuffer(kChunkSize)); | |
| 28 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get())); | |
| 29 readback_pos_ = 0; | |
| 30 } | |
| 31 | |
| 32 void TearDown() override { | |
| 33 // Check that none of the messages created by the text fixtures below did | |
| 34 // under/overflow their heap boundaries. | |
| 35 for (std::unique_ptr<uint8_t[]>& mem : messages_) { | |
| 36 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get())); | |
| 37 EXPECT_STREQ(kEndWatermark, | |
| 38 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) + | |
| 39 sizeof(ProtoZeroMessage))); | |
| 40 mem.reset(); | |
| 41 } | |
| 42 | |
|
petrcermak
2016/07/12 10:18:47
Shouldn't you also reset |messages_|? Otherwise, t
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
True. Done.
| |
| 43 stream_writer_.reset(); | |
| 44 buffer_.reset(); | |
| 45 } | |
| 46 | |
| 47 ProtoZeroMessage* NewMessage() { | |
| 48 std::unique_ptr<uint8_t[]> mem( | |
| 49 new uint8_t[sizeof(kStartWatermark) + sizeof(ProtoZeroMessage) + | |
| 50 sizeof(kEndWatermark)]); | |
| 51 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark); | |
| 52 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark)); | |
| 53 memset(msg_start, 0, sizeof(ProtoZeroMessage)); | |
| 54 memcpy(msg_start + sizeof(ProtoZeroMessage), kEndWatermark, | |
| 55 sizeof(kEndWatermark)); | |
| 56 messages_.push_back(std::move(mem)); | |
| 57 ProtoZeroMessage* msg = reinterpret_cast<ProtoZeroMessage*>(msg_start); | |
| 58 msg->Reset(stream_writer_.get()); | |
| 59 return msg; | |
| 60 } | |
| 61 | |
| 62 size_t GetNumSerializedBytes() { | |
| 63 if (buffer_->chunks().empty()) | |
| 64 return 0; | |
| 65 return buffer_->chunks().size() * kChunkSize - | |
| 66 stream_writer_->bytes_available(); | |
| 67 } | |
| 68 | |
| 69 std::string GetNextSerializedBytes(size_t num_bytes) { | |
| 70 size_t old_readback_pos = readback_pos_; | |
| 71 readback_pos_ += num_bytes; | |
| 72 return buffer_->GetBytesAsString(old_readback_pos, num_bytes); | |
| 73 } | |
| 74 | |
| 75 private: | |
| 76 std::unique_ptr<FakeScatteredBuffer> buffer_; | |
| 77 std::unique_ptr<ScatteredStreamWriter> stream_writer_; | |
| 78 std::vector<std::unique_ptr<uint8_t[]>> messages_; | |
| 79 size_t readback_pos_; | |
| 80 }; | |
| 81 | |
| 82 class FakeMessage : public ProtoZeroMessage { | |
| 83 public: | |
| 84 }; | |
| 85 | |
| 86 TEST_F(ProtoZeroMessageTest, BasicTypesNoNesting) { | |
| 87 ProtoZeroMessage* msg = NewMessage(); | |
| 88 msg->AppendVarIntU32(1 /* field_id */, 0); | |
| 89 msg->AppendVarIntU32(2 /* field_id */, std::numeric_limits<uint32_t>::max()); | |
| 90 msg->AppendVarIntU64(3 /* field_id */, 42); | |
| 91 msg->AppendVarIntU64(4 /* field_id */, std::numeric_limits<uint64_t>::max()); | |
| 92 msg->AppendFloat(5 /* field_id */, 3.1415f); | |
| 93 msg->AppendDouble(6 /* field_id */, 3.14159265358979323846); | |
| 94 msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes)); | |
| 95 | |
| 96 // Field id > 32 are expected to be varint encoded (preamble > 1 byte) | |
|
petrcermak
2016/07/12 10:18:48
nit: s/id/ids/ (because of "are")
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
Done. Also the right number is 16 not 32 :)
| |
| 97 msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF"); | |
| 98 | |
| 99 EXPECT_EQ(72u, msg->Finalize()); | |
| 100 EXPECT_EQ(72u, GetNumSerializedBytes()); | |
| 101 | |
| 102 // These lines match the serialization of the Append* calls above. | |
| 103 ASSERT_EQ("0800", GetNextSerializedBytes(2)); | |
| 104 ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6)); | |
| 105 ASSERT_EQ("182A", GetNextSerializedBytes(2)); | |
| 106 ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11)); | |
| 107 ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5)); | |
| 108 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9)); | |
| 109 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12)); | |
| 110 ASSERT_EQ("8A101630313233343536373839616263646566414243444546", | |
| 111 GetNextSerializedBytes(25)); | |
| 112 } | |
| 113 | |
| 114 TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) { | |
| 115 ProtoZeroMessage* root_msg = NewMessage(); | |
| 116 root_msg->AppendVarIntU32(1 /* field_id */, 1); | |
| 117 | |
| 118 FakeMessage* nested_msg = | |
| 119 root_msg->BeginNestedMessage<FakeMessage>(128 /* field_id */); | |
| 120 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*)); | |
| 121 nested_msg->AppendVarIntU32(2 /* field_id */, 2); | |
| 122 | |
| 123 nested_msg = root_msg->BeginNestedMessage<FakeMessage>(129 /* field_id */); | |
| 124 nested_msg->AppendVarIntU32(4 /* field_id */, 2); | |
| 125 | |
| 126 root_msg->AppendVarIntU32(5 /* field_id */, 3); | |
| 127 | |
| 128 // The expected size of the root message is supposed to be 20 bytes: | |
| 129 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload) | |
| 130 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size) | |
| 131 // 2 bytes for the varint field (id: 2) of the 1st nested message | |
| 132 // 6 bytes for the premable of the 2nd nested message | |
| 133 // 2 bytes for the varint field (id: 4) of the 2nd nested message. | |
| 134 // 2 bytes for the last varint (id : 5) field of the root message. | |
| 135 EXPECT_EQ(20u, root_msg->Finalize()); | |
| 136 EXPECT_EQ(20u, GetNumSerializedBytes()); | |
| 137 | |
| 138 ASSERT_EQ("0801", GetNextSerializedBytes(2)); | |
| 139 | |
| 140 ASSERT_EQ("820882808000", GetNextSerializedBytes(6)); | |
| 141 ASSERT_EQ("1002", GetNextSerializedBytes(2)); | |
| 142 | |
| 143 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6)); | |
| 144 ASSERT_EQ("2002", GetNextSerializedBytes(2)); | |
| 145 | |
| 146 ASSERT_EQ("2803", GetNextSerializedBytes(2)); | |
| 147 } | |
| 148 | |
| 149 // Checks that the size field of root and nested messages is properly written | |
| 150 // on finalization. | |
| 151 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) { | |
| 152 ProtoZeroMessage* root_msg = NewMessage(); | |
| 153 uint8_t root_msg_size[proto::kMessageLengthFieldSize]; | |
| 154 root_msg->set_size_field( | |
| 155 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]}); | |
| 156 root_msg->AppendVarIntU32(1, 0x42); | |
| 157 | |
| 158 FakeMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeMessage>(2); | |
| 159 nested_msg_1->AppendVarIntU32(3, 0x43); | |
| 160 | |
| 161 FakeMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeMessage>(4); | |
| 162 uint8_t buf200[200]; | |
| 163 memset(buf200, 0x42, sizeof(buf200)); | |
| 164 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200)); | |
| 165 | |
| 166 root_msg->inc_size_already_written(6); | |
| 167 | |
| 168 // The value returned by Finalize() should be == the full size of |root_msg|. | |
| 169 EXPECT_EQ(217u, root_msg->Finalize()); | |
| 170 EXPECT_EQ(217u, GetNumSerializedBytes()); | |
| 171 | |
| 172 // However the size written in the size field should take into account the | |
| 173 // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded | |
| 174 // in a rendundant varint encoding of kMessageLengthFieldSize bytes. | |
| 175 EXPECT_STREQ("\xD3\x81\x80\x00", reinterpret_cast<char*>(root_msg_size)); | |
| 176 | |
| 177 // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble. | |
| 178 GetNextSerializedBytes(3); | |
|
petrcermak
2016/07/12 10:18:47
Why don't you call EXPECT_EQ on this anyway (also
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
I don't care too much agbout the contents of these
petrcermak
2016/07/12 17:41:17
Acknowledged.
| |
| 179 | |
| 180 // Check that the size of |nested_msg_1| was backfilled. Its size is: | |
| 181 // 203 bytes for |nest_mesg_2| (see below)+ 5 bytes for its preamble + | |
|
petrcermak
2016/07/12 10:18:47
nit: missing space between "below)" and "+".
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
Done.
| |
| 182 // 2 bytes for the 0x43 varint = 210 bytes. | |
|
petrcermak
2016/07/12 10:18:47
nit: double space before "="
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
Done.
| |
| 183 EXPECT_EQ("D2818000", GetNextSerializedBytes(4)); | |
| 184 | |
| 185 // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble. | |
| 186 GetNextSerializedBytes(3); | |
| 187 | |
| 188 // Check that the size of |nested_msg_2| was backfilled. Its size is: | |
| 189 // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes. | |
| 190 EXPECT_EQ("CB818000", GetNextSerializedBytes(4)); | |
| 191 } | |
| 192 | |
| 193 TEST_F(ProtoZeroMessageTest, StressTest) { | |
| 194 std::vector<ProtoZeroMessage*> nested_msgs; | |
| 195 | |
| 196 ProtoZeroMessage* root_msg = NewMessage(); | |
| 197 | |
| 198 ProtoZeroMessage* msg = root_msg; | |
| 199 for (size_t depth = 0; depth < ProtoZeroMessage::kMaxNestingDepth; ++depth) { | |
|
petrcermak
2016/07/12 10:18:48
These two loops would be much more readable if imp
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
uh? not sure I agree, then you'd have to jump up a
petrcermak
2016/07/12 17:41:17
I still think that the following would be more rea
Primiano Tucci (use gerrit)
2016/07/13 10:25:07
ahhhhh I completely misunderstood what you meant.
| |
| 200 nested_msgs.push_back(msg); | |
| 201 for (uint32_t i = 0; i < 128; ++i) { | |
|
alph
2016/07/12 00:20:43
may get signed/unsigned comparison error on some p
Primiano Tucci (use gerrit)
2016/07/12 10:15:32
Hm there seem to be quite a few of this:
https://
| |
| 202 msg->AppendBytes(1, kTestBytes, sizeof(kTestBytes)); | |
| 203 } | |
| 204 msg = msg->BeginNestedMessage<FakeMessage>(2); | |
| 205 } | |
| 206 | |
| 207 for (size_t depth = 0; depth < ProtoZeroMessage::kMaxNestingDepth; ++depth) { | |
| 208 ProtoZeroMessage* msg = nested_msgs.back(); | |
| 209 nested_msgs.pop_back(); | |
| 210 msg->AppendVarIntU32(3, 42); | |
|
alph
2016/07/12 00:20:42
Test EndNestedMessage & Finalize calls on nested m
Primiano Tucci (use gerrit)
2016/07/12 10:15:32
Done for Finalize. Also you reminded me to add a t
| |
| 211 } | |
| 212 | |
| 213 root_msg->Finalize(); | |
| 214 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes()); | |
|
petrcermak
2016/07/12 10:18:47
Maybe at least check the length as well? You could
Primiano Tucci (use gerrit)
2016/07/12 17:25:17
Very hard you can get a different length with the
petrcermak
2016/07/12 17:41:17
Acknowledged.
| |
| 215 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size()); | |
| 216 EXPECT_EQ(0XE98498A2u, buf_hash); | |
| 217 } | |
| 218 | |
| 219 } // namespace v2 | |
| 220 } // namespace tracing | |
| OLD | NEW |