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

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

Issue 2308583003: tracing v2: Introduce TraceBufferReader to read-back the trace buffer (Closed)
Patch Set: DISALLOW_COPY_AND_ASSIGN + cctype for isalnum Created 4 years, 3 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
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/trace_buffer_reader.h"
6
7 #include "base/macros.h"
8 #include "base/memory/ptr_util.h"
9 #include "components/tracing/core/string_interning.h"
10 #include "components/tracing/test/golden_protos/event.pb.h"
11 #include "components/tracing/test/golden_protos/events_chunk.pb.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace tracing {
15 namespace v2 {
16 namespace {
17
18 namespace golden_protos = ::tracing::proto;
19
20 ::testing::AssertionResult ValueEquals(const char* m_expr,
21 const char* n_expr,
22 const base::Value& m,
23 const base::Value& n) {
24 if (m.Equals(&n))
25 return ::testing::AssertionSuccess();
26
27 return ::testing::AssertionFailure() << "\nExpected:\n"
28 << m << "\nActual:\n"
29 << n;
30 }
31
32 void ParseChunk(TraceBufferReader* reader, const std::string& chunk) {
33 reader->ParseChunk(reinterpret_cast<const uint8_t*>(chunk.data()),
34 chunk.size());
35 }
36
37 // Parse a zero length chunk and a chunk with no events. In both cases parsing
38 // should succeed but no event should be decoded.
39 TEST(TraceBufferReaderTest, EmptyChunk) {
40 golden_protos::EventsChunk chunk;
41 chunk.set_writer_id(1);
42 chunk.set_seq_id(0);
43
44 TraceBufferReader reader(TraceBufferReader::kBuildLegacyJSONEvents);
45 std::string zero_len_chunk;
46 ParseChunk(&reader, zero_len_chunk);
47 ParseChunk(&reader, chunk.SerializeAsString());
48 ASSERT_EQ(0u, reader.legacy_events()->GetSize());
49 }
50
51 TEST(TraceBufferReaderTest, OneChunkOneEvent) {
52 golden_protos::Event evt;
53 evt.set_type(golden_protos::Event::COMPLETE);
54 evt.set_name_str("copied_str_name");
55 auto interned_cat_name = InternString("interned_category_name");
56 evt.set_category_id(interned_cat_name);
57 evt.set_timestamp(42);
58 evt.set_thread_timestamp(0xf1f2f3f4);
59
60 golden_protos::EventsChunk chunk;
61 chunk.set_writer_id(1);
62 chunk.set_seq_id(0);
63 chunk.add_events(evt.SerializeAsString());
64
65 TraceBufferReader reader(TraceBufferReader::kBuildLegacyJSONEvents |
66 TraceBufferReader::kBuildInternedStringsTable);
67 ParseChunk(&reader, chunk.SerializeAsString());
68 ASSERT_EQ(1u, reader.legacy_events()->GetSize());
69 base::DictionaryValue* decoded_evt = nullptr;
70 ASSERT_TRUE(reader.legacy_events()->GetDictionary(0, &decoded_evt));
71
72 base::DictionaryValue expected_value;
73 expected_value.SetString("ph", "X");
74 expected_value.SetString("name", "copied_str_name");
75 expected_value.SetString("cat", "interned_category_name");
76 expected_value.SetInteger("ts", 42);
77 expected_value.SetInteger("tts", static_cast<int>(0xf1f2f3f4));
78 EXPECT_PRED_FORMAT2(ValueEquals, expected_value, *decoded_evt);
79
80 ASSERT_EQ(1u, reader.interned_strings().count(interned_cat_name));
81 EXPECT_EQ("interned_category_name",
82 reader.interned_strings().at(interned_cat_name));
83 }
84
85 TEST(TraceBufferReaderTest, OneChunkManyEvents) {
86 golden_protos::EventsChunk chunk;
87 chunk.set_writer_id(1);
88 chunk.set_seq_id(42);
89 const char* kCatNames[] = {"cat1", "cat2", "cat3", "cat4"};
90 const size_t kNumEvents = 100;
91
92 for (size_t i = 0; i < kNumEvents; ++i) {
93 golden_protos::Event evt;
94 evt.set_type(golden_protos::Event::COMPLETE);
95 evt.set_name_str("copied_str_name");
96 evt.set_category_id(InternString(kCatNames[i % arraysize(kCatNames)]));
97 evt.set_timestamp(0xff000000 + i);
98 chunk.add_events(evt.SerializeAsString());
99 }
100
101 TraceBufferReader reader(TraceBufferReader::kBuildLegacyJSONEvents |
102 TraceBufferReader::kBuildInternedStringsTable);
103 ParseChunk(&reader, chunk.SerializeAsString());
104 ASSERT_EQ(kNumEvents, reader.legacy_events()->GetSize());
105 for (size_t i = 0; i < kNumEvents; ++i) {
106 base::DictionaryValue* decoded_evt = nullptr;
107 ASSERT_TRUE(reader.legacy_events()->GetDictionary(i, &decoded_evt));
108 base::DictionaryValue expected_value;
109 expected_value.SetString("ph", "X");
110 expected_value.SetString("name", "copied_str_name");
111 expected_value.SetString("cat", kCatNames[i % arraysize(kCatNames)]);
112 expected_value.SetInteger("ts", static_cast<int>(0xff000000 + i));
113 ASSERT_PRED_FORMAT2(ValueEquals, expected_value, *decoded_evt);
114 }
115 }
116
117 // Test the decoding events that are fragmented across multiple chunks.
118 TEST(TraceBufferReaderTest, FragmentedEvents) {
119 golden_protos::Event evt[3];
120 for (size_t i = 0; i < arraysize(evt); ++i) {
121 evt[i].set_type(golden_protos::Event::COMPLETE);
122 evt[i].set_name_str("copied_str_name");
123 evt[i].set_category_id(InternString("interned_category_name"));
124 evt[i].set_timestamp(i);
125 }
126
127 // The 2nd event (evt[1]) will be split into three fragments and distributed
128 // over all three chunks.
129 const size_t evt1_size = evt[1].ByteSize();
130 DCHECK_GT(evt1_size, 8u);
131 std::unique_ptr<uint8_t[]> serialized_evt1(new uint8_t[evt1_size]);
132 evt[1].SerializeToArray(serialized_evt1.get(), evt1_size);
133
134 // Create three chunks and split the three events as follows:
135 // chunk[0]: evt[0] (full), evt[1] (fragment 1/3)
136 // chunk[1]: evt[1] (fragment 2/3)
137 // chunk[2]: evt[1] (fragment 3/3), evt[2] (full)
138
139 golden_protos::EventsChunk chunk[3];
140 for (size_t i = 0; i < arraysize(chunk); ++i) {
141 chunk[i].set_writer_id(42);
142 chunk[i].set_seq_id(i);
143 }
144
145 chunk[0].set_first_event_continues_from_prev_chunk(false);
146 chunk[0].set_last_event_continues_on_next_chunk(true);
147 chunk[0].add_events(evt[0].SerializeAsString());
148 chunk[0].add_events(&serialized_evt1[0], 4);
149
150 chunk[1].set_first_event_continues_from_prev_chunk(true);
151 chunk[1].set_last_event_continues_on_next_chunk(true);
152 chunk[1].add_events(&serialized_evt1[4], 4);
153
154 chunk[2].set_first_event_continues_from_prev_chunk(true);
155 chunk[2].add_events(&serialized_evt1[8], evt1_size - 8);
156 chunk[2].add_events(evt[2].SerializeAsString());
157
158 TraceBufferReader reader(TraceBufferReader::kBuildLegacyJSONEvents |
159 TraceBufferReader::kBuildInternedStringsTable);
160 for (size_t i = 0; i < arraysize(chunk); ++i)
161 ParseChunk(&reader, chunk[i].SerializeAsString());
162
163 ASSERT_EQ(arraysize(evt), reader.legacy_events()->GetSize());
164 for (size_t i = 0; i < arraysize(evt); ++i) {
165 base::DictionaryValue* decoded_evt = nullptr;
166 ASSERT_TRUE(reader.legacy_events()->GetDictionary(i, &decoded_evt));
167
168 base::DictionaryValue expected_value;
169 expected_value.SetString("ph", "X");
170 expected_value.SetString("name", "copied_str_name");
171 expected_value.SetString("cat", "interned_category_name");
172 expected_value.SetInteger("ts", static_cast<int>(i));
173 ASSERT_PRED_FORMAT2(ValueEquals, expected_value, *decoded_evt);
174 }
175 }
176
177 // Test that the fragment reconstruction logic discards fragments if one of
178 // the chunks is missing.
179 TEST(TraceBufferReaderTest, FragmentedEventsWithMissingChunks) {
180 golden_protos::Event evt[2];
181 for (size_t i = 0; i < arraysize(evt); ++i) {
182 evt[i].set_type(golden_protos::Event::METADATA);
183 evt[i].set_timestamp(i);
184 }
185
186 golden_protos::EventsChunk chunk[2];
187 for (size_t i = 0; i < arraysize(chunk); ++i) {
188 chunk[i].set_writer_id(42);
189 chunk[i].set_seq_id(1 + i);
190 }
191
192 // The 2nd event (evt[1]) will be split into two fragments.
193 const size_t evt1_size = evt[1].ByteSize();
194 DCHECK_GT(evt1_size, 2u);
195 std::unique_ptr<uint8_t[]> serialized_evt1(new uint8_t[evt1_size]);
196 evt[1].SerializeToArray(serialized_evt1.get(), evt1_size);
197
198 chunk[0].set_first_event_continues_from_prev_chunk(true);
199 chunk[0].set_last_event_continues_on_next_chunk(true);
200 chunk[0].add_events("should be discarded because seq id 0 is not seen.");
201 chunk[0].add_events(evt[0].SerializeAsString());
202 chunk[0].add_events(&serialized_evt1[0], 2);
203
204 chunk[1].set_first_event_continues_from_prev_chunk(true);
205 chunk[1].set_last_event_continues_on_next_chunk(true);
206 chunk[1].add_events(&serialized_evt1[0] + 2, evt1_size - 2);
207 chunk[1].add_events("should be discarded because seq id 2 is not seen.");
208
209 TraceBufferReader reader(TraceBufferReader::kBuildLegacyJSONEvents);
210 ParseChunk(&reader, chunk[0].SerializeAsString());
211 ParseChunk(&reader, chunk[1].SerializeAsString());
212
213 ASSERT_EQ(arraysize(evt), reader.legacy_events()->GetSize());
214 for (size_t i = 0; i < arraysize(evt); ++i) {
215 base::DictionaryValue* decoded_evt = nullptr;
216 ASSERT_TRUE(reader.legacy_events()->GetDictionary(i, &decoded_evt));
217
218 base::DictionaryValue expected_value;
219 expected_value.SetString("ph", "M");
220 expected_value.SetInteger("ts", static_cast<int>(i));
221 ASSERT_PRED_FORMAT2(ValueEquals, expected_value, *decoded_evt);
222 }
223 }
224
225 } // namespace
226 } // namespace v2
227 } // namespace tracing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698