1 // Copyright 2014 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.
5 #include "net/base/trace_net_log_observer.h"
10 #include "base/debug/trace_event.h"
11 #include "base/debug/trace_event_impl.h"
12 #include "base/json/json_reader.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/run_loop.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/values.h"
20 #include "net/base/capturing_net_log.h"
21 #include "net/base/net_log.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::debug::TraceLog;
30 struct TraceEntryInfo {
35 std::string source_type;
38 TraceEntryInfo GetTraceEntryInfoFromValue(const base::DictionaryValue& value) {
40 EXPECT_TRUE(value.GetString("cat", &info.category));
41 EXPECT_TRUE(value.GetString("id", &info.id));
42 EXPECT_TRUE(value.GetString("ph", &info.phase));
43 EXPECT_TRUE(value.GetString("name", &info.name));
44 EXPECT_TRUE(value.GetString("args.source_type", &info.source_type));
49 class TraceNetLogObserverTest : public testing::Test {
51 TraceNetLogObserverTest() {
52 TraceLog* tracelog = TraceLog::GetInstance();
54 DCHECK(!tracelog->IsEnabled());
55 trace_buffer_.SetOutputCallback(json_output_.GetCallback());
56 trace_net_log_observer_.reset(new TraceNetLogObserver());
57 trace_events_.reset(new base::ListValue());
60 virtual ~TraceNetLogObserverTest() {
61 DCHECK(!TraceLog::GetInstance()->IsEnabled());
64 void OnTraceDataCollected(
65 base::RunLoop* run_loop,
66 const scoped_refptr<base::RefCountedString>& events_str,
67 bool has_more_events) {
68 DCHECK(trace_events_->empty());
69 trace_buffer_.Start();
70 trace_buffer_.AddFragment(events_str->data());
71 trace_buffer_.Finish();
73 scoped_ptr<base::Value> trace_value;
74 trace_value.reset(base::JSONReader::Read(
75 json_output_.json_output,
76 base::JSON_PARSE_RFC | base::JSON_DETACHABLE_CHILDREN));
78 ASSERT_TRUE(trace_value) << json_output_.json_output;
79 base::ListValue* trace_events = NULL;
80 ASSERT_TRUE(trace_value->GetAsList(&trace_events));
82 trace_events_ = FilterNetLogTraceEvents(*trace_events);
88 static void EnableTraceLog() {
89 TraceLog::GetInstance()->SetEnabled(base::debug::CategoryFilter("netlog"),
90 TraceLog::RECORDING_MODE,
91 base::debug::TraceOptions());
94 void EndTraceAndFlush() {
95 base::RunLoop run_loop;
96 TraceLog::GetInstance()->SetDisabled();
97 TraceLog::GetInstance()->Flush(
98 base::Bind(&TraceNetLogObserverTest::OnTraceDataCollected,
99 base::Unretained(this),
100 base::Unretained(&run_loop)));
104 void set_trace_net_log_observer(TraceNetLogObserver* trace_net_log_observer) {
105 trace_net_log_observer_.reset(trace_net_log_observer);
108 static scoped_ptr<base::ListValue> FilterNetLogTraceEvents(
109 const base::ListValue& trace_events) {
110 scoped_ptr<base::ListValue> filtered_trace_events(new base::ListValue());
111 for (size_t i = 0; i < trace_events.GetSize(); i++) {
112 const base::DictionaryValue* dict = NULL;
113 if (!trace_events.GetDictionary(i, &dict)) {
114 ADD_FAILURE() << "Unexpected non-dictionary event in trace_events";
117 std::string category;
118 if (!dict->GetString("cat", &category)) {
120 << "Unexpected item without a category field in trace_events";
123 if (category != "netlog")
125 filtered_trace_events->Append(dict->DeepCopy());
127 return filtered_trace_events.Pass();
130 base::ListValue* trace_events() const {
131 return trace_events_.get();
134 CapturingNetLog* net_log() {
138 TraceNetLogObserver* trace_net_log_observer() const {
139 return trace_net_log_observer_.get();
143 scoped_ptr<base::ListValue> trace_events_;
144 base::debug::TraceResultBuffer trace_buffer_;
145 base::debug::TraceResultBuffer::SimpleOutput json_output_;
146 CapturingNetLog net_log_;
147 scoped_ptr<TraceNetLogObserver> trace_net_log_observer_;
150 TEST_F(TraceNetLogObserverTest, TracingNotEnabled) {
151 trace_net_log_observer()->WatchForTraceStart(net_log());
152 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
155 trace_net_log_observer()->StopWatchForTraceStart();
157 EXPECT_EQ(0u, trace_events()->GetSize());
160 TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
161 CapturingNetLog::CapturedEntryList entries;
162 net_log()->GetEntries(&entries);
163 EXPECT_TRUE(entries.empty());
165 trace_net_log_observer()->WatchForTraceStart(net_log());
167 BoundNetLog bound_net_log =
168 BoundNetLog::Make(net_log(), net::NetLog::SOURCE_NONE);
169 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
170 bound_net_log.BeginEvent(NetLog::TYPE_URL_REQUEST_START_JOB);
171 bound_net_log.EndEvent(NetLog::TYPE_REQUEST_ALIVE);
173 net_log()->GetEntries(&entries);
174 EXPECT_EQ(3u, entries.size());
176 trace_net_log_observer()->StopWatchForTraceStart();
177 EXPECT_EQ(3u, trace_events()->GetSize());
178 const base::DictionaryValue* item1 = NULL;
179 ASSERT_TRUE(trace_events()->GetDictionary(0, &item1));
180 const base::DictionaryValue* item2 = NULL;
181 ASSERT_TRUE(trace_events()->GetDictionary(1, &item2));
182 const base::DictionaryValue* item3 = NULL;
183 ASSERT_TRUE(trace_events()->GetDictionary(2, &item3));
185 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
186 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
187 TraceEntryInfo actual_item3 = GetTraceEntryInfoFromValue(*item3);
188 EXPECT_EQ("netlog", actual_item1.category);
189 EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
190 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
192 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
194 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
195 actual_item1.source_type);
197 EXPECT_EQ("netlog", actual_item2.category);
198 EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
199 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN),
201 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_URL_REQUEST_START_JOB),
203 EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
204 actual_item2.source_type);
206 EXPECT_EQ("netlog", actual_item3.category);
207 EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item3.id);
208 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_END),
210 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_REQUEST_ALIVE),
212 EXPECT_EQ(NetLog::SourceTypeToString(entries[2].source.type),
213 actual_item3.source_type);
216 TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
217 trace_net_log_observer()->WatchForTraceStart(net_log());
219 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
220 TraceLog::GetInstance()->SetDisabled();
221 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
223 net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
226 trace_net_log_observer()->StopWatchForTraceStart();
228 CapturingNetLog::CapturedEntryList entries;
229 net_log()->GetEntries(&entries);
230 EXPECT_EQ(3u, entries.size());
231 EXPECT_EQ(2u, trace_events()->GetSize());
232 const base::DictionaryValue* item1 = NULL;
233 ASSERT_TRUE(trace_events()->GetDictionary(0, &item1));
234 const base::DictionaryValue* item2 = NULL;
235 ASSERT_TRUE(trace_events()->GetDictionary(1, &item2));
237 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
238 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
239 EXPECT_EQ("netlog", actual_item1.category);
240 EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
241 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
243 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
245 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
246 actual_item1.source_type);
248 EXPECT_EQ("netlog", actual_item2.category);
249 EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item2.id);
250 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
252 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_URL_REQUEST_START_JOB),
254 EXPECT_EQ(NetLog::SourceTypeToString(entries[2].source.type),
255 actual_item2.source_type);
258 TEST_F(TraceNetLogObserverTest, DestroyObserverWhileTracing) {
259 trace_net_log_observer()->WatchForTraceStart(net_log());
261 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
262 trace_net_log_observer()->StopWatchForTraceStart();
263 set_trace_net_log_observer(NULL);
264 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
268 CapturingNetLog::CapturedEntryList entries;
269 net_log()->GetEntries(&entries);
270 EXPECT_EQ(2u, entries.size());
271 EXPECT_EQ(1u, trace_events()->GetSize());
273 const base::DictionaryValue* item1 = NULL;
274 ASSERT_TRUE(trace_events()->GetDictionary(0, &item1));
276 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
277 EXPECT_EQ("netlog", actual_item1.category);
278 EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
279 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
281 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
283 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
284 actual_item1.source_type);
287 TEST_F(TraceNetLogObserverTest, DestroyObserverWhileNotTracing) {
288 trace_net_log_observer()->WatchForTraceStart(net_log());
289 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
290 trace_net_log_observer()->StopWatchForTraceStart();
291 set_trace_net_log_observer(NULL);
292 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
293 net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
297 CapturingNetLog::CapturedEntryList entries;
298 net_log()->GetEntries(&entries);
299 EXPECT_EQ(3u, entries.size());
300 EXPECT_EQ(0u, trace_events()->GetSize());
303 TEST_F(TraceNetLogObserverTest, CreateObserverAfterTracingStarts) {
304 set_trace_net_log_observer(NULL);
306 set_trace_net_log_observer(new TraceNetLogObserver());
307 trace_net_log_observer()->WatchForTraceStart(net_log());
308 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
309 trace_net_log_observer()->StopWatchForTraceStart();
310 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
311 net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
315 CapturingNetLog::CapturedEntryList entries;
316 net_log()->GetEntries(&entries);
317 EXPECT_EQ(3u, entries.size());
318 EXPECT_EQ(0u, trace_events()->GetSize());
321 TEST_F(TraceNetLogObserverTest, EventsWithAndWithoutParameters) {
322 trace_net_log_observer()->WatchForTraceStart(net_log());
324 NetLog::ParametersCallback net_log_callback;
325 std::string param = "bar";
326 net_log_callback = NetLog::StringCallback("foo", ¶m);
328 net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED, net_log_callback);
329 net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
332 trace_net_log_observer()->StopWatchForTraceStart();
334 CapturingNetLog::CapturedEntryList entries;
335 net_log()->GetEntries(&entries);
336 EXPECT_EQ(2u, entries.size());
337 EXPECT_EQ(2u, trace_events()->GetSize());
338 const base::DictionaryValue* item1 = NULL;
339 ASSERT_TRUE(trace_events()->GetDictionary(0, &item1));
340 const base::DictionaryValue* item2 = NULL;
341 ASSERT_TRUE(trace_events()->GetDictionary(1, &item2));
343 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
344 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
345 EXPECT_EQ("netlog", actual_item1.category);
346 EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
347 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
349 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
351 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
352 actual_item1.source_type);
354 EXPECT_EQ("netlog", actual_item2.category);
355 EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
356 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
358 EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_REQUEST_ALIVE),
360 EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
361 actual_item2.source_type);
363 std::string item1_params;
364 std::string item2_params;
365 EXPECT_TRUE(item1->GetString("args.params.foo", &item1_params));
366 EXPECT_EQ("bar", item1_params);
368 EXPECT_TRUE(item2->GetString("args.params", &item2_params));
369 EXPECT_TRUE(item2_params.empty());