1 // Copyright 2018 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 "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h"
6 
7 #include <memory>
8 #include <numeric>
9 #include <vector>
10 
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/optional.h"
15 #include "base/rand_util.h"
16 #include "base/test/task_environment.h"
17 #include "build/build_config.h"
18 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_unittest_helpers.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/zlib/google/compression_utils.h"
21 
22 #if defined(OS_CHROMEOS)
23 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
24 #include "chrome/browser/chromeos/profiles/profile_helper.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "components/account_id/account_id.h"
27 #include "components/user_manager/scoped_user_manager.h"
28 #include "content/public/test/browser_task_environment.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #endif
31 
32 namespace webrtc_event_logging {
33 
34 namespace {
35 constexpr LogCompressor::Result OK = LogCompressor::Result::OK;
36 constexpr LogCompressor::Result DISALLOWED = LogCompressor::Result::DISALLOWED;
37 constexpr LogCompressor::Result ERROR_ENCOUNTERED =
38     LogCompressor::Result::ERROR_ENCOUNTERED;
39 }  // namespace
40 
41 // Tests for GzipLogCompressor.
42 // Note that these tests may not use GzippedSize(), or they would be assuming
43 // what they set out to prove. (Subsequent tests may use it, though.)
44 class GzipLogCompressorTest : public ::testing::Test {
45  public:
46   ~GzipLogCompressorTest() override = default;
47 
Init(std::unique_ptr<CompressedSizeEstimator::Factory> estimator_factory)48   void Init(
49       std::unique_ptr<CompressedSizeEstimator::Factory> estimator_factory) {
50     DCHECK(!compressor_factory_);
51     DCHECK(estimator_factory);
52     compressor_factory_ = std::make_unique<GzipLogCompressorFactory>(
53         std::move(estimator_factory));
54   }
55 
Decompress(const std::string & input)56   std::string Decompress(const std::string& input) {
57     std::string output;
58     EXPECT_TRUE(compression::GzipUncompress(input, &output));
59     return output;
60   }
61 
62   std::unique_ptr<GzipLogCompressorFactory> compressor_factory_;
63 };
64 
TEST_F(GzipLogCompressorTest,GzipLogCompressorFactoryCreatesCompressorIfMinimalSizeOrAbove)65 TEST_F(GzipLogCompressorTest,
66        GzipLogCompressorFactoryCreatesCompressorIfMinimalSizeOrAbove) {
67   Init(std::make_unique<PerfectGzipEstimator::Factory>());
68   const size_t min_size = compressor_factory_->MinSizeBytes();
69   auto compressor = compressor_factory_->Create(min_size);
70   EXPECT_TRUE(compressor);
71 }
72 
TEST_F(GzipLogCompressorTest,GzipLogCompressorFactoryDoesNotCreateCompressorIfBelowMinimalSize)73 TEST_F(GzipLogCompressorTest,
74        GzipLogCompressorFactoryDoesNotCreateCompressorIfBelowMinimalSize) {
75   Init(std::make_unique<PerfectGzipEstimator::Factory>());
76   const size_t min_size = compressor_factory_->MinSizeBytes();
77   ASSERT_GE(min_size, 1u);
78   auto compressor = compressor_factory_->Create(min_size - 1);
79   EXPECT_FALSE(compressor);
80 }
81 
TEST_F(GzipLogCompressorTest,EmptyStreamReasonableMaxSize)82 TEST_F(GzipLogCompressorTest, EmptyStreamReasonableMaxSize) {
83   Init(std::make_unique<PerfectGzipEstimator::Factory>());
84 
85   auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes);
86   ASSERT_TRUE(compressor);
87 
88   std::string header;
89   compressor->CreateHeader(&header);
90 
91   std::string footer;
92   ASSERT_TRUE(compressor->CreateFooter(&footer));
93 
94   const std::string simulated_file = header + footer;
95   EXPECT_EQ(Decompress(simulated_file), std::string());
96 }
97 
TEST_F(GzipLogCompressorTest,EmptyStreamMinimalSize)98 TEST_F(GzipLogCompressorTest, EmptyStreamMinimalSize) {
99   Init(std::make_unique<PerfectGzipEstimator::Factory>());
100 
101   const size_t min_size = compressor_factory_->MinSizeBytes();
102   auto compressor = compressor_factory_->Create(min_size);
103   ASSERT_TRUE(compressor);
104 
105   std::string header;
106   compressor->CreateHeader(&header);
107 
108   std::string footer;
109   ASSERT_TRUE(compressor->CreateFooter(&footer));
110 
111   const std::string simulated_file = header + footer;
112   EXPECT_EQ(Decompress(simulated_file), std::string());
113 }
114 
TEST_F(GzipLogCompressorTest,SingleCallToCompress)115 TEST_F(GzipLogCompressorTest, SingleCallToCompress) {
116   Init(std::make_unique<PerfectGzipEstimator::Factory>());
117 
118   auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes);
119   ASSERT_TRUE(compressor);
120 
121   std::string header;
122   compressor->CreateHeader(&header);
123 
124   const std::string input = "Some random text.";
125   std::string log;
126   ASSERT_EQ(compressor->Compress(input, &log), OK);
127 
128   std::string footer;
129   ASSERT_TRUE(compressor->CreateFooter(&footer));
130 
131   const std::string simulated_file = header + log + footer;
132   EXPECT_EQ(Decompress(simulated_file), input);
133 }
134 
TEST_F(GzipLogCompressorTest,MultipleCallsToCompress)135 TEST_F(GzipLogCompressorTest, MultipleCallsToCompress) {
136   Init(std::make_unique<PerfectGzipEstimator::Factory>());
137 
138   auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes);
139   ASSERT_TRUE(compressor);
140 
141   std::string header;
142   compressor->CreateHeader(&header);
143 
144   const std::vector<std::string> inputs = {
145       "Some random text.",
146       "This text is also random. I give you my word for it. 100% random.",
147       "nejnnc pqmnx0981 mnl<D@ikjed90~~,z."};
148 
149   std::vector<std::string> logs(inputs.size());
150   for (size_t i = 0; i < inputs.size(); i++) {
151     ASSERT_EQ(compressor->Compress(inputs[i], &logs[i]), OK);
152   }
153 
154   std::string footer;
155   ASSERT_TRUE(compressor->CreateFooter(&footer));
156 
157   const auto input = std::accumulate(begin(inputs), end(inputs), std::string());
158   const auto log = std::accumulate(begin(logs), end(logs), std::string());
159 
160   const std::string simulated_file = header + log + footer;
161   EXPECT_EQ(Decompress(simulated_file), input);
162 }
163 
TEST_F(GzipLogCompressorTest,UnlimitedBudgetSanity)164 TEST_F(GzipLogCompressorTest, UnlimitedBudgetSanity) {
165   Init(std::make_unique<PerfectGzipEstimator::Factory>());
166 
167   auto compressor = compressor_factory_->Create(base::Optional<size_t>());
168   ASSERT_TRUE(compressor);
169 
170   std::string header;
171   compressor->CreateHeader(&header);
172 
173   const std::string input = "Some random text.";
174   std::string log;
175   ASSERT_EQ(compressor->Compress(input, &log), OK);
176 
177   std::string footer;
178   ASSERT_TRUE(compressor->CreateFooter(&footer));
179 
180   const std::string simulated_file = header + log + footer;
181   EXPECT_EQ(Decompress(simulated_file), input);
182 }
183 
184 // Test once with a big input, to provide coverage over inputs that could
185 // exceed the size of some local buffers in the UUT.
TEST_F(GzipLogCompressorTest,CompressionBigInput)186 TEST_F(GzipLogCompressorTest, CompressionBigInput) {
187   Init(std::make_unique<PerfectGzipEstimator::Factory>());
188 
189   auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes);
190   ASSERT_TRUE(compressor);
191 
192   std::string header;
193   compressor->CreateHeader(&header);
194 
195   constexpr size_t kRealisticSizeBytes = 1000 * 1000;
196   const std::string input = base::RandBytesAsString(kRealisticSizeBytes);
197   std::string log;
198   ASSERT_EQ(compressor->Compress(input, &log), OK);
199 
200   std::string footer;
201   ASSERT_TRUE(compressor->CreateFooter(&footer));
202 
203   const std::string simulated_file = header + log + footer;
204   EXPECT_EQ(Decompress(simulated_file), input);
205 }
206 
TEST_F(GzipLogCompressorTest,BudgetExceededByFirstCompressYieldsEmptyFile)207 TEST_F(GzipLogCompressorTest, BudgetExceededByFirstCompressYieldsEmptyFile) {
208   Init(std::make_unique<PerfectGzipEstimator::Factory>());
209 
210   const std::string input = "This won't fit.";
211 
212   auto compressor = compressor_factory_->Create(GzippedSize(input) - 1);
213   ASSERT_TRUE(compressor);
214 
215   std::string header;
216   compressor->CreateHeader(&header);
217 
218   // Focal point #1 - Compress() returns DISALLOWED.
219   std::string log;
220   EXPECT_EQ(compressor->Compress(input, &log), DISALLOWED);
221 
222   // Focal point #2 - CreateFooter() still succeeds;
223   std::string footer;
224   EXPECT_TRUE(compressor->CreateFooter(&footer));
225 
226   // Focal point #3 - the resulting log is parsable, and contains only those
227   // logs for which Compress() was successful.
228   // Note that |log| is not supposed to be written to the file, because
229   // Compress() has disallowed it.
230   const std::string simulated_file = header + footer;
231   EXPECT_EQ(Decompress(simulated_file), std::string());
232 }
233 
TEST_F(GzipLogCompressorTest,BudgetExceededByNonFirstCompressYieldsPartialFile)234 TEST_F(GzipLogCompressorTest,
235        BudgetExceededByNonFirstCompressYieldsPartialFile) {
236   Init(std::make_unique<PerfectGzipEstimator::Factory>());
237 
238   const std::string short_input = "short";
239   const std::string long_input = "A somewhat longer input string. @$%^&*()!!2";
240 
241   // Allocate enough budget that |short_input| would be produced, and not yet
242   // exhaust the budget, but |long_input| won't fit.
243   auto compressor = compressor_factory_->Create(GzippedSize(short_input) + 1);
244   ASSERT_TRUE(compressor);
245 
246   std::string header;
247   compressor->CreateHeader(&header);
248 
249   std::string short_log;
250   ASSERT_EQ(compressor->Compress(short_input, &short_log), OK);
251 
252   // Focal point #1 - Compress() returns DISALLOWED.
253   std::string long_log;
254   EXPECT_EQ(compressor->Compress(long_input, &long_log), DISALLOWED);
255   EXPECT_TRUE(long_log.empty());
256 
257   // Focal point #2 - CreateFooter() still succeeds;
258   std::string footer;
259   EXPECT_TRUE(compressor->CreateFooter(&footer));
260 
261   // Focal point #3 - the resulting log is parsable, and contains only those
262   // logs for which Compress() was successful.
263   // Note that |long_log| is not supposed to be written to the file, because
264   // Compress() has disallowed it.
265   const std::string simulated_file = header + short_log + footer;
266   EXPECT_EQ(Decompress(simulated_file), short_input);
267 }
268 
TEST_F(GzipLogCompressorTest,ExceedingBudgetDueToOverlyOptimisticEstimationYieldsError)269 TEST_F(GzipLogCompressorTest,
270        ExceedingBudgetDueToOverlyOptimisticEstimationYieldsError) {
271   // Use an estimator that will always be overly optimistic.
272   Init(std::make_unique<NullEstimator::Factory>());
273 
274   // Set a budget that will easily be exceeded.
275   auto compressor = compressor_factory_->Create(kGzipOverheadBytes + 5);
276   ASSERT_TRUE(compressor);
277 
278   std::string header;
279   compressor->CreateHeader(&header);
280 
281   // Prepare to compress an input that is guaranteed to exceed the budget.
282   const std::string input = "A string that would not fit in five bytes.";
283 
284   // The estimation allowed the compression, but then the compressed output
285   // ended up being over-budget.
286   std::string compressed;
287   EXPECT_EQ(compressor->Compress(input, &compressed), ERROR_ENCOUNTERED);
288   EXPECT_TRUE(compressed.empty());
289 }
290 
291 // Tests relevant to all LogFileWriter subclasses.
292 class LogFileWriterTest
293     : public ::testing::Test,
294       public ::testing::WithParamInterface<WebRtcEventLogCompression> {
295  public:
LogFileWriterTest()296   LogFileWriterTest() { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); }
297 
~LogFileWriterTest()298   ~LogFileWriterTest() override {}
299 
Init(WebRtcEventLogCompression compression)300   void Init(WebRtcEventLogCompression compression) {
301     DCHECK(!compression_.has_value()) << "Must only be called once.";
302     compression_ = compression;
303     log_file_writer_factory_ = CreateLogFileWriterFactory(compression);
304     path_ = temp_dir_.GetPath()
305                 .Append(FILE_PATH_LITERAL("arbitrary_filename"))
306                 .AddExtension(log_file_writer_factory_->Extension());
307   }
308 
CreateWriter(base::Optional<size_t> max_size)309   std::unique_ptr<LogFileWriter> CreateWriter(base::Optional<size_t> max_size) {
310     return log_file_writer_factory_->Create(path_, max_size);
311   }
312 
ExpectFileContents(const base::FilePath & file_path,const std::string & expected_contents)313   void ExpectFileContents(const base::FilePath& file_path,
314                           const std::string& expected_contents) {
315     DCHECK(compression_.has_value()) << "Must call Init().";
316 
317     std::string file_contents;
318     ASSERT_TRUE(base::ReadFileToString(file_path, &file_contents));
319 
320     switch (compression_.value()) {
321       case WebRtcEventLogCompression::NONE: {
322         EXPECT_EQ(file_contents, expected_contents);
323         break;
324       }
325       case WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION:
326       case WebRtcEventLogCompression::GZIP_NULL_ESTIMATION: {
327         std::string uncompressed;
328         ASSERT_TRUE(compression::GzipUncompress(file_contents, &uncompressed));
329         EXPECT_EQ(uncompressed, expected_contents);
330         break;
331       }
332       default: { NOTREACHED(); }
333     }
334   }
335 
336   base::test::TaskEnvironment task_environment_;
337   base::Optional<WebRtcEventLogCompression> compression_;  // Set in Init().
338   base::ScopedTempDir temp_dir_;
339   base::FilePath path_;
340   std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory_;
341 };
342 
TEST_P(LogFileWriterTest,FactoryCreatesLogFileWriter)343 TEST_P(LogFileWriterTest, FactoryCreatesLogFileWriter) {
344   Init(GetParam());
345   EXPECT_TRUE(CreateWriter(log_file_writer_factory_->MinFileSizeBytes()));
346 }
347 
348 #if defined(OS_POSIX)
TEST_P(LogFileWriterTest,FactoryReturnsEmptyUniquePtrIfCantCreateFile)349 TEST_P(LogFileWriterTest, FactoryReturnsEmptyUniquePtrIfCantCreateFile) {
350   Init(GetParam());
351   RemoveWritePermissions(temp_dir_.GetPath());
352   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
353   EXPECT_FALSE(writer);
354 }
355 #endif  // defined(OS_POSIX)
356 
TEST_P(LogFileWriterTest,CloseSucceedsWhenNoErrorsOccurred)357 TEST_P(LogFileWriterTest, CloseSucceedsWhenNoErrorsOccurred) {
358   Init(GetParam());
359 
360   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
361   ASSERT_TRUE(writer);
362 
363   EXPECT_TRUE(writer->Close());
364 }
365 
366 // Other tests check check the case of compression where the estimation is
367 // close to the file's capacity, reaches or exceeds it.
TEST_P(LogFileWriterTest,CallToWriteSuccedsWhenCapacityFarOff)368 TEST_P(LogFileWriterTest, CallToWriteSuccedsWhenCapacityFarOff) {
369   Init(GetParam());
370 
371   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
372   ASSERT_TRUE(writer);
373 
374   const std::string log = "log";
375   EXPECT_TRUE(writer->Write(log));
376 
377   ASSERT_TRUE(writer->Close());
378   ExpectFileContents(path_, log);
379 }
380 
TEST_P(LogFileWriterTest,CallToWriteWithEmptyStringSucceeds)381 TEST_P(LogFileWriterTest, CallToWriteWithEmptyStringSucceeds) {
382   Init(GetParam());
383 
384   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
385   ASSERT_TRUE(writer);
386 
387   const std::string log;
388   EXPECT_TRUE(writer->Write(log));
389 
390   ASSERT_TRUE(writer->Close());
391   ExpectFileContents(path_, log);
392 }
393 
TEST_P(LogFileWriterTest,UnlimitedBudgetSanity)394 TEST_P(LogFileWriterTest, UnlimitedBudgetSanity) {
395   Init(GetParam());
396 
397   auto writer = CreateWriter(base::Optional<size_t>());
398   ASSERT_TRUE(writer);
399 
400   const std::string log = "log";
401   EXPECT_TRUE(writer->Write(log));
402 
403   ASSERT_TRUE(writer->Close());
404   ExpectFileContents(path_, log);
405 }
406 
TEST_P(LogFileWriterTest,DeleteRemovesUnclosedFile)407 TEST_P(LogFileWriterTest, DeleteRemovesUnclosedFile) {
408   Init(GetParam());
409 
410   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
411   ASSERT_TRUE(writer);
412 
413   writer->Delete();
414   EXPECT_FALSE(base::PathExists(path_));
415 }
416 
TEST_P(LogFileWriterTest,DeleteRemovesClosedFile)417 TEST_P(LogFileWriterTest, DeleteRemovesClosedFile) {
418   Init(GetParam());
419 
420   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
421   ASSERT_TRUE(writer);
422 
423   EXPECT_TRUE(writer->Close());
424 
425   writer->Delete();
426   EXPECT_FALSE(base::PathExists(path_));
427 }
428 
429 #if !defined(OS_WIN)  // Deleting the open file does not work on Windows.
TEST_P(LogFileWriterTest,WriteDoesNotCrashIfFileRemovedExternally)430 TEST_P(LogFileWriterTest, WriteDoesNotCrashIfFileRemovedExternally) {
431   Init(GetParam());
432 
433   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
434   ASSERT_TRUE(writer);
435 
436   ASSERT_TRUE(base::DeleteFile(path_));
437   ASSERT_FALSE(base::PathExists(path_));  // Sanity on the test itself.
438 
439   // It's up to the OS whether this will succeed or fail, but it must not crash.
440   writer->Write("log");
441 }
442 
TEST_P(LogFileWriterTest,CloseDoesNotCrashIfFileRemovedExternally)443 TEST_P(LogFileWriterTest, CloseDoesNotCrashIfFileRemovedExternally) {
444   Init(GetParam());
445 
446   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
447   ASSERT_TRUE(writer);
448 
449   ASSERT_TRUE(base::DeleteFile(path_));
450   ASSERT_FALSE(base::PathExists(path_));  // Sanity on the test itself.
451 
452   // It's up to the OS whether this will succeed or fail, but it must not crash.
453   writer->Close();
454 }
455 
TEST_P(LogFileWriterTest,DeleteDoesNotCrashIfFileRemovedExternally)456 TEST_P(LogFileWriterTest, DeleteDoesNotCrashIfFileRemovedExternally) {
457   Init(GetParam());
458 
459   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
460   ASSERT_TRUE(writer);
461 
462   ASSERT_TRUE(base::DeleteFile(path_));
463   ASSERT_FALSE(base::PathExists(path_));  // Sanity on the test itself.
464 
465   // It's up to the OS whether this will succeed or fail, but it must not crash.
466   writer->Delete();
467 }
468 #endif  // !defined(OS_WIN)
469 
TEST_P(LogFileWriterTest,PathReturnsTheCorrectPath)470 TEST_P(LogFileWriterTest, PathReturnsTheCorrectPath) {
471   Init(GetParam());
472 
473   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
474   ASSERT_TRUE(writer);
475 
476   ASSERT_EQ(writer->path(), path_);
477 }
478 
479 INSTANTIATE_TEST_SUITE_P(
480     Compression,
481     LogFileWriterTest,
482     ::testing::Values(WebRtcEventLogCompression::NONE,
483                       WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION));
484 
485 // Tests for UncompressedLogFileWriterTest only.
486 class UncompressedLogFileWriterTest : public LogFileWriterTest {
487  public:
488   ~UncompressedLogFileWriterTest() override = default;
489 };
490 
TEST_F(UncompressedLogFileWriterTest,MaxSizeReachedReturnsFalseWhenMaxNotReached)491 TEST_F(UncompressedLogFileWriterTest,
492        MaxSizeReachedReturnsFalseWhenMaxNotReached) {
493   Init(WebRtcEventLogCompression::NONE);
494 
495   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
496   ASSERT_TRUE(writer);
497 
498   const std::string log = "log";
499   ASSERT_TRUE(writer->Write(log));
500 
501   EXPECT_FALSE(writer->MaxSizeReached());
502 }
503 
TEST_F(UncompressedLogFileWriterTest,MaxSizeReachedReturnsTrueWhenMaxReached)504 TEST_F(UncompressedLogFileWriterTest, MaxSizeReachedReturnsTrueWhenMaxReached) {
505   Init(WebRtcEventLogCompression::NONE);
506 
507   const std::string log = "log";
508 
509   auto writer = CreateWriter(log.size());
510   ASSERT_TRUE(writer);
511 
512   ASSERT_TRUE(writer->Write(log));  // (CallToWriteSuccedsWhenCapacityReached)
513 
514   EXPECT_TRUE(writer->MaxSizeReached());
515 }
516 
TEST_F(UncompressedLogFileWriterTest,CallToWriteSuccedsWhenCapacityReached)517 TEST_F(UncompressedLogFileWriterTest, CallToWriteSuccedsWhenCapacityReached) {
518   Init(WebRtcEventLogCompression::NONE);
519 
520   const std::string log = "log";
521 
522   auto writer = CreateWriter(log.size());
523   ASSERT_TRUE(writer);
524 
525   EXPECT_TRUE(writer->Write(log));
526 
527   ASSERT_TRUE(writer->Close());
528   ExpectFileContents(path_, log);
529 }
530 
TEST_F(UncompressedLogFileWriterTest,CallToWriteFailsWhenCapacityExceeded)531 TEST_F(UncompressedLogFileWriterTest, CallToWriteFailsWhenCapacityExceeded) {
532   Init(WebRtcEventLogCompression::NONE);
533 
534   const std::string log = "log";
535 
536   auto writer = CreateWriter(log.size() - 1);
537   ASSERT_TRUE(writer);
538 
539   EXPECT_FALSE(writer->Write(log));
540 
541   ASSERT_TRUE(writer->Close());
542   ExpectFileContents(path_, std::string());
543 }
544 
TEST_F(UncompressedLogFileWriterTest,WriteCompleteMessagesOnly)545 TEST_F(UncompressedLogFileWriterTest, WriteCompleteMessagesOnly) {
546   Init(WebRtcEventLogCompression::NONE);
547 
548   const std::string log1 = "01234";
549   const std::string log2 = "56789";
550 
551   auto writer = CreateWriter(log1.size() + log2.size() - 1);
552   ASSERT_TRUE(writer);
553 
554   EXPECT_TRUE(writer->Write(log1));
555 
556   EXPECT_FALSE(writer->Write(log2));
557 
558   ASSERT_TRUE(writer->Close());
559   ExpectFileContents(path_, log1);
560 }
561 
562 // Tests for GzippedLogFileWriterTest only.
563 class GzippedLogFileWriterTest : public LogFileWriterTest {
564  public:
565   ~GzippedLogFileWriterTest() override = default;
566 };
567 
TEST_F(GzippedLogFileWriterTest,FactoryDeletesFileIfMaxSizeBelowMin)568 TEST_F(GzippedLogFileWriterTest, FactoryDeletesFileIfMaxSizeBelowMin) {
569   Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION);
570 
571   const size_t min_size = log_file_writer_factory_->MinFileSizeBytes();
572   ASSERT_GE(min_size, 1u);
573 
574   auto writer = CreateWriter(min_size - 1);
575   ASSERT_FALSE(writer);
576 
577   EXPECT_FALSE(base::PathExists(path_));
578 }
579 
TEST_F(GzippedLogFileWriterTest,MaxSizeReachedReturnsFalseWhenMaxNotReached)580 TEST_F(GzippedLogFileWriterTest, MaxSizeReachedReturnsFalseWhenMaxNotReached) {
581   Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION);
582 
583   auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes);
584   ASSERT_TRUE(writer);
585 
586   const std::string log = "log";
587   ASSERT_TRUE(writer->Write(log));
588   EXPECT_FALSE(writer->MaxSizeReached());
589 }
590 
TEST_F(GzippedLogFileWriterTest,MaxSizeReachedReturnsTrueWhenMaxReached)591 TEST_F(GzippedLogFileWriterTest, MaxSizeReachedReturnsTrueWhenMaxReached) {
592   // By using a 0 estimation, we allow the compressor to keep going to
593   // the point of budget saturation.
594   Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION);
595 
596   const std::string log = "log";
597 
598   auto writer = CreateWriter(GzippedSize(log));
599   ASSERT_TRUE(writer);
600 
601   ASSERT_TRUE(writer->Write(log));  // (CallToWriteSuccedsWhenCapacityReached)
602   EXPECT_TRUE(writer->MaxSizeReached());
603 }
604 
TEST_F(GzippedLogFileWriterTest,CallToWriteSuccedsWhenCapacityReached)605 TEST_F(GzippedLogFileWriterTest, CallToWriteSuccedsWhenCapacityReached) {
606   Init(WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION);
607 
608   const std::string log = "log";
609 
610   auto writer = CreateWriter(GzippedSize(log));
611   ASSERT_TRUE(writer);
612 
613   EXPECT_TRUE(writer->Write(log));
614 
615   ASSERT_TRUE(writer->Close());
616   ExpectFileContents(path_, log);
617 }
618 
619 // Also tests the scenario WriteCompleteMessagesOnly.
TEST_F(GzippedLogFileWriterTest,CallToWriteFailsWhenCapacityWouldBeExceededButEstimationPreventedWrite)620 TEST_F(GzippedLogFileWriterTest,
621        CallToWriteFailsWhenCapacityWouldBeExceededButEstimationPreventedWrite) {
622   Init(WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION);
623 
624   const std::string log1 = "abcde";
625   const std::string log2 = "fghij";
626   const std::vector<std::string> logs = {log1, log2};
627 
628   // Find out the size necessary for compressing log1 and log2 in two calls.
629   const size_t compressed_len = GzippedSize(logs);  // Vector version.
630 
631   auto writer = CreateWriter(compressed_len - 1);
632   ASSERT_TRUE(writer);
633 
634   ASSERT_TRUE(writer->Write(log1));
635 
636   EXPECT_FALSE(writer->Write(log2));
637 
638   // The second write was succesfully prevented; no error should have occurred,
639   // and it should be possible to produce a meaningful gzipped log file.
640   EXPECT_TRUE(writer->Close());
641 
642   ExpectFileContents(path_, log1);  // Only the in-budget part was written.
643 }
644 
645 // This tests the case when the estimation fails to warn us of a pending
646 // over-budget write, which leaves us unable to produce a valid compression
647 // footer for the truncated file. This forces us to discard the file.
TEST_F(GzippedLogFileWriterTest,CallToWriteFailsWhenCapacityExceededDespiteEstimationAllowingIt)648 TEST_F(GzippedLogFileWriterTest,
649        CallToWriteFailsWhenCapacityExceededDespiteEstimationAllowingIt) {
650   // By using a 0 estimation, we allow the compressor to keep going to
651   // the point of budget saturation.
652   Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION);
653 
654   const std::string log = "log";
655 
656   auto writer = CreateWriter(GzippedSize(log) - 1);
657   ASSERT_TRUE(writer);
658 
659   EXPECT_FALSE(writer->Write(log));
660 
661   EXPECT_FALSE(writer->Close());
662   EXPECT_FALSE(base::PathExists(path_));  // Errored files deleted by Close().
663 }
664 
665 #if defined(OS_CHROMEOS)
666 
667 struct DoesProfileDefaultToLoggingEnabledForUserTypeTestCase {
668   user_manager::UserType user_type;
669   bool defaults_to_logging_enabled;
670 };
671 
672 class DoesProfileDefaultToLoggingEnabledForUserTypeParametrizedTest
673     : public ::testing::TestWithParam<
674           DoesProfileDefaultToLoggingEnabledForUserTypeTestCase> {
675  protected:
676   content::BrowserTaskEnvironment task_environment_;
677 };
678 
TEST_P(DoesProfileDefaultToLoggingEnabledForUserTypeParametrizedTest,WebRtcPolicyDefaultTest)679 TEST_P(DoesProfileDefaultToLoggingEnabledForUserTypeParametrizedTest,
680        WebRtcPolicyDefaultTest) {
681   DoesProfileDefaultToLoggingEnabledForUserTypeTestCase test_case = GetParam();
682 
683   TestingProfile::Builder profile_builder;
684   profile_builder.OverridePolicyConnectorIsManagedForTesting(true);
685   std::unique_ptr<TestingProfile> testing_profile = profile_builder.Build();
686   std::unique_ptr<testing::NiceMock<chromeos::FakeChromeUserManager>>
687       fake_user_manager_ = std::make_unique<
688           testing::NiceMock<chromeos::FakeChromeUserManager>>();
689   // We use a standard Gaia account by default:
690   AccountId account_id = AccountId::FromUserEmailGaiaId("name", "id");
691 
692   switch (test_case.user_type) {
693     case user_manager::USER_TYPE_REGULAR:
694       fake_user_manager_->AddUserWithAffiliationAndTypeAndProfile(
695           account_id, false, test_case.user_type, testing_profile.get());
696       break;
697     case user_manager::USER_TYPE_GUEST:
698       account_id = fake_user_manager_->GetGuestAccountId();
699       fake_user_manager_->AddGuestUser();
700       break;
701     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
702       fake_user_manager_->AddPublicAccountUser(account_id);
703       break;
704     case user_manager::USER_TYPE_KIOSK_APP:
705       fake_user_manager_->AddKioskAppUser(account_id);
706       break;
707     case user_manager::USER_TYPE_CHILD:
708       fake_user_manager_->AddChildUser(account_id);
709       break;
710     case user_manager::USER_TYPE_ARC_KIOSK_APP:
711       fake_user_manager_->AddArcKioskAppUser(account_id);
712       break;
713     case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
714       account_id = AccountId::AdFromObjGuid("guid");
715       fake_user_manager_->AddUserWithAffiliationAndTypeAndProfile(
716           account_id, false, test_case.user_type, testing_profile.get());
717       break;
718     default:
719       FAIL() << "Invalid test setup. Unexpected user type.";
720       break;
721   }
722 
723   fake_user_manager_->LoginUser(account_id);
724   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_ =
725       std::make_unique<user_manager::ScopedUserManager>(
726           std::move(fake_user_manager_));
727 
728   EXPECT_EQ(DoesProfileDefaultToLoggingEnabled(testing_profile.get()),
729             test_case.defaults_to_logging_enabled);
730 }
731 
732 INSTANTIATE_TEST_CASE_P(
733     WebRtcPolicyDefaultTests,
734     DoesProfileDefaultToLoggingEnabledForUserTypeParametrizedTest,
735     testing::ValuesIn(
736         std::vector<DoesProfileDefaultToLoggingEnabledForUserTypeTestCase>{
737             {user_manager::USER_TYPE_REGULAR, true},
738             {user_manager::USER_TYPE_GUEST, false},
739             {user_manager::USER_TYPE_PUBLIC_ACCOUNT, false},
740             {user_manager::USER_TYPE_KIOSK_APP, false},
741             {user_manager::USER_TYPE_CHILD, false},
742             {user_manager::USER_TYPE_ARC_KIOSK_APP, false},
743             {user_manager::USER_TYPE_ACTIVE_DIRECTORY, false}}));
744 
745 #endif  // defined(OS_CHROMEOS)
746 
747 }  // namespace webrtc_event_logging
748