1 // Copyright 2014 The Chromium Authors
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 "net/log/trace_net_log_observer.h"
6
7 #include <memory>
8 #include <string>
9 #include <vector>
10
11 #include "base/check.h"
12 #include "base/functional/bind.h"
13 #include "base/json/json_reader.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/run_loop.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/test/task_environment.h"
20 #include "base/trace_event/trace_buffer.h"
21 #include "base/trace_event/trace_event.h"
22 #include "base/trace_event/trace_event_impl.h"
23 #include "base/values.h"
24 #include "net/log/net_log.h"
25 #include "net/log/net_log_event_type.h"
26 #include "net/log/net_log_source_type.h"
27 #include "net/log/net_log_with_source.h"
28 #include "net/log/test_net_log.h"
29 #include "net/test/test_with_task_environment.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 using base::trace_event::TraceLog;
33
34 namespace net {
35
36 namespace {
37
38 // TraceLog category for NetLog events.
39 const char kNetLogTracingCategory[] = "netlog";
40
41 struct TraceEntryInfo {
42 std::string category;
43 // The netlog source id formatted as a hexadecimal string.
44 std::string id;
45 std::string phase;
46 std::string name;
47 std::string source_type;
48 };
49
GetTraceEntryInfoFromValue(const base::Value::Dict & value)50 TraceEntryInfo GetTraceEntryInfoFromValue(const base::Value::Dict& value) {
51 TraceEntryInfo info;
52 if (const std::string* cat = value.FindString("cat")) {
53 info.category = *cat;
54 } else {
55 ADD_FAILURE() << "Missing 'cat'";
56 }
57 if (const std::string* id = value.FindString("id")) {
58 info.id = *id;
59 } else {
60 ADD_FAILURE() << "Missing 'id'";
61 }
62 if (const std::string* ph = value.FindString("ph")) {
63 info.phase = *ph;
64 } else {
65 ADD_FAILURE() << "Missing 'ph'";
66 }
67 if (const std::string* name = value.FindString("name")) {
68 info.name = *name;
69 } else {
70 ADD_FAILURE() << "Missing 'name'";
71 }
72 if (const std::string* type =
73 value.FindStringByDottedPath("args.source_type")) {
74 info.source_type = *type;
75 } else {
76 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_END), info.phase);
77 }
78
79 return info;
80 }
81
EnableTraceLog(std::string_view category)82 void EnableTraceLog(std::string_view category) {
83 TraceLog::GetInstance()->SetEnabled(
84 base::trace_event::TraceConfig(category, ""), TraceLog::RECORDING_MODE);
85 // AsyncEnabledStateObserver will receive enabled notification one message
86 // loop iteration later.
87 base::RunLoop().RunUntilIdle();
88 }
89
DisableTraceLog()90 void DisableTraceLog() {
91 TraceLog::GetInstance()->SetDisabled();
92 // AsyncEnabledStateObserver will receive disabled notification one message
93 // loop iteration later.
94 base::RunLoop().RunUntilIdle();
95 }
96
EnableTraceLogWithNetLog()97 void EnableTraceLogWithNetLog() {
98 EnableTraceLog(kNetLogTracingCategory);
99 }
100
EnableTraceLogWithoutNetLog()101 void EnableTraceLogWithoutNetLog() {
102 std::string disabled_netlog_category =
103 std::string("-") + kNetLogTracingCategory;
104 EnableTraceLog(disabled_netlog_category);
105 }
106
107 class TraceNetLogObserverTest : public TestWithTaskEnvironment {
108 public:
TraceNetLogObserverTest()109 TraceNetLogObserverTest() {
110 TraceLog* tracelog = TraceLog::GetInstance();
111 DCHECK(tracelog);
112 DCHECK(!tracelog->IsEnabled());
113 trace_buffer_.SetOutputCallback(json_output_.GetCallback());
114 trace_net_log_observer_ = std::make_unique<TraceNetLogObserver>();
115 }
116
~TraceNetLogObserverTest()117 ~TraceNetLogObserverTest() override {
118 DCHECK(!TraceLog::GetInstance()->IsEnabled());
119 }
120
OnTraceDataCollected(base::RunLoop * run_loop,const scoped_refptr<base::RefCountedString> & events_str,bool has_more_events)121 void OnTraceDataCollected(
122 base::RunLoop* run_loop,
123 const scoped_refptr<base::RefCountedString>& events_str,
124 bool has_more_events) {
125 DCHECK(trace_events_.empty());
126 trace_buffer_.Start();
127 trace_buffer_.AddFragment(events_str->data());
128 trace_buffer_.Finish();
129
130 std::optional<base::Value> trace_value;
131 trace_value =
132 base::JSONReader::Read(json_output_.json_output, base::JSON_PARSE_RFC);
133
134 ASSERT_TRUE(trace_value) << json_output_.json_output;
135 ASSERT_TRUE(trace_value->is_list());
136
137 trace_events_ = FilterNetLogTraceEvents(trace_value->GetList());
138
139 if (!has_more_events)
140 run_loop->Quit();
141 }
142
EndTraceAndFlush()143 void EndTraceAndFlush() {
144 DisableTraceLog();
145 base::RunLoop run_loop;
146 TraceLog::GetInstance()->Flush(base::BindRepeating(
147 &TraceNetLogObserverTest::OnTraceDataCollected, base::Unretained(this),
148 base::Unretained(&run_loop)));
149 run_loop.Run();
150 }
151
set_trace_net_log_observer(std::unique_ptr<TraceNetLogObserver> trace_net_log_observer)152 void set_trace_net_log_observer(
153 std::unique_ptr<TraceNetLogObserver> trace_net_log_observer) {
154 trace_net_log_observer_ = std::move(trace_net_log_observer);
155 }
156
FilterNetLogTraceEvents(const base::Value::List & trace_events)157 static base::Value::List FilterNetLogTraceEvents(
158 const base::Value::List& trace_events) {
159 base::Value::List filtered_trace_events;
160
161 for (const auto& event : trace_events) {
162 if (!event.is_dict()) {
163 ADD_FAILURE() << "Unexpected non-dictionary event in trace_events";
164 continue;
165 }
166 const std::string* category =
167 event.GetDict().FindStringByDottedPath("cat");
168 if (!category) {
169 ADD_FAILURE()
170 << "Unexpected item without a category field in trace_events";
171 continue;
172 }
173 if (*category != kNetLogTracingCategory)
174 continue;
175 filtered_trace_events.Append(event.Clone());
176 }
177 return filtered_trace_events;
178 }
179
trace_events() const180 const base::Value::List& trace_events() const { return trace_events_; }
181
clear_trace_events()182 void clear_trace_events() {
183 trace_events_.clear();
184 json_output_.json_output.clear();
185 }
186
trace_events_size() const187 size_t trace_events_size() const { return trace_events_.size(); }
188
net_log_observer()189 RecordingNetLogObserver* net_log_observer() { return &net_log_observer_; }
190
trace_net_log_observer() const191 TraceNetLogObserver* trace_net_log_observer() const {
192 return trace_net_log_observer_.get();
193 }
194
195 private:
196 base::Value::List trace_events_;
197 base::trace_event::TraceResultBuffer trace_buffer_;
198 base::trace_event::TraceResultBuffer::SimpleOutput json_output_;
199 RecordingNetLogObserver net_log_observer_;
200 std::unique_ptr<TraceNetLogObserver> trace_net_log_observer_;
201 };
202
TEST_F(TraceNetLogObserverTest,TracingNotEnabled)203 TEST_F(TraceNetLogObserverTest, TracingNotEnabled) {
204 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
205 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
206
207 EndTraceAndFlush();
208 trace_net_log_observer()->StopWatchForTraceStart();
209
210 EXPECT_EQ(0u, trace_events_size());
211 }
212
213 // This test will result in a deadlock if EnabledStateObserver instead
214 // of AsyncEnabledStateObserver is used. Regression test for crbug.com/760817.
215 // Perfetto SDK doesn't have this problem, so the test is not necessary.
216 #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
TEST_F(TraceNetLogObserverTest,TracingDisabledDuringOnAddEntry)217 TEST_F(TraceNetLogObserverTest, TracingDisabledDuringOnAddEntry) {
218 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
219 TraceLog* trace_log = TraceLog::GetInstance();
220 trace_log->SetTraceBufferForTesting(base::WrapUnique(
221 base::trace_event::TraceBuffer::CreateTraceBufferVectorOfSize(1)));
222 EnableTraceLogWithNetLog();
223 // TraceLog will disable itself when an event makes the TraceBuffer full.
224 while (!trace_log->BufferIsFull()) {
225 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
226 }
227
228 base::RunLoop().RunUntilIdle();
229 ASSERT_FALSE(trace_log->IsEnabled());
230 ASSERT_FALSE(trace_net_log_observer()->net_log());
231 trace_net_log_observer()->StopWatchForTraceStart();
232 // Flush now so that TraceLog's buffer is empty in the next test.
233 EndTraceAndFlush();
234 }
235 #endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
236
TEST_F(TraceNetLogObserverTest,TraceEventCaptured)237 TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
238 auto entries = net_log_observer()->GetEntries();
239 EXPECT_TRUE(entries.empty());
240
241 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
242 EnableTraceLogWithNetLog();
243 NetLogWithSource net_log_with_source =
244 NetLogWithSource::Make(NetLog::Get(), net::NetLogSourceType::NONE);
245 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
246 net_log_with_source.BeginEvent(NetLogEventType::URL_REQUEST_START_JOB);
247 net_log_with_source.EndEvent(NetLogEventType::URL_REQUEST_START_JOB);
248
249 entries = net_log_observer()->GetEntries();
250 EXPECT_EQ(3u, entries.size());
251 EndTraceAndFlush();
252 trace_net_log_observer()->StopWatchForTraceStart();
253
254 EXPECT_EQ(3u, trace_events_size());
255
256 const base::Value* item1 = &trace_events()[0];
257 ASSERT_TRUE(item1->is_dict());
258 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(item1->GetDict());
259 EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
260 EXPECT_EQ(base::StringPrintf("0x%x", entries[0].source.id), actual_item1.id);
261 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
262 actual_item1.phase);
263 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::CANCELLED),
264 actual_item1.name);
265 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
266 actual_item1.source_type);
267
268 const base::Value* item2 = &trace_events()[1];
269 ASSERT_TRUE(item2->is_dict());
270 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(item2->GetDict());
271 EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
272 EXPECT_EQ(base::StringPrintf("0x%x", entries[1].source.id), actual_item2.id);
273 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN),
274 actual_item2.phase);
275 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::URL_REQUEST_START_JOB),
276 actual_item2.name);
277 EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
278 actual_item2.source_type);
279
280 const base::Value* item3 = &trace_events()[2];
281 ASSERT_TRUE(item3->is_dict());
282 TraceEntryInfo actual_item3 = GetTraceEntryInfoFromValue(item3->GetDict());
283 EXPECT_EQ(kNetLogTracingCategory, actual_item3.category);
284 EXPECT_EQ(base::StringPrintf("0x%x", entries[2].source.id), actual_item3.id);
285 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_END),
286 actual_item3.phase);
287 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::URL_REQUEST_START_JOB),
288 actual_item3.name);
289 }
290
TEST_F(TraceNetLogObserverTest,EnableAndDisableTracing)291 TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
292 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
293 EnableTraceLogWithNetLog();
294 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
295 EndTraceAndFlush();
296
297 auto entries = net_log_observer()->GetEntries();
298 EXPECT_EQ(1u, entries.size());
299 EXPECT_EQ(1u, trace_events_size());
300 const base::Value* item1 = &trace_events()[0];
301 ASSERT_TRUE(item1->is_dict());
302 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(item1->GetDict());
303 EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
304 EXPECT_EQ(base::StringPrintf("0x%x", entries[0].source.id), actual_item1.id);
305 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
306 actual_item1.phase);
307 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::CANCELLED),
308 actual_item1.name);
309 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
310 actual_item1.source_type);
311
312 clear_trace_events();
313
314 // This entry is emitted while tracing is off.
315 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
316
317 EnableTraceLogWithNetLog();
318 NetLog::Get()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
319 EndTraceAndFlush();
320 trace_net_log_observer()->StopWatchForTraceStart();
321
322 entries = net_log_observer()->GetEntries();
323 EXPECT_EQ(3u, entries.size());
324 EXPECT_EQ(1u, trace_events_size());
325 const base::Value* item2 = &trace_events()[0];
326 ASSERT_TRUE(item2->is_dict());
327 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(item2->GetDict());
328 EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
329 EXPECT_EQ(base::StringPrintf("0x%x", entries[2].source.id), actual_item2.id);
330 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
331 actual_item2.phase);
332 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::URL_REQUEST_START_JOB),
333 actual_item2.name);
334 EXPECT_EQ(NetLog::SourceTypeToString(entries[2].source.type),
335 actual_item2.source_type);
336 }
337
TEST_F(TraceNetLogObserverTest,DestroyObserverWhileTracing)338 TEST_F(TraceNetLogObserverTest, DestroyObserverWhileTracing) {
339 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
340 EnableTraceLogWithNetLog();
341 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
342 trace_net_log_observer()->StopWatchForTraceStart();
343 set_trace_net_log_observer(nullptr);
344 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
345
346 EndTraceAndFlush();
347
348 auto entries = net_log_observer()->GetEntries();
349 EXPECT_EQ(2u, entries.size());
350 EXPECT_EQ(1u, trace_events_size());
351
352 const base::Value* item1 = &trace_events()[0];
353 ASSERT_TRUE(item1->is_dict());
354
355 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(item1->GetDict());
356 EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
357 EXPECT_EQ(base::StringPrintf("0x%x", entries[0].source.id), actual_item1.id);
358 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
359 actual_item1.phase);
360 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::CANCELLED),
361 actual_item1.name);
362 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
363 actual_item1.source_type);
364 }
365
TEST_F(TraceNetLogObserverTest,DestroyObserverWhileNotTracing)366 TEST_F(TraceNetLogObserverTest, DestroyObserverWhileNotTracing) {
367 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
368 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
369 trace_net_log_observer()->StopWatchForTraceStart();
370 set_trace_net_log_observer(nullptr);
371 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
372 NetLog::Get()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
373
374 EndTraceAndFlush();
375
376 auto entries = net_log_observer()->GetEntries();
377 EXPECT_EQ(3u, entries.size());
378 EXPECT_EQ(0u, trace_events_size());
379 }
380
TEST_F(TraceNetLogObserverTest,CreateObserverAfterTracingStarts)381 TEST_F(TraceNetLogObserverTest, CreateObserverAfterTracingStarts) {
382 set_trace_net_log_observer(nullptr);
383 EnableTraceLogWithNetLog();
384 set_trace_net_log_observer(std::make_unique<TraceNetLogObserver>());
385 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
386 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
387 trace_net_log_observer()->StopWatchForTraceStart();
388 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
389 NetLog::Get()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
390
391 EndTraceAndFlush();
392
393 auto entries = net_log_observer()->GetEntries();
394 EXPECT_EQ(3u, entries.size());
395 EXPECT_EQ(1u, trace_events_size());
396 }
397
TEST_F(TraceNetLogObserverTest,CreateObserverAfterTracingStartsDisabledCategory)398 TEST_F(TraceNetLogObserverTest,
399 CreateObserverAfterTracingStartsDisabledCategory) {
400 set_trace_net_log_observer(nullptr);
401
402 EnableTraceLogWithoutNetLog();
403
404 set_trace_net_log_observer(std::make_unique<TraceNetLogObserver>());
405 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
406 NetLog::Get()->AddGlobalEntry(NetLogEventType::CANCELLED);
407 trace_net_log_observer()->StopWatchForTraceStart();
408 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
409 NetLog::Get()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
410
411 EndTraceAndFlush();
412
413 auto entries = net_log_observer()->GetEntries();
414 EXPECT_EQ(3u, entries.size());
415 EXPECT_EQ(0u, trace_events_size());
416 }
417
TEST_F(TraceNetLogObserverTest,EventsWithAndWithoutParameters)418 TEST_F(TraceNetLogObserverTest, EventsWithAndWithoutParameters) {
419 trace_net_log_observer()->WatchForTraceStart(NetLog::Get());
420 EnableTraceLogWithNetLog();
421
422 NetLog::Get()->AddGlobalEntryWithStringParams(NetLogEventType::CANCELLED,
423 "foo", "bar");
424 NetLog::Get()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
425
426 EndTraceAndFlush();
427 trace_net_log_observer()->StopWatchForTraceStart();
428
429 auto entries = net_log_observer()->GetEntries();
430 EXPECT_EQ(2u, entries.size());
431 EXPECT_EQ(2u, trace_events_size());
432 const base::Value* item1 = &trace_events()[0];
433 ASSERT_TRUE(item1->is_dict());
434 const base::Value* item2 = &trace_events()[1];
435 ASSERT_TRUE(item2->is_dict());
436
437 TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(item1->GetDict());
438 TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(item2->GetDict());
439
440 EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
441 EXPECT_EQ(base::StringPrintf("0x%x", entries[0].source.id), actual_item1.id);
442 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
443 actual_item1.phase);
444 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::CANCELLED),
445 actual_item1.name);
446 EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
447 actual_item1.source_type);
448
449 EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
450 EXPECT_EQ(base::StringPrintf("0x%x", entries[1].source.id), actual_item2.id);
451 EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
452 actual_item2.phase);
453 EXPECT_EQ(NetLogEventTypeToString(NetLogEventType::REQUEST_ALIVE),
454 actual_item2.name);
455 EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
456 actual_item2.source_type);
457
458 const std::string* item1_params =
459 item1->GetDict().FindStringByDottedPath("args.params.foo");
460 ASSERT_TRUE(item1_params);
461 EXPECT_EQ("bar", *item1_params);
462
463 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
464 // Perfetto tracing backend skips empty args.
465 const base::Value::Dict* item2_args =
466 item2->GetDict().FindDictByDottedPath("args");
467 EXPECT_FALSE(item2_args->contains("params"));
468 #else
469 const base::Value::Dict* item2_params =
470 item2->GetDict().FindDictByDottedPath("args.params");
471 ASSERT_TRUE(item2_params);
472 EXPECT_TRUE(item2_params->empty());
473 #endif
474 }
475
TEST(TraceNetLogObserverCategoryTest,DisabledCategory)476 TEST(TraceNetLogObserverCategoryTest, DisabledCategory) {
477 base::test::TaskEnvironment task_environment;
478 TraceNetLogObserver observer;
479 observer.WatchForTraceStart(NetLog::Get());
480
481 EXPECT_FALSE(NetLog::Get()->IsCapturing());
482
483 EnableTraceLogWithoutNetLog();
484
485 EXPECT_FALSE(NetLog::Get()->IsCapturing());
486 observer.StopWatchForTraceStart();
487 EXPECT_FALSE(NetLog::Get()->IsCapturing());
488
489 DisableTraceLog();
490 }
491
TEST(TraceNetLogObserverCategoryTest,EnabledCategory)492 TEST(TraceNetLogObserverCategoryTest, EnabledCategory) {
493 base::test::TaskEnvironment task_environment;
494 TraceNetLogObserver observer;
495 observer.WatchForTraceStart(NetLog::Get());
496
497 EXPECT_FALSE(NetLog::Get()->IsCapturing());
498
499 EnableTraceLogWithNetLog();
500
501 EXPECT_TRUE(NetLog::Get()->IsCapturing());
502 observer.StopWatchForTraceStart();
503 EXPECT_FALSE(NetLog::Get()->IsCapturing());
504
505 DisableTraceLog();
506 }
507
508 } // namespace
509
510 } // namespace net
511