Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/tracing/core/proto_zero_message.h" | 5 #include "components/tracing/core/proto_zero_message.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/hash.h" | 11 #include "base/hash.h" |
| 12 #include "components/tracing/core/proto_utils.h" | 12 #include "components/tracing/core/proto_utils.h" |
| 13 #include "components/tracing/core/proto_zero_message_handle.h" | |
| 13 #include "components/tracing/test/fake_scattered_buffer.h" | 14 #include "components/tracing/test/fake_scattered_buffer.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 16 |
| 16 namespace tracing { | 17 namespace tracing { |
| 17 namespace v2 { | 18 namespace v2 { |
| 18 | 19 |
| 19 const size_t kChunkSize = 16; | 20 const size_t kChunkSize = 16; |
| 20 const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0}; | 21 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 kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'}; |
| 22 const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'}; | 23 const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'}; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 return buffer_->chunks().size() * kChunkSize - | 70 return buffer_->chunks().size() * kChunkSize - |
| 70 stream_writer_->bytes_available(); | 71 stream_writer_->bytes_available(); |
| 71 } | 72 } |
| 72 | 73 |
| 73 std::string GetNextSerializedBytes(size_t num_bytes) { | 74 std::string GetNextSerializedBytes(size_t num_bytes) { |
| 74 size_t old_readback_pos = readback_pos_; | 75 size_t old_readback_pos = readback_pos_; |
| 75 readback_pos_ += num_bytes; | 76 readback_pos_ += num_bytes; |
| 76 return buffer_->GetBytesAsString(old_readback_pos, num_bytes); | 77 return buffer_->GetBytesAsString(old_readback_pos, num_bytes); |
| 77 } | 78 } |
| 78 | 79 |
| 80 std::string GetSerializedBytes(size_t start, size_t num_bytes) { | |
| 81 return buffer_->GetBytesAsString(start, num_bytes); | |
| 82 } | |
| 83 | |
| 79 static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) { | 84 static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) { |
| 80 for (uint32_t i = 1; i <= 128; ++i) | 85 for (uint32_t i = 1; i <= 128; ++i) |
| 81 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes)); | 86 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes)); |
| 82 | 87 |
| 83 if (depth < ProtoZeroMessage::kMaxNestingDepth) { | 88 if (depth < ProtoZeroMessage::kMaxNestingDepth) { |
| 84 auto* child_msg = msg->BeginNestedMessage<FakeMessage>(1 + depth * 10); | 89 auto* child_msg = msg->BeginNestedMessage<FakeMessage>(1 + depth * 10); |
| 85 BuildNestedMessages(depth + 1, child_msg); | 90 BuildNestedMessages(depth + 1, child_msg); |
| 86 } | 91 } |
| 87 | 92 |
| 88 for (uint32_t i = 129; i <= 256; ++i) | 93 for (uint32_t i = 129; i <= 256; ++i) |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6)); | 168 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6)); |
| 164 ASSERT_EQ("2002", GetNextSerializedBytes(2)); | 169 ASSERT_EQ("2002", GetNextSerializedBytes(2)); |
| 165 | 170 |
| 166 ASSERT_EQ("2803", GetNextSerializedBytes(2)); | 171 ASSERT_EQ("2803", GetNextSerializedBytes(2)); |
| 167 } | 172 } |
| 168 | 173 |
| 169 // Checks that the size field of root and nested messages is properly written | 174 // Checks that the size field of root and nested messages is properly written |
| 170 // on finalization. | 175 // on finalization. |
| 171 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) { | 176 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) { |
| 172 ProtoZeroMessage* root_msg = NewMessage(); | 177 ProtoZeroMessage* root_msg = NewMessage(); |
| 173 uint8_t root_msg_size[proto::kMessageLengthFieldSize]; | 178 uint8_t root_msg_size[proto::kMessageLengthFieldSize] = {}; |
| 174 root_msg->set_size_field( | 179 root_msg->set_size_field( |
| 175 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]}); | 180 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]}); |
| 176 root_msg->AppendVarIntU32(1, 0x42); | 181 root_msg->AppendVarIntU32(1, 0x42); |
| 177 | 182 |
| 178 FakeMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeMessage>(2); | 183 FakeMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeMessage>(2); |
| 179 nested_msg_1->AppendVarIntU32(3, 0x43); | 184 nested_msg_1->AppendVarIntU32(3, 0x43); |
| 180 | 185 |
| 181 FakeMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeMessage>(4); | 186 FakeMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeMessage>(4); |
| 182 uint8_t buf200[200]; | 187 uint8_t buf200[200]; |
| 183 memset(buf200, 0x42, sizeof(buf200)); | 188 memset(buf200, 0x42, sizeof(buf200)); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 | 224 |
| 220 // The main point of this test is to stress the code paths and test for | 225 // 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 | 226 // unexpected crashes of the production code. The actual serialization is |
| 222 // already covered in the other text fixtures. Keeping just a final smoke test | 227 // already covered in the other text fixtures. Keeping just a final smoke test |
| 223 // here on the full buffer hash. | 228 // here on the full buffer hash. |
| 224 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes()); | 229 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes()); |
| 225 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size()); | 230 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size()); |
| 226 EXPECT_EQ(0x14BC1BA3u, buf_hash); | 231 EXPECT_EQ(0x14BC1BA3u, buf_hash); |
| 227 } | 232 } |
| 228 | 233 |
| 234 TEST_F(ProtoZeroMessageTest, MessageHandle) { | |
| 235 ProtoZeroMessage* msg1 = NewMessage(); | |
| 236 ProtoZeroMessage* msg2 = NewMessage(); | |
| 237 ProtoZeroMessage* msg3 = NewMessage(); | |
| 238 ProtoZeroMessage* ignored_msg = NewMessage(); | |
| 239 uint8_t msg1_size[proto::kMessageLengthFieldSize] = {}; | |
| 240 uint8_t msg2_size[proto::kMessageLengthFieldSize] = {}; | |
| 241 uint8_t msg3_size[proto::kMessageLengthFieldSize] = {}; | |
| 242 msg1->set_size_field( | |
| 243 {&msg1_size[0], &msg1_size[proto::kMessageLengthFieldSize]}); | |
| 244 msg2->set_size_field( | |
| 245 {&msg2_size[0], &msg2_size[proto::kMessageLengthFieldSize]}); | |
| 246 msg3->set_size_field( | |
| 247 {&msg3_size[0], &msg3_size[proto::kMessageLengthFieldSize]}); | |
| 248 | |
| 249 // Test that the handle going out of scope causes the finalization of the | |
| 250 // target message. | |
| 251 { | |
| 252 ProtoZeroMessageHandleBase handle1(msg1); | |
| 253 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */); | |
| 254 ASSERT_EQ(0u, msg1_size[0]); | |
| 255 } | |
| 256 ASSERT_EQ(0x83u, msg1_size[0]); | |
| 257 | |
| 258 // Test that the handle can be late initialized. | |
| 259 ProtoZeroMessageHandleBase handle2(ignored_msg); | |
| 260 handle2 = ProtoZeroMessageHandleBase(msg2); | |
| 261 handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */); | |
| 262 ASSERT_EQ(0u, msg2_size[0]); // |msg2| should not be finalized yet. | |
| 263 | |
| 264 // Test that std::move works and does NOT cause finalization of the moved | |
| 265 // message. | |
| 266 ProtoZeroMessageHandleBase handle_swp(ignored_msg); | |
| 267 handle_swp = std::move(handle2); | |
| 268 ASSERT_EQ(0u, msg2_size[0]); // msg2 should be NOT finalized yet. | |
| 269 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */); | |
| 270 | |
| 271 ProtoZeroMessageHandleBase handle3(msg3); | |
| 272 handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */); | |
| 273 ASSERT_EQ(0u, msg3_size[0]); // msg2 should be NOT finalized yet. | |
| 274 | |
| 275 // Both |handle3| and |handle_swp| point to a valid message (respectively, | |
| 276 // |msg3| and |msg2|). Now move |handle3| into |handle_swp|. | |
| 277 handle_swp = std::move(handle3); | |
| 278 ASSERT_EQ(0x89u, msg2_size[0]); // |msg2| should be finalized at this point. | |
| 279 | |
| 280 // At this point writing into handle_swp should actually write into |msg3|. | |
| 281 ASSERT_EQ(msg3, &*handle_swp); | |
| 282 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */); | |
| 283 ProtoZeroMessageHandleBase another_handle(ignored_msg); | |
| 284 handle_swp = std::move(another_handle); | |
| 285 ASSERT_EQ(0x90u, msg3_size[0]); // |msg3| should be finalized at this point. | |
| 286 | |
| 287 #if DCHECK_IS_ON() | |
| 288 // In developer builds w/ DCHECK on a finalized message should invalidate the | |
| 289 // handle, in order to early catch bugs in the client code. | |
| 290 ProtoZeroMessage* msg4 = NewMessage(); | |
| 291 ProtoZeroMessageHandleBase handle4(msg4); | |
| 292 ASSERT_EQ(msg4, &*handle4); | |
| 293 msg4->Finalize(); | |
| 294 ASSERT_EQ(nullptr, &*handle4); | |
| 295 #endif | |
| 296 | |
| 297 // Test also the behavior of handle with non-root (nested) messages. | |
| 298 | |
| 299 ContiguousMemoryRange size_msg_2; | |
| 300 { | |
| 301 auto* child_msg_1 = NewMessage()->BeginNestedMessage<FakeMessage>(3); | |
| 302 ProtoZeroMessageHandle<FakeMessage> child_handle_1(child_msg_1); | |
| 303 ContiguousMemoryRange size_msg_1 = child_msg_1->size_field(); | |
| 304 memset(size_msg_1.begin, 0, size_msg_1.size()); | |
| 305 child_handle_1->AppendVarIntU32(1, 0x11); | |
| 306 | |
| 307 auto* child_msg_2 = NewMessage()->BeginNestedMessage<FakeMessage>(2); | |
| 308 size_msg_2 = child_msg_2->size_field(); | |
| 309 memset(size_msg_2.begin, 0, size_msg_2.size()); | |
| 310 ProtoZeroMessageHandle<FakeMessage> child_handle_2(child_msg_2); | |
| 311 child_handle_2->AppendVarIntU32(2, 0xFF); | |
| 312 | |
| 313 // |child_msg_1| should not be finalized yet. | |
| 314 ASSERT_EQ(0u, size_msg_1.begin[0]); | |
| 315 | |
| 316 // should stay NOT finalized, until end of the current scope. | |
| 317 child_handle_1 = std::move(child_handle_2); | |
| 318 // This move should cause |child_msg_1| to be finalized, while |child_msg_2| | |
|
alph
2016/07/20 18:35:00
s/while/but not/
Primiano Tucci (use gerrit)
2016/07/21 10:50:03
Oh I must have accidentally swapped the lines. Thi
| |
| 319 ASSERT_EQ(0x82u, size_msg_1.begin[0]); | |
| 320 ASSERT_EQ(0u, size_msg_2.begin[0]); | |
| 321 } | |
| 322 ASSERT_EQ(0x83u, size_msg_2.begin[0]); | |
| 323 } | |
| 324 | |
| 229 } // namespace v2 | 325 } // namespace v2 |
| 230 } // namespace tracing | 326 } // namespace tracing |
| OLD | NEW |