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