• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/log/file_net_log_observer.h"
11 
12 #include <string>
13 #include <vector>
14 
15 #include "base/files/file.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_file.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/functional/bind.h"
21 #include "base/functional/callback.h"
22 #include "base/json/json_reader.h"
23 #include "base/json/json_writer.h"
24 #include "base/memory/raw_ptr.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/task/thread_pool/thread_pool_instance.h"
29 #include "base/test/gmock_expected_support.h"
30 #include "base/threading/thread.h"
31 #include "base/types/expected.h"
32 #include "base/types/expected_macros.h"
33 #include "base/values.h"
34 #include "build/build_config.h"
35 #include "net/base/test_completion_callback.h"
36 #include "net/log/net_log.h"
37 #include "net/log/net_log_entry.h"
38 #include "net/log/net_log_event_type.h"
39 #include "net/log/net_log_source.h"
40 #include "net/log/net_log_source_type.h"
41 #include "net/log/net_log_util.h"
42 #include "net/log/net_log_values.h"
43 #include "net/test/test_with_task_environment.h"
44 #include "net/url_request/url_request.h"
45 #include "net/url_request/url_request_context.h"
46 #include "net/url_request/url_request_test_util.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48 
49 namespace net {
50 
51 namespace {
52 
53 // Indicates the number of event files used in test cases.
54 const int kTotalNumFiles = 10;
55 
56 // Used to set the total file size maximum in test cases where the file size
57 // doesn't matter.
58 const int kLargeFileSize = 100000000;
59 
60 // Used to set the size of events to be sent to the observer in test cases
61 // where event size doesn't matter.
62 const size_t kDummyEventSize = 150;
63 
64 // Adds |num_entries| to |logger|. The "inverse" of this is VerifyEventsInLog().
AddEntries(FileNetLogObserver * logger,int num_entries,size_t entry_size)65 void AddEntries(FileNetLogObserver* logger,
66                 int num_entries,
67                 size_t entry_size) {
68   // Get base size of event.
69   const int kDummyId = 0;
70   NetLogSource source(NetLogSourceType::HTTP2_SESSION, kDummyId);
71   NetLogEntry base_entry(NetLogEventType::PAC_JAVASCRIPT_ERROR, source,
72                          NetLogEventPhase::BEGIN, base::TimeTicks::Now(),
73                          NetLogParamsWithString("message", ""));
74   base::Value::Dict value = base_entry.ToDict();
75   std::string json;
76   base::JSONWriter::Write(value, &json);
77   size_t base_entry_size = json.size();
78 
79   // The maximum value of base::TimeTicks::Now() will be the maximum value of
80   // int64_t, and if the maximum number of digits are included, the
81   // |base_entry_size| could be up to 136 characters. Check that the event
82   // format does not include additional padding.
83   DCHECK_LE(base_entry_size, 136u);
84 
85   // |entry_size| should be at least as big as the largest possible base
86   // entry.
87   EXPECT_GE(entry_size, 136u);
88 
89   // |entry_size| cannot be smaller than the minimum event size.
90   EXPECT_GE(entry_size, base_entry_size);
91 
92   for (int i = 0; i < num_entries; i++) {
93     source = NetLogSource(NetLogSourceType::HTTP2_SESSION, i);
94     std::string id = base::NumberToString(i);
95 
96     // String size accounts for the number of digits in id so that all events
97     // are the same size.
98     std::string message =
99         std::string(entry_size - base_entry_size - id.size() + 1, 'x');
100     NetLogEntry entry(NetLogEventType::PAC_JAVASCRIPT_ERROR, source,
101                       NetLogEventPhase::BEGIN, base::TimeTicks::Now(),
102                       NetLogParamsWithString("message", message));
103     logger->OnAddEntry(entry);
104   }
105 }
106 
107 // ParsedNetLog holds the parsed contents of a NetLog file (constants, events,
108 // and polled data).
109 struct ParsedNetLog {
110   base::expected<void, std::string> InitFromFileContents(
111       const std::string& input);
112   const base::Value::Dict* GetEvent(size_t i) const;
113 
114   // Initializes the ParsedNetLog by parsing a JSON file.
115   // Owner for the Value tree and a dictionary for the entire netlog.
116   base::Value root;
117 
118   // The constants dictionary.
119   raw_ptr<const base::Value::Dict> constants = nullptr;
120 
121   // The events list.
122   raw_ptr<const base::Value::List> events = nullptr;
123 
124   // The optional polled data (may be nullptr).
125   raw_ptr<const base::Value::Dict> polled_data = nullptr;
126 };
127 
InitFromFileContents(const std::string & input)128 base::expected<void, std::string> ParsedNetLog::InitFromFileContents(
129     const std::string& input) {
130   if (input.empty()) {
131     return base::unexpected("input is empty");
132   }
133 
134   ASSIGN_OR_RETURN(root, base::JSONReader::ReadAndReturnValueWithError(input),
135                    &base::JSONReader::Error::message);
136 
137   const base::Value::Dict* dict = root.GetIfDict();
138   if (!dict) {
139     return base::unexpected("Not a dictionary");
140   }
141 
142   events = dict->FindListByDottedPath("events");
143   if (!events) {
144     return base::unexpected("No events list");
145   }
146 
147   constants = dict->FindDictByDottedPath("constants");
148   if (!constants) {
149     return base::unexpected("No constants dictionary");
150   }
151 
152   // Polled data is optional (ignore success).
153   polled_data = dict->FindDictByDottedPath("polledData");
154 
155   return base::ok();
156 }
157 
158 // Returns the event at index |i|, or nullptr if there is none.
GetEvent(size_t i) const159 const base::Value::Dict* ParsedNetLog::GetEvent(size_t i) const {
160   if (!events || i >= events->size())
161     return nullptr;
162 
163   return (*events)[i].GetIfDict();
164 }
165 
166 // Creates a ParsedNetLog by reading a NetLog from a file. Returns nullptr on
167 // failure.
ReadNetLogFromDisk(const base::FilePath & log_path)168 base::expected<std::unique_ptr<ParsedNetLog>, std::string> ReadNetLogFromDisk(
169     const base::FilePath& log_path) {
170   std::string input;
171   if (!base::ReadFileToString(log_path, &input)) {
172     return base::unexpected("Failed reading file: " +
173                             base::UTF16ToUTF8(log_path.LossyDisplayName()));
174   }
175 
176   std::unique_ptr<ParsedNetLog> result = std::make_unique<ParsedNetLog>();
177 
178   RETURN_IF_ERROR(result->InitFromFileContents(input));
179   return result;
180 }
181 
182 // Checks that |log| contains events as emitted by AddEntries() above.
183 // |num_events_emitted| corresponds to |num_entries| of AddEntries(). Whereas
184 // |num_events_saved| is the expected number of events that have actually been
185 // written to the log (post-truncation).
VerifyEventsInLog(const ParsedNetLog * log,size_t num_events_emitted,size_t num_events_saved)186 void VerifyEventsInLog(const ParsedNetLog* log,
187                        size_t num_events_emitted,
188                        size_t num_events_saved) {
189   ASSERT_TRUE(log);
190   ASSERT_LE(num_events_saved, num_events_emitted);
191   ASSERT_EQ(num_events_saved, log->events->size());
192 
193   // The last |num_events_saved| should all be sequential, with the last one
194   // being numbered |num_events_emitted - 1|.
195   for (size_t i = 0; i < num_events_saved; ++i) {
196     const base::Value::Dict* event = log->GetEvent(i);
197     ASSERT_TRUE(event);
198 
199     size_t expected_source_id = num_events_emitted - num_events_saved + i;
200 
201     std::optional<int> id_value = event->FindIntByDottedPath("source.id");
202     ASSERT_EQ(static_cast<int>(expected_source_id), id_value);
203   }
204 }
205 
206 // Helper that checks whether |dict| has a string property at |key| having
207 // |value|.
ExpectDictionaryContainsProperty(const base::Value::Dict & dict,const std::string & key,const std::string & value)208 void ExpectDictionaryContainsProperty(const base::Value::Dict& dict,
209                                       const std::string& key,
210                                       const std::string& value) {
211   const std::string* actual_value = dict.FindStringByDottedPath(key);
212   ASSERT_EQ(value, *actual_value);
213 }
214 
215 // Used for tests that are common to both bounded and unbounded modes of the
216 // the FileNetLogObserver. The param is true if bounded mode is used.
217 class FileNetLogObserverTest : public ::testing::TestWithParam<bool>,
218                                public WithTaskEnvironment {
219  public:
SetUp()220   void SetUp() override {
221     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
222     log_path_ = temp_dir_.GetPath().AppendASCII("net-log.json");
223   }
224 
TearDown()225   void TearDown() override {
226     logger_.reset();
227     // FileNetLogObserver destructor might post to message loop.
228     RunUntilIdle();
229   }
230 
IsBounded() const231   bool IsBounded() const { return GetParam(); }
232 
CreateAndStartObserving(std::unique_ptr<base::Value::Dict> constants,NetLogCaptureMode capture_mode=NetLogCaptureMode::kDefault)233   void CreateAndStartObserving(
234       std::unique_ptr<base::Value::Dict> constants,
235       NetLogCaptureMode capture_mode = NetLogCaptureMode::kDefault) {
236     if (IsBounded()) {
237       logger_ = FileNetLogObserver::CreateBoundedForTests(
238           log_path_, kLargeFileSize, kTotalNumFiles, capture_mode,
239           std::move(constants));
240     } else {
241       logger_ = FileNetLogObserver::CreateUnbounded(log_path_, capture_mode,
242                                                     std::move(constants));
243     }
244 
245     logger_->StartObserving(NetLog::Get());
246   }
247 
CreateAndStartObservingBoundedFile(int max_file_size,std::unique_ptr<base::Value::Dict> constants)248   void CreateAndStartObservingBoundedFile(
249       int max_file_size,
250       std::unique_ptr<base::Value::Dict> constants) {
251     base::File file(log_path_,
252                     base::File::FLAG_CREATE | base::File::FLAG_WRITE);
253     EXPECT_TRUE(file.IsValid());
254     // Stick in some nonsense to make sure the file gets cleared properly
255     file.Write(0, "not json", 8);
256 
257     logger_ = FileNetLogObserver::CreateBoundedFile(
258         std::move(file), max_file_size, NetLogCaptureMode::kDefault,
259         std::move(constants));
260 
261     logger_->StartObserving(NetLog::Get());
262   }
263 
CreateAndStartObservingPreExisting(std::unique_ptr<base::Value::Dict> constants)264   void CreateAndStartObservingPreExisting(
265       std::unique_ptr<base::Value::Dict> constants) {
266     ASSERT_TRUE(scratch_dir_.CreateUniqueTempDir());
267 
268     base::File file(log_path_,
269                     base::File::FLAG_CREATE | base::File::FLAG_WRITE);
270     EXPECT_TRUE(file.IsValid());
271     // Stick in some nonsense to make sure the file gets cleared properly
272     file.Write(0, "not json", 8);
273 
274     if (IsBounded()) {
275       logger_ = FileNetLogObserver::CreateBoundedPreExisting(
276           scratch_dir_.GetPath(), std::move(file), kLargeFileSize,
277           NetLogCaptureMode::kDefault, std::move(constants));
278     } else {
279       logger_ = FileNetLogObserver::CreateUnboundedPreExisting(
280           std::move(file), NetLogCaptureMode::kDefault, std::move(constants));
281     }
282 
283     logger_->StartObserving(NetLog::Get());
284   }
285 
LogFileExists()286   bool LogFileExists() {
287     // The log files are written by a sequenced task runner. Drain all the
288     // scheduled tasks to ensure that the file writing ones have run before
289     // checking if they exist.
290     base::ThreadPoolInstance::Get()->FlushForTesting();
291     return base::PathExists(log_path_);
292   }
293 
294  protected:
295   std::unique_ptr<FileNetLogObserver> logger_;
296   base::ScopedTempDir temp_dir_;
297   base::ScopedTempDir scratch_dir_;  // used for bounded + preexisting
298   base::FilePath log_path_;
299 };
300 
301 // Used for tests that are exclusive to the bounded mode of FileNetLogObserver.
302 class FileNetLogObserverBoundedTest : public ::testing::Test,
303                                       public WithTaskEnvironment {
304  public:
SetUp()305   void SetUp() override {
306     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
307     log_path_ = temp_dir_.GetPath().AppendASCII("net-log.json");
308   }
309 
TearDown()310   void TearDown() override {
311     logger_.reset();
312     // FileNetLogObserver destructor might post to message loop.
313     RunUntilIdle();
314   }
315 
CreateAndStartObserving(std::unique_ptr<base::Value::Dict> constants,uint64_t total_file_size,int num_files)316   void CreateAndStartObserving(std::unique_ptr<base::Value::Dict> constants,
317                                uint64_t total_file_size,
318                                int num_files) {
319     logger_ = FileNetLogObserver::CreateBoundedForTests(
320         log_path_, total_file_size, num_files, NetLogCaptureMode::kDefault,
321         std::move(constants));
322     logger_->StartObserving(NetLog::Get());
323   }
324 
325   // Returns the path for an internally directory created for bounded logs (this
326   // needs to be kept in sync with the implementation).
GetInprogressDirectory() const327   base::FilePath GetInprogressDirectory() const {
328     return log_path_.AddExtension(FILE_PATH_LITERAL(".inprogress"));
329   }
330 
GetEventFilePath(int index) const331   base::FilePath GetEventFilePath(int index) const {
332     return GetInprogressDirectory().AppendASCII(
333         "event_file_" + base::NumberToString(index) + ".json");
334   }
335 
GetEndNetlogPath() const336   base::FilePath GetEndNetlogPath() const {
337     return GetInprogressDirectory().AppendASCII("end_netlog.json");
338   }
339 
GetConstantsPath() const340   base::FilePath GetConstantsPath() const {
341     return GetInprogressDirectory().AppendASCII("constants.json");
342   }
343 
344 
345  protected:
346   std::unique_ptr<FileNetLogObserver> logger_;
347   base::FilePath log_path_;
348 
349  private:
350   base::ScopedTempDir temp_dir_;
351 };
352 
353 // Instantiates each FileNetLogObserverTest to use bounded and unbounded modes.
354 INSTANTIATE_TEST_SUITE_P(All,
355                          FileNetLogObserverTest,
356                          ::testing::Values(true, false));
357 
358 // Tests deleting a FileNetLogObserver without first calling StopObserving().
TEST_P(FileNetLogObserverTest,ObserverDestroyedWithoutStopObserving)359 TEST_P(FileNetLogObserverTest, ObserverDestroyedWithoutStopObserving) {
360   CreateAndStartObserving(nullptr);
361 
362   // Send dummy event
363   AddEntries(logger_.get(), 1, kDummyEventSize);
364 
365   // The log files should have been started.
366   ASSERT_TRUE(LogFileExists());
367 
368   logger_.reset();
369 
370   // When the logger is re-set without having called StopObserving(), the
371   // partially written log files are deleted.
372   ASSERT_FALSE(LogFileExists());
373 }
374 
375 // Same but with pre-existing file.
TEST_P(FileNetLogObserverTest,ObserverDestroyedWithoutStopObservingPreExisting)376 TEST_P(FileNetLogObserverTest,
377        ObserverDestroyedWithoutStopObservingPreExisting) {
378   CreateAndStartObservingPreExisting(nullptr);
379 
380   // Send dummy event
381   AddEntries(logger_.get(), 1, kDummyEventSize);
382 
383   // The log files should have been started.
384   ASSERT_TRUE(LogFileExists());
385 
386   // Should also have the scratch dir, if bounded. (Can be checked since
387   // LogFileExists flushed the thread pool).
388   if (IsBounded()) {
389     ASSERT_TRUE(base::PathExists(scratch_dir_.GetPath()));
390   }
391 
392   logger_.reset();
393 
394   // Unlike in the non-preexisting case, the output file isn't deleted here,
395   // since the process running the observer likely won't have the sandbox
396   // permission to do so.
397   ASSERT_TRUE(LogFileExists());
398   if (IsBounded()) {
399     ASSERT_FALSE(base::PathExists(scratch_dir_.GetPath()));
400   }
401 }
402 
403 // Tests calling StopObserving() with a null closure.
TEST_P(FileNetLogObserverTest,StopObservingNullClosure)404 TEST_P(FileNetLogObserverTest, StopObservingNullClosure) {
405   CreateAndStartObserving(nullptr);
406 
407   // Send dummy event
408   AddEntries(logger_.get(), 1, kDummyEventSize);
409 
410   // The log files should have been started.
411   ASSERT_TRUE(LogFileExists());
412 
413   logger_->StopObserving(nullptr, base::OnceClosure());
414 
415   logger_.reset();
416 
417   // Since the logger was explicitly stopped, its files should still exist.
418   ASSERT_TRUE(LogFileExists());
419 }
420 
421 // Tests creating a FileNetLogObserver using an invalid (can't be written to)
422 // path.
TEST_P(FileNetLogObserverTest,InitLogWithInvalidPath)423 TEST_P(FileNetLogObserverTest, InitLogWithInvalidPath) {
424   // Use a path to a non-existent directory.
425   log_path_ = temp_dir_.GetPath().AppendASCII("bogus").AppendASCII("path");
426 
427   CreateAndStartObserving(nullptr);
428 
429   // Send dummy event
430   AddEntries(logger_.get(), 1, kDummyEventSize);
431 
432   // No log files should have been written, as the log writer will not create
433   // missing directories.
434   ASSERT_FALSE(LogFileExists());
435 
436   logger_->StopObserving(nullptr, base::OnceClosure());
437 
438   logger_.reset();
439 
440   // There should still be no files.
441   ASSERT_FALSE(LogFileExists());
442 }
443 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithNoEvents)444 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithNoEvents) {
445   TestClosure closure;
446 
447   CreateAndStartObserving(nullptr);
448 
449   logger_->StopObserving(nullptr, closure.closure());
450 
451   closure.WaitForResult();
452 
453   // Verify the written log.
454   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
455                        ReadNetLogFromDisk(log_path_));
456   ASSERT_EQ(0u, log->events->size());
457 }
458 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithOneEvent)459 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithOneEvent) {
460   TestClosure closure;
461 
462   CreateAndStartObserving(nullptr);
463 
464   // Send dummy event.
465   AddEntries(logger_.get(), 1, kDummyEventSize);
466 
467   logger_->StopObserving(nullptr, closure.closure());
468 
469   closure.WaitForResult();
470 
471   // Verify the written log.
472   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
473                        ReadNetLogFromDisk(log_path_));
474   ASSERT_EQ(1u, log->events->size());
475 }
476 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithOneEventPreExisting)477 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithOneEventPreExisting) {
478   TestClosure closure;
479 
480   CreateAndStartObservingPreExisting(nullptr);
481 
482   // Send dummy event.
483   AddEntries(logger_.get(), 1, kDummyEventSize);
484 
485   logger_->StopObserving(nullptr, closure.closure());
486 
487   closure.WaitForResult();
488 
489   // Verify the written log.
490   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
491                        ReadNetLogFromDisk(log_path_));
492   ASSERT_EQ(1u, log->events->size());
493 }
494 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithNoEventsCreateBoundedFile)495 TEST_P(FileNetLogObserverTest,
496        GeneratesValidJSONWithNoEventsCreateBoundedFile) {
497   TestClosure closure;
498 
499   CreateAndStartObservingBoundedFile(kLargeFileSize, nullptr);
500 
501   logger_->StopObserving(nullptr, closure.closure());
502 
503   closure.WaitForResult();
504 
505   // Verify the written log.
506   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
507                        ReadNetLogFromDisk(log_path_));
508   ASSERT_EQ(0u, log->events->size());
509 }
510 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithOneEventCreateBoundedFile)511 TEST_P(FileNetLogObserverTest,
512        GeneratesValidJSONWithOneEventCreateBoundedFile) {
513   TestClosure closure;
514 
515   CreateAndStartObservingBoundedFile(kLargeFileSize, nullptr);
516 
517   // Send dummy event.
518   AddEntries(logger_.get(), 1, kDummyEventSize);
519 
520   logger_->StopObserving(nullptr, closure.closure());
521 
522   closure.WaitForResult();
523 
524   // Verify the written log.
525   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
526                        ReadNetLogFromDisk(log_path_));
527   ASSERT_EQ(1u, log->events->size());
528 }
529 
530 // Sends exactly enough events to the observer to completely fill the file.
TEST_P(FileNetLogObserverTest,BoundedFileFillsFile)531 TEST_P(FileNetLogObserverTest, BoundedFileFillsFile) {
532   const int kTotalFileSize = 10000;
533   const int kEventSize = 200;
534   const int kFileSize = kTotalFileSize;
535   const int kNumEvents = kFileSize / kEventSize;
536   TestClosure closure;
537 
538   CreateAndStartObservingBoundedFile(kTotalFileSize, nullptr);
539 
540   // Send dummy events.
541   AddEntries(logger_.get(), kNumEvents, kEventSize);
542 
543   logger_->StopObserving(nullptr, closure.closure());
544 
545   closure.WaitForResult();
546 
547   // Verify the written log.
548   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
549                        ReadNetLogFromDisk(log_path_));
550   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
551 }
552 
553 // Sends twice as many events as will fill the file to the observer
TEST_P(FileNetLogObserverTest,BoundedFileTruncatesEventsAfterLimit)554 TEST_P(FileNetLogObserverTest, BoundedFileTruncatesEventsAfterLimit) {
555   const int kTotalFileSize = 10000;
556   const int kEventSize = 200;
557   const int kFileSize = kTotalFileSize;
558   const int kNumEvents = kFileSize / kEventSize;
559   TestClosure closure;
560 
561   CreateAndStartObservingBoundedFile(kTotalFileSize, nullptr);
562 
563   // Send dummy events.
564   AddEntries(logger_.get(), kNumEvents * 2, kEventSize);
565 
566   logger_->StopObserving(nullptr, closure.closure());
567 
568   closure.WaitForResult();
569 
570   // Verify the written log.
571   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
572                        ReadNetLogFromDisk(log_path_));
573   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
574 }
575 
TEST_P(FileNetLogObserverTest,PreExistingFileBroken)576 TEST_P(FileNetLogObserverTest, PreExistingFileBroken) {
577   // Test that pre-existing output file not being successfully open is
578   // tolerated.
579   ASSERT_TRUE(scratch_dir_.CreateUniqueTempDir());
580   base::File file;
581   EXPECT_FALSE(file.IsValid());
582   if (IsBounded())
583     logger_ = FileNetLogObserver::CreateBoundedPreExisting(
584         scratch_dir_.GetPath(), std::move(file), kLargeFileSize,
585         NetLogCaptureMode::kDefault, nullptr);
586   else
587     logger_ = FileNetLogObserver::CreateUnboundedPreExisting(
588         std::move(file), NetLogCaptureMode::kDefault, nullptr);
589   logger_->StartObserving(NetLog::Get());
590 
591   // Send dummy event.
592   AddEntries(logger_.get(), 1, kDummyEventSize);
593   TestClosure closure;
594   logger_->StopObserving(nullptr, closure.closure());
595   closure.WaitForResult();
596 }
597 
TEST_P(FileNetLogObserverTest,CustomConstants)598 TEST_P(FileNetLogObserverTest, CustomConstants) {
599   TestClosure closure;
600 
601   const char kConstantKey[] = "magic";
602   const char kConstantString[] = "poney";
603   base::Value::Dict constants;
604   constants.SetByDottedPath(kConstantKey, kConstantString);
605 
606   CreateAndStartObserving(
607       std::make_unique<base::Value::Dict>(std::move(constants)));
608 
609   logger_->StopObserving(nullptr, closure.closure());
610 
611   closure.WaitForResult();
612 
613   // Verify the written log.
614   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
615                        ReadNetLogFromDisk(log_path_));
616 
617   // Check that custom constant was correctly printed.
618   ExpectDictionaryContainsProperty(*log->constants, kConstantKey,
619                                    kConstantString);
620 }
621 
TEST_P(FileNetLogObserverTest,GeneratesValidJSONWithPolledData)622 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithPolledData) {
623   TestClosure closure;
624 
625   CreateAndStartObserving(nullptr);
626 
627   // Create dummy polled data
628   const char kDummyPolledDataPath[] = "dummy_path";
629   const char kDummyPolledDataString[] = "dummy_info";
630   base::Value::Dict dummy_polled_data;
631   dummy_polled_data.SetByDottedPath(kDummyPolledDataPath,
632                                     kDummyPolledDataString);
633 
634   logger_->StopObserving(
635       std::make_unique<base::Value>(std::move(dummy_polled_data)),
636       closure.closure());
637 
638   closure.WaitForResult();
639 
640   // Verify the written log.
641   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
642                        ReadNetLogFromDisk(log_path_));
643   ASSERT_EQ(0u, log->events->size());
644 
645   // Make sure additional information is present and validate it.
646   ASSERT_TRUE(log->polled_data);
647   ExpectDictionaryContainsProperty(*log->polled_data, kDummyPolledDataPath,
648                                    kDummyPolledDataString);
649 }
650 
651 // Ensure that the Capture Mode is recorded as a constant in the NetLog.
TEST_P(FileNetLogObserverTest,LogModeRecorded)652 TEST_P(FileNetLogObserverTest, LogModeRecorded) {
653   struct TestCase {
654     NetLogCaptureMode capture_mode;
655     const char* expected_value;
656   } test_cases[] = {// Challenges that result in success results.
657                     {NetLogCaptureMode::kEverything, "Everything"},
658                     {NetLogCaptureMode::kIncludeSensitive, "IncludeSensitive"},
659                     {NetLogCaptureMode::kDefault, "Default"}};
660 
661   TestClosure closure;
662   for (const auto& test_case : test_cases) {
663     CreateAndStartObserving(nullptr, test_case.capture_mode);
664     logger_->StopObserving(nullptr, closure.closure());
665     closure.WaitForResult();
666     ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
667                          ReadNetLogFromDisk(log_path_));
668     ExpectDictionaryContainsProperty(*log->constants, "logCaptureMode",
669                                      test_case.expected_value);
670   }
671 }
672 
673 // Adds events concurrently from several different threads. The exact order of
674 // events seen by this test is non-deterministic.
TEST_P(FileNetLogObserverTest,AddEventsFromMultipleThreads)675 TEST_P(FileNetLogObserverTest, AddEventsFromMultipleThreads) {
676   const size_t kNumThreads = 10;
677   std::vector<std::unique_ptr<base::Thread>> threads(kNumThreads);
678 
679 #if BUILDFLAG(IS_FUCHSIA)
680   // TODO(crbug.com/40625862): Diagnosting logging to determine where
681   // this test sometimes hangs.
682   LOG(ERROR) << "Create and start threads.";
683 #endif
684 
685   // Start all the threads. Waiting for them to start is to hopefuly improve
686   // the odds of hitting interesting races once events start being added.
687   for (size_t i = 0; i < threads.size(); ++i) {
688     threads[i] = std::make_unique<base::Thread>("WorkerThread" +
689                                                 base::NumberToString(i));
690     threads[i]->Start();
691     threads[i]->WaitUntilThreadStarted();
692   }
693 
694 #if BUILDFLAG(IS_FUCHSIA)
695   LOG(ERROR) << "Create and start observing.";
696 #endif
697 
698   CreateAndStartObserving(nullptr);
699 
700   const size_t kNumEventsAddedPerThread = 200;
701 
702 #if BUILDFLAG(IS_FUCHSIA)
703   LOG(ERROR) << "Posting tasks.";
704 #endif
705 
706   // Add events in parallel from all the threads.
707   for (size_t i = 0; i < kNumThreads; ++i) {
708     threads[i]->task_runner()->PostTask(
709         FROM_HERE, base::BindOnce(&AddEntries, base::Unretained(logger_.get()),
710                                   kNumEventsAddedPerThread, kDummyEventSize));
711   }
712 
713 #if BUILDFLAG(IS_FUCHSIA)
714   LOG(ERROR) << "Joining all threads.";
715 #endif
716 
717   // Join all the threads.
718   threads.clear();
719 
720 #if BUILDFLAG(IS_FUCHSIA)
721   LOG(ERROR) << "Stop observing.";
722 #endif
723 
724   // Stop observing.
725   TestClosure closure;
726   logger_->StopObserving(nullptr, closure.closure());
727   closure.WaitForResult();
728 
729 #if BUILDFLAG(IS_FUCHSIA)
730   LOG(ERROR) << "Read log from disk and verify.";
731 #endif
732 
733   // Verify the written log.
734   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
735                        ReadNetLogFromDisk(log_path_));
736   // Check that the expected number of events were written to disk.
737   EXPECT_EQ(kNumEventsAddedPerThread * kNumThreads, log->events->size());
738 
739 #if BUILDFLAG(IS_FUCHSIA)
740   LOG(ERROR) << "Teardown.";
741 #endif
742 }
743 
744 // Sends enough events to the observer to completely fill one file, but not
745 // write any events to an additional file. Checks the file bounds.
TEST_F(FileNetLogObserverBoundedTest,EqualToOneFile)746 TEST_F(FileNetLogObserverBoundedTest, EqualToOneFile) {
747   // The total size of the events is equal to the size of one file.
748   // |kNumEvents| * |kEventSize| = |kTotalFileSize| / |kTotalNumEvents|
749   const int kTotalFileSize = 5000;
750   const int kNumEvents = 2;
751   const int kEventSize = 250;
752   TestClosure closure;
753 
754   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
755 
756   AddEntries(logger_.get(), kNumEvents, kEventSize);
757   logger_->StopObserving(nullptr, closure.closure());
758 
759   closure.WaitForResult();
760 
761   // Verify the written log.
762   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
763                        ReadNetLogFromDisk(log_path_));
764   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
765 }
766 
767 // Sends enough events to fill one file, and partially fill a second file.
768 // Checks the file bounds and writing to a new file.
TEST_F(FileNetLogObserverBoundedTest,OneEventOverOneFile)769 TEST_F(FileNetLogObserverBoundedTest, OneEventOverOneFile) {
770   // The total size of the events is greater than the size of one file, and
771   // less than the size of two files. The total size of all events except one
772   // is equal to the size of one file, so the last event will be the only event
773   // in the second file.
774   // (|kNumEvents| - 1) * kEventSize = |kTotalFileSize| / |kTotalNumEvents|
775   const int kTotalFileSize = 6000;
776   const int kNumEvents = 4;
777   const int kEventSize = 200;
778   TestClosure closure;
779 
780   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
781 
782   AddEntries(logger_.get(), kNumEvents, kEventSize);
783 
784   logger_->StopObserving(nullptr, closure.closure());
785 
786   closure.WaitForResult();
787 
788   // Verify the written log.
789   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
790                        ReadNetLogFromDisk(log_path_));
791   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
792 }
793 
794 // Sends enough events to the observer to completely fill two files.
TEST_F(FileNetLogObserverBoundedTest,EqualToTwoFiles)795 TEST_F(FileNetLogObserverBoundedTest, EqualToTwoFiles) {
796   // The total size of the events is equal to the total size of two files.
797   // |kNumEvents| * |kEventSize| = 2 * |kTotalFileSize| / |kTotalNumEvents|
798   const int kTotalFileSize = 6000;
799   const int kNumEvents = 6;
800   const int kEventSize = 200;
801   TestClosure closure;
802 
803   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
804 
805   AddEntries(logger_.get(), kNumEvents, kEventSize);
806 
807   logger_->StopObserving(nullptr, closure.closure());
808 
809   closure.WaitForResult();
810 
811   // Verify the written log.
812   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
813                        ReadNetLogFromDisk(log_path_));
814   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
815 }
816 
817 // Sends exactly enough events to the observer to completely fill all files,
818 // so that all events fit into the event files and no files need to be
819 // overwritten.
TEST_F(FileNetLogObserverBoundedTest,FillAllFilesNoOverwriting)820 TEST_F(FileNetLogObserverBoundedTest, FillAllFilesNoOverwriting) {
821   // The total size of events is equal to the total size of all files.
822   // |kEventSize| * |kNumEvents| = |kTotalFileSize|
823   const int kTotalFileSize = 10000;
824   const int kEventSize = 200;
825   const int kFileSize = kTotalFileSize / kTotalNumFiles;
826   const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
827   TestClosure closure;
828 
829   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
830 
831   AddEntries(logger_.get(), kNumEvents, kEventSize);
832 
833   logger_->StopObserving(nullptr, closure.closure());
834 
835   closure.WaitForResult();
836 
837   // Verify the written log.
838   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
839                        ReadNetLogFromDisk(log_path_));
840   VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
841 }
842 
843 // Sends more events to the observer than will fill the WriteQueue, forcing the
844 // queue to drop an event. Checks that the queue drops the oldest event.
TEST_F(FileNetLogObserverBoundedTest,DropOldEventsFromWriteQueue)845 TEST_F(FileNetLogObserverBoundedTest, DropOldEventsFromWriteQueue) {
846   // The total size of events is greater than the WriteQueue's memory limit, so
847   // the oldest event must be dropped from the queue and not written to any
848   // file.
849   // |kNumEvents| * |kEventSize| > |kTotalFileSize| * 2
850   const int kTotalFileSize = 1000;
851   const int kNumEvents = 11;
852   const int kEventSize = 200;
853   const int kFileSize = kTotalFileSize / kTotalNumFiles;
854   TestClosure closure;
855 
856   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
857 
858   AddEntries(logger_.get(), kNumEvents, kEventSize);
859 
860   logger_->StopObserving(nullptr, closure.closure());
861 
862   closure.WaitForResult();
863 
864   // Verify the written log.
865   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
866                        ReadNetLogFromDisk(log_path_));
867   VerifyEventsInLog(
868       log.get(), kNumEvents,
869       static_cast<size_t>(kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1)));
870 }
871 
872 // Sends twice as many events as will fill all files to the observer, so that
873 // all of the event files will be filled twice, and every file will be
874 // overwritten.
TEST_F(FileNetLogObserverBoundedTest,OverwriteAllFiles)875 TEST_F(FileNetLogObserverBoundedTest, OverwriteAllFiles) {
876   // The total size of the events is much greater than twice the number of
877   // events that can fit in the event files, to make sure that the extra events
878   // are written to a file, not just dropped from the queue.
879   // |kNumEvents| * |kEventSize| >= 2 * |kTotalFileSize|
880   const int kTotalFileSize = 6000;
881   const int kNumEvents = 60;
882   const int kEventSize = 200;
883   const int kFileSize = kTotalFileSize / kTotalNumFiles;
884   TestClosure closure;
885 
886   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
887 
888   AddEntries(logger_.get(), kNumEvents, kEventSize);
889 
890   logger_->StopObserving(nullptr, closure.closure());
891 
892   closure.WaitForResult();
893 
894   // Check that the minimum number of events that should fit in event files
895   // have been written to all files.
896   int events_per_file = (kFileSize - 1) / kEventSize + 1;
897   int events_in_last_file = (kNumEvents - 1) % events_per_file + 1;
898 
899   // Indicates the total number of events that should be written to all files.
900   int num_events_in_files =
901       (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
902 
903   // Verify the written log.
904   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
905                        ReadNetLogFromDisk(log_path_));
906   VerifyEventsInLog(log.get(), kNumEvents,
907                     static_cast<size_t>(num_events_in_files));
908 }
909 
910 // Sends enough events to the observer to fill all event files, plus overwrite
911 // some files, without overwriting all of them. Checks that the FileWriter
912 // overwrites the file with the oldest events.
TEST_F(FileNetLogObserverBoundedTest,PartiallyOverwriteFiles)913 TEST_F(FileNetLogObserverBoundedTest, PartiallyOverwriteFiles) {
914   // The number of events sent to the observer is greater than the number of
915   // events that can fit into the event files, but the events can fit in less
916   // than twice the number of event files, so not every file will need to be
917   // overwritten.
918   // |kTotalFileSize| < |kNumEvents| * |kEventSize|
919   // |kNumEvents| * |kEventSize| <= (2 * |kTotalNumFiles| - 1) * |kFileSize|
920   const int kTotalFileSize = 6000;
921   const int kNumEvents = 50;
922   const int kEventSize = 200;
923   const int kFileSize = kTotalFileSize / kTotalNumFiles;
924   TestClosure closure;
925 
926   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
927 
928   AddEntries(logger_.get(), kNumEvents, kEventSize);
929 
930   logger_->StopObserving(nullptr, closure.closure());
931 
932   closure.WaitForResult();
933 
934   // Check that the minimum number of events that should fit in event files
935   // have been written to a file.
936   int events_per_file = (kFileSize - 1) / kEventSize + 1;
937   int events_in_last_file = kNumEvents % events_per_file;
938   if (!events_in_last_file)
939     events_in_last_file = events_per_file;
940   int num_events_in_files =
941       (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
942 
943   // Verify the written log.
944   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
945                        ReadNetLogFromDisk(log_path_));
946   VerifyEventsInLog(log.get(), kNumEvents,
947                     static_cast<size_t>(num_events_in_files));
948 }
949 
950 // Start logging in bounded mode. Create directories in places where the logger
951 // expects to create files, in order to cause that file creation to fail.
952 //
953 //   constants.json      -- succeess
954 //   event_file_0.json   -- fails to open
955 //   end_netlog.json     -- fails to open
TEST_F(FileNetLogObserverBoundedTest,SomeFilesFailToOpen)956 TEST_F(FileNetLogObserverBoundedTest, SomeFilesFailToOpen) {
957   // The total size of events is equal to the total size of all files.
958   // |kEventSize| * |kNumEvents| = |kTotalFileSize|
959   const int kTotalFileSize = 10000;
960   const int kEventSize = 200;
961   const int kFileSize = kTotalFileSize / kTotalNumFiles;
962   const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
963   TestClosure closure;
964 
965   // Create directories as a means to block files from being created by logger.
966   EXPECT_TRUE(base::CreateDirectory(GetEventFilePath(0)));
967   EXPECT_TRUE(base::CreateDirectory(GetEndNetlogPath()));
968 
969   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
970 
971   AddEntries(logger_.get(), kNumEvents, kEventSize);
972 
973   logger_->StopObserving(nullptr, closure.closure());
974 
975   closure.WaitForResult();
976 
977   // The written log is invalid (and hence can't be parsed). It is just the
978   // constants.
979   std::string log_contents;
980   ASSERT_TRUE(base::ReadFileToString(log_path_, &log_contents));
981   // TODO(eroman): Verify the partially written log file?
982 
983   // Even though FileNetLogObserver didn't create the directory itself, it will
984   // unconditionally delete it. The name should be uncommon enough for this be
985   // to reasonable.
986   EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
987 }
988 
989 // Start logging in bounded mode. Create a file at the path where the logger
990 // expects to create its inprogress directory to store event files. This will
991 // cause logging to completely break. open it.
TEST_F(FileNetLogObserverBoundedTest,InprogressDirectoryBlocked)992 TEST_F(FileNetLogObserverBoundedTest, InprogressDirectoryBlocked) {
993   // The total size of events is equal to the total size of all files.
994   // |kEventSize| * |kNumEvents| = |kTotalFileSize|
995   const int kTotalFileSize = 10000;
996   const int kEventSize = 200;
997   const int kFileSize = kTotalFileSize / kTotalNumFiles;
998   const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
999   TestClosure closure;
1000 
1001   // By creating a file where a directory should be, it will not be possible to
1002   // write any event files.
1003   EXPECT_TRUE(base::WriteFile(GetInprogressDirectory(), "x"));
1004 
1005   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
1006 
1007   AddEntries(logger_.get(), kNumEvents, kEventSize);
1008 
1009   logger_->StopObserving(nullptr, closure.closure());
1010 
1011   closure.WaitForResult();
1012 
1013   // There will be a log file at the final output, however it will be empty
1014   // since nothing was written to the .inprogress directory.
1015   std::string log_contents;
1016   ASSERT_TRUE(base::ReadFileToString(log_path_, &log_contents));
1017   EXPECT_EQ("", log_contents);
1018 
1019   // FileNetLogObserver unconditionally deletes the inprogress path (even though
1020   // it didn't actually create this file and it was a file instead of a
1021   // directory).
1022   // TODO(eroman): Should it only delete if it is a file?
1023   EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
1024 }
1025 
1026 // Start logging in bounded mode. Create a file with the same name as the 0th
1027 // events file. This will prevent any events from being written.
TEST_F(FileNetLogObserverBoundedTest,BlockEventsFile0)1028 TEST_F(FileNetLogObserverBoundedTest, BlockEventsFile0) {
1029   // The total size of events is equal to the total size of all files.
1030   // |kEventSize| * |kNumEvents| = |kTotalFileSize|
1031   const int kTotalFileSize = 10000;
1032   const int kEventSize = 200;
1033   const int kFileSize = kTotalFileSize / kTotalNumFiles;
1034   const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
1035   TestClosure closure;
1036 
1037   // Block the 0th events file.
1038   EXPECT_TRUE(base::CreateDirectory(GetEventFilePath(0)));
1039 
1040   CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
1041 
1042   AddEntries(logger_.get(), kNumEvents, kEventSize);
1043 
1044   logger_->StopObserving(nullptr, closure.closure());
1045 
1046   closure.WaitForResult();
1047 
1048   // Verify the written log.
1049   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
1050                        ReadNetLogFromDisk(log_path_));
1051   ASSERT_EQ(0u, log->events->size());
1052 }
1053 
1054 // Make sure that when using bounded mode with a pre-existing output file,
1055 // a separate in-progress directory can be specified.
TEST_F(FileNetLogObserverBoundedTest,PreExistingUsesSpecifiedDir)1056 TEST_F(FileNetLogObserverBoundedTest, PreExistingUsesSpecifiedDir) {
1057   base::ScopedTempDir scratch_dir;
1058   ASSERT_TRUE(scratch_dir.CreateUniqueTempDir());
1059 
1060   base::File file(log_path_, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
1061   ASSERT_TRUE(file.IsValid());
1062 
1063   // Stick in some nonsense to make sure the file gets cleared properly
1064   file.Write(0, "not json", 8);
1065 
1066   logger_ = FileNetLogObserver::CreateBoundedPreExisting(
1067       scratch_dir.GetPath(), std::move(file), kLargeFileSize,
1068       NetLogCaptureMode::kDefault, nullptr);
1069   logger_->StartObserving(NetLog::Get());
1070 
1071   base::ThreadPoolInstance::Get()->FlushForTesting();
1072   EXPECT_TRUE(base::PathExists(log_path_));
1073   EXPECT_TRUE(
1074       base::PathExists(scratch_dir.GetPath().AppendASCII("constants.json")));
1075   EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
1076 
1077   TestClosure closure;
1078   logger_->StopObserving(nullptr, closure.closure());
1079   closure.WaitForResult();
1080 
1081   // Now the scratch dir should be gone, too.
1082   EXPECT_FALSE(base::PathExists(scratch_dir.GetPath()));
1083   EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
1084 }
1085 
1086 // Creates a bounded log with a very large total size and verifies that events
1087 // are not dropped. This is a regression test for https://crbug.com/959929 in
1088 // which the WriteQueue size was calculated by the possibly overflowed
1089 // expression |total_file_size * 2|.
TEST_F(FileNetLogObserverBoundedTest,LargeWriteQueueSize)1090 TEST_F(FileNetLogObserverBoundedTest, LargeWriteQueueSize) {
1091   TestClosure closure;
1092 
1093   // This is a large value such that multiplying it by 2 will overflow to a much
1094   // smaller value (5).
1095   uint64_t total_file_size = 0x8000000000000005;
1096 
1097   CreateAndStartObserving(nullptr, total_file_size, kTotalNumFiles);
1098 
1099   // Send 3 dummy events. This isn't a lot of data, however if WriteQueue was
1100   // initialized using the overflowed value of |total_file_size * 2| (which is
1101   // 5), then the effective limit would prevent any events from being written.
1102   AddEntries(logger_.get(), 3, kDummyEventSize);
1103 
1104   logger_->StopObserving(nullptr, closure.closure());
1105 
1106   closure.WaitForResult();
1107 
1108   // Verify the written log.
1109   ASSERT_OK_AND_ASSIGN(std::unique_ptr<ParsedNetLog> log,
1110                        ReadNetLogFromDisk(log_path_));
1111   ASSERT_EQ(3u, log->events->size());
1112 }
1113 
AddEntriesViaNetLog(NetLog * net_log,int num_entries)1114 void AddEntriesViaNetLog(NetLog* net_log, int num_entries) {
1115   for (int i = 0; i < num_entries; i++) {
1116     net_log->AddGlobalEntry(NetLogEventType::PAC_JAVASCRIPT_ERROR);
1117   }
1118 }
1119 
TEST_P(FileNetLogObserverTest,AddEventsFromMultipleThreadsWithStopObserving)1120 TEST_P(FileNetLogObserverTest, AddEventsFromMultipleThreadsWithStopObserving) {
1121   const size_t kNumThreads = 10;
1122   std::vector<std::unique_ptr<base::Thread>> threads(kNumThreads);
1123   // Start all the threads. Waiting for them to start is to hopefully improve
1124   // the odds of hitting interesting races once events start being added.
1125   for (size_t i = 0; i < threads.size(); ++i) {
1126     threads[i] = std::make_unique<base::Thread>("WorkerThread" +
1127                                                 base::NumberToString(i));
1128     threads[i]->Start();
1129     threads[i]->WaitUntilThreadStarted();
1130   }
1131 
1132   CreateAndStartObserving(nullptr);
1133 
1134   const size_t kNumEventsAddedPerThread = 200;
1135 
1136   // Add events in parallel from all the threads.
1137   for (size_t i = 0; i < kNumThreads; ++i) {
1138     threads[i]->task_runner()->PostTask(
1139         FROM_HERE,
1140         base::BindOnce(&AddEntriesViaNetLog, base::Unretained(NetLog::Get()),
1141                        kNumEventsAddedPerThread));
1142   }
1143 
1144   // Stop observing.
1145   TestClosure closure;
1146   logger_->StopObserving(nullptr, closure.closure());
1147   closure.WaitForResult();
1148 
1149   // Join all the threads.
1150   threads.clear();
1151 
1152   ASSERT_TRUE(LogFileExists());
1153 }
1154 
TEST_P(FileNetLogObserverTest,AddEventsFromMultipleThreadsWithoutStopObserving)1155 TEST_P(FileNetLogObserverTest,
1156        AddEventsFromMultipleThreadsWithoutStopObserving) {
1157   const size_t kNumThreads = 10;
1158   std::vector<std::unique_ptr<base::Thread>> threads(kNumThreads);
1159   // Start all the threads. Waiting for them to start is to hopefully improve
1160   // the odds of hitting interesting races once events start being added.
1161   for (size_t i = 0; i < threads.size(); ++i) {
1162     threads[i] = std::make_unique<base::Thread>("WorkerThread" +
1163                                                 base::NumberToString(i));
1164     threads[i]->Start();
1165     threads[i]->WaitUntilThreadStarted();
1166   }
1167 
1168   CreateAndStartObserving(nullptr);
1169 
1170   const size_t kNumEventsAddedPerThread = 200;
1171 
1172   // Add events in parallel from all the threads.
1173   for (size_t i = 0; i < kNumThreads; ++i) {
1174     threads[i]->task_runner()->PostTask(
1175         FROM_HERE,
1176         base::BindOnce(&AddEntriesViaNetLog, base::Unretained(NetLog::Get()),
1177                        kNumEventsAddedPerThread));
1178   }
1179 
1180   // Destroy logger.
1181   logger_.reset();
1182 
1183   // Join all the threads.
1184   threads.clear();
1185 
1186   // The log file doesn't exist since StopObserving() was not called.
1187   ASSERT_FALSE(LogFileExists());
1188 }
1189 
1190 }  // namespace
1191 
1192 }  // namespace net
1193