| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h" |
| |
| #include <memory> |
| #include <numeric> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/optional.h" |
| #include "base/rand_util.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_unittest_helpers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/zlib/google/compression_utils.h" |
| |
| namespace webrtc_event_logging { |
| |
| namespace { |
| constexpr LogCompressor::Result OK = LogCompressor::Result::OK; |
| constexpr LogCompressor::Result DISALLOWED = LogCompressor::Result::DISALLOWED; |
| constexpr LogCompressor::Result ERROR_ENCOUNTERED = |
| LogCompressor::Result::ERROR_ENCOUNTERED; |
| } // namespace |
| |
| // Tests for GzipLogCompressor. |
| // Note that these tests may not use GzippedSize(), or they would be assuming |
| // what they set out to prove. (Subsequent tests may use it, though.) |
| class GzipLogCompressorTest : public ::testing::Test { |
| public: |
| ~GzipLogCompressorTest() override = default; |
| |
| void Init( |
| std::unique_ptr<CompressedSizeEstimator::Factory> estimator_factory) { |
| DCHECK(!compressor_factory_); |
| DCHECK(estimator_factory); |
| compressor_factory_ = std::make_unique<GzipLogCompressorFactory>( |
| std::move(estimator_factory)); |
| } |
| |
| std::string Decompress(const std::string& input) { |
| std::string output; |
| EXPECT_TRUE(compression::GzipUncompress(input, &output)); |
| return output; |
| } |
| |
| std::unique_ptr<GzipLogCompressorFactory> compressor_factory_; |
| }; |
| |
| TEST_F(GzipLogCompressorTest, |
| GzipLogCompressorFactoryCreatesCompressorIfMinimalSizeOrAbove) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| const size_t min_size = compressor_factory_->MinSizeBytes(); |
| auto compressor = compressor_factory_->Create(min_size); |
| EXPECT_TRUE(compressor); |
| } |
| |
| TEST_F(GzipLogCompressorTest, |
| GzipLogCompressorFactoryDoesNotCreateCompressorIfBelowMinimalSize) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| const size_t min_size = compressor_factory_->MinSizeBytes(); |
| ASSERT_GE(min_size, 1u); |
| auto compressor = compressor_factory_->Create(min_size - 1); |
| EXPECT_FALSE(compressor); |
| } |
| |
| TEST_F(GzipLogCompressorTest, EmptyStreamReasonableMaxSize) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const std::string simulated_file = header + footer; |
| EXPECT_EQ(Decompress(simulated_file), std::string()); |
| } |
| |
| TEST_F(GzipLogCompressorTest, EmptyStreamMinimalSize) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| const size_t min_size = compressor_factory_->MinSizeBytes(); |
| auto compressor = compressor_factory_->Create(min_size); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const std::string simulated_file = header + footer; |
| EXPECT_EQ(Decompress(simulated_file), std::string()); |
| } |
| |
| TEST_F(GzipLogCompressorTest, SingleCallToCompress) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| const std::string input = "Some random text."; |
| std::string log; |
| ASSERT_EQ(compressor->Compress(input, &log), OK); |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const std::string simulated_file = header + log + footer; |
| EXPECT_EQ(Decompress(simulated_file), input); |
| } |
| |
| TEST_F(GzipLogCompressorTest, MultipleCallsToCompress) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| const std::vector<std::string> inputs = { |
| "Some random text.", |
| "This text is also random. I give you my word for it. 100% random.", |
| "nejnnc pqmnx0981 mnl<D@ikjed90~~,z."}; |
| |
| std::vector<std::string> logs(inputs.size()); |
| for (size_t i = 0; i < inputs.size(); i++) { |
| ASSERT_EQ(compressor->Compress(inputs[i], &logs[i]), OK); |
| } |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const auto input = std::accumulate(begin(inputs), end(inputs), std::string()); |
| const auto log = std::accumulate(begin(logs), end(logs), std::string()); |
| |
| const std::string simulated_file = header + log + footer; |
| EXPECT_EQ(Decompress(simulated_file), input); |
| } |
| |
| TEST_F(GzipLogCompressorTest, UnlimitedBudgetSanity) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| auto compressor = compressor_factory_->Create(base::Optional<size_t>()); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| const std::string input = "Some random text."; |
| std::string log; |
| ASSERT_EQ(compressor->Compress(input, &log), OK); |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const std::string simulated_file = header + log + footer; |
| EXPECT_EQ(Decompress(simulated_file), input); |
| } |
| |
| // Test once with a big input, to provide coverage over inputs that could |
| // exceed the size of some local buffers in the UUT. |
| TEST_F(GzipLogCompressorTest, CompressionBigInput) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| auto compressor = compressor_factory_->Create(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| constexpr size_t kRealisticSizeBytes = 1000 * 1000; |
| const std::string input = base::RandBytesAsString(kRealisticSizeBytes); |
| std::string log; |
| ASSERT_EQ(compressor->Compress(input, &log), OK); |
| |
| std::string footer; |
| ASSERT_TRUE(compressor->CreateFooter(&footer)); |
| |
| const std::string simulated_file = header + log + footer; |
| EXPECT_EQ(Decompress(simulated_file), input); |
| } |
| |
| TEST_F(GzipLogCompressorTest, BudgetExceededByFirstCompressYieldsEmptyFile) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| const std::string input = "This won't fit."; |
| |
| auto compressor = compressor_factory_->Create(GzippedSize(input) - 1); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| // Focal point #1 - Compress() returns DISALLOWED. |
| std::string log; |
| EXPECT_EQ(compressor->Compress(input, &log), DISALLOWED); |
| |
| // Focal point #2 - CreateFooter() still succeeds; |
| std::string footer; |
| EXPECT_TRUE(compressor->CreateFooter(&footer)); |
| |
| // Focal point #3 - the resulting log is parsable, and contains only those |
| // logs for which Compress() was successful. |
| // Note that |log| is not supposed to be written to the file, because |
| // Compress() has disallowed it. |
| const std::string simulated_file = header + footer; |
| EXPECT_EQ(Decompress(simulated_file), std::string()); |
| } |
| |
| TEST_F(GzipLogCompressorTest, |
| BudgetExceededByNonFirstCompressYieldsPartialFile) { |
| Init(std::make_unique<PerfectGzipEstimator::Factory>()); |
| |
| const std::string short_input = "short"; |
| const std::string long_input = "A somewhat longer input string. @$%^&*()!!2"; |
| |
| // Allocate enough budget that |short_input| would be produced, and not yet |
| // exhaust the budget, but |long_input| won't fit. |
| auto compressor = compressor_factory_->Create(GzippedSize(short_input) + 1); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| std::string short_log; |
| ASSERT_EQ(compressor->Compress(short_input, &short_log), OK); |
| |
| // Focal point #1 - Compress() returns DISALLOWED. |
| std::string long_log; |
| EXPECT_EQ(compressor->Compress(long_input, &long_log), DISALLOWED); |
| EXPECT_TRUE(long_log.empty()); |
| |
| // Focal point #2 - CreateFooter() still succeeds; |
| std::string footer; |
| EXPECT_TRUE(compressor->CreateFooter(&footer)); |
| |
| // Focal point #3 - the resulting log is parsable, and contains only those |
| // logs for which Compress() was successful. |
| // Note that |long_log| is not supposed to be written to the file, because |
| // Compress() has disallowed it. |
| const std::string simulated_file = header + short_log + footer; |
| EXPECT_EQ(Decompress(simulated_file), short_input); |
| } |
| |
| TEST_F(GzipLogCompressorTest, |
| ExceedingBudgetDueToOverlyOptimisticEstimationYieldsError) { |
| // Use an estimator that will always be overly optimistic. |
| Init(std::make_unique<NullEstimator::Factory>()); |
| |
| // Set a budget that will easily be exceeded. |
| auto compressor = compressor_factory_->Create(kGzipOverheadBytes + 5); |
| ASSERT_TRUE(compressor); |
| |
| std::string header; |
| compressor->CreateHeader(&header); |
| |
| // Prepare to compress an input that is guaranteed to exceed the budget. |
| const std::string input = "A string that would not fit in five bytes."; |
| |
| // The estimation allowed the compression, but then the compressed output |
| // ended up being over-budget. |
| std::string compressed; |
| EXPECT_EQ(compressor->Compress(input, &compressed), ERROR_ENCOUNTERED); |
| EXPECT_TRUE(compressed.empty()); |
| } |
| |
| // Tests relevant to all LogFileWriter subclasses. |
| class LogFileWriterTest |
| : public ::testing::Test, |
| public ::testing::WithParamInterface<WebRtcEventLogCompression> { |
| public: |
| LogFileWriterTest() { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); } |
| |
| ~LogFileWriterTest() override {} |
| |
| void Init(WebRtcEventLogCompression compression) { |
| DCHECK(!compression_.has_value()) << "Must only be called once."; |
| compression_ = compression; |
| log_file_writer_factory_ = CreateLogFileWriterFactory(compression); |
| path_ = temp_dir_.GetPath() |
| .Append(FILE_PATH_LITERAL("arbitrary_filename")) |
| .AddExtension(log_file_writer_factory_->Extension()); |
| } |
| |
| std::unique_ptr<LogFileWriter> CreateWriter(base::Optional<size_t> max_size) { |
| return log_file_writer_factory_->Create(path_, max_size); |
| } |
| |
| void ExpectFileContents(const base::FilePath& file_path, |
| const std::string& expected_contents) { |
| DCHECK(compression_.has_value()) << "Must call Init()."; |
| |
| std::string file_contents; |
| ASSERT_TRUE(base::ReadFileToString(file_path, &file_contents)); |
| |
| switch (compression_.value()) { |
| case WebRtcEventLogCompression::NONE: { |
| EXPECT_EQ(file_contents, expected_contents); |
| break; |
| } |
| case WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION: |
| case WebRtcEventLogCompression::GZIP_NULL_ESTIMATION: { |
| std::string uncompressed; |
| ASSERT_TRUE(compression::GzipUncompress(file_contents, &uncompressed)); |
| EXPECT_EQ(uncompressed, expected_contents); |
| break; |
| } |
| default: { NOTREACHED(); } |
| } |
| } |
| |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| base::Optional<WebRtcEventLogCompression> compression_; // Set in Init(). |
| base::ScopedTempDir temp_dir_; |
| base::FilePath path_; |
| std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory_; |
| }; |
| |
| TEST_P(LogFileWriterTest, FactoryCreatesLogFileWriter) { |
| Init(GetParam()); |
| EXPECT_TRUE(CreateWriter(log_file_writer_factory_->MinFileSizeBytes())); |
| } |
| |
| #if defined(OS_POSIX) |
| TEST_P(LogFileWriterTest, FactoryReturnsEmptyUniquePtrIfCantCreateFile) { |
| Init(GetParam()); |
| RemoveWritePermissions(temp_dir_.GetPath()); |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| EXPECT_FALSE(writer); |
| } |
| #endif // defined(OS_POSIX) |
| |
| TEST_P(LogFileWriterTest, CloseSucceedsWhenNoErrorsOccurred) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_TRUE(writer->Close()); |
| } |
| |
| // Other tests check check the case of compression where the estimation is |
| // close to the file's capacity, reaches or exceeds it. |
| TEST_P(LogFileWriterTest, CallToWriteSuccedsWhenCapacityFarOff) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| const std::string log = "log"; |
| EXPECT_TRUE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log); |
| } |
| |
| TEST_P(LogFileWriterTest, CallToWriteWithEmptyStringSucceeds) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| const std::string log = ""; |
| EXPECT_TRUE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log); |
| } |
| |
| TEST_P(LogFileWriterTest, UnlimitedBudgetSanity) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(base::Optional<size_t>()); |
| ASSERT_TRUE(writer); |
| |
| const std::string log = "log"; |
| EXPECT_TRUE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log); |
| } |
| |
| TEST_P(LogFileWriterTest, DeleteRemovesUnclosedFile) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| writer->Delete(); |
| EXPECT_FALSE(base::PathExists(path_)); |
| } |
| |
| TEST_P(LogFileWriterTest, DeleteRemovesClosedFile) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_TRUE(writer->Close()); |
| |
| writer->Delete(); |
| EXPECT_FALSE(base::PathExists(path_)); |
| } |
| |
| #if !defined(OS_WIN) // Deleting the open file does not work on Windows. |
| TEST_P(LogFileWriterTest, WriteDoesNotCrashIfFileRemovedExternally) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(base::DeleteFile(path_, /*recursive=*/false)); |
| ASSERT_FALSE(base::PathExists(path_)); // Sanity on the test itself. |
| |
| // It's up to the OS whether this will succeed or fail, but it must not crash. |
| writer->Write("log"); |
| } |
| |
| TEST_P(LogFileWriterTest, CloseDoesNotCrashIfFileRemovedExternally) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(base::DeleteFile(path_, /*recursive=*/false)); |
| ASSERT_FALSE(base::PathExists(path_)); // Sanity on the test itself. |
| |
| // It's up to the OS whether this will succeed or fail, but it must not crash. |
| writer->Close(); |
| } |
| |
| TEST_P(LogFileWriterTest, DeleteDoesNotCrashIfFileRemovedExternally) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(base::DeleteFile(path_, /*recursive=*/false)); |
| ASSERT_FALSE(base::PathExists(path_)); // Sanity on the test itself. |
| |
| // It's up to the OS whether this will succeed or fail, but it must not crash. |
| writer->Delete(); |
| } |
| #endif // !defined(OS_WIN) |
| |
| TEST_P(LogFileWriterTest, PathReturnsTheCorrectPath) { |
| Init(GetParam()); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_EQ(writer->path(), path_); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| Compression, |
| LogFileWriterTest, |
| ::testing::Values(WebRtcEventLogCompression::NONE, |
| WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION)); |
| |
| // Tests for UncompressedLogFileWriterTest only. |
| class UncompressedLogFileWriterTest : public LogFileWriterTest { |
| public: |
| ~UncompressedLogFileWriterTest() override = default; |
| }; |
| |
| TEST_F(UncompressedLogFileWriterTest, |
| MaxSizeReachedReturnsFalseWhenMaxNotReached) { |
| Init(WebRtcEventLogCompression::NONE); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| const std::string log = "log"; |
| ASSERT_TRUE(writer->Write(log)); |
| |
| EXPECT_FALSE(writer->MaxSizeReached()); |
| } |
| |
| TEST_F(UncompressedLogFileWriterTest, MaxSizeReachedReturnsTrueWhenMaxReached) { |
| Init(WebRtcEventLogCompression::NONE); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(log.size()); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(writer->Write(log)); // (CallToWriteSuccedsWhenCapacityReached) |
| |
| EXPECT_TRUE(writer->MaxSizeReached()); |
| } |
| |
| TEST_F(UncompressedLogFileWriterTest, CallToWriteSuccedsWhenCapacityReached) { |
| Init(WebRtcEventLogCompression::NONE); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(log.size()); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_TRUE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log); |
| } |
| |
| TEST_F(UncompressedLogFileWriterTest, CallToWriteFailsWhenCapacityExceeded) { |
| Init(WebRtcEventLogCompression::NONE); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(log.size() - 1); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_FALSE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, std::string()); |
| } |
| |
| TEST_F(UncompressedLogFileWriterTest, WriteCompleteMessagesOnly) { |
| Init(WebRtcEventLogCompression::NONE); |
| |
| const std::string log1 = "01234"; |
| const std::string log2 = "56789"; |
| |
| auto writer = CreateWriter(log1.size() + log2.size() - 1); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_TRUE(writer->Write(log1)); |
| |
| EXPECT_FALSE(writer->Write(log2)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log1); |
| } |
| |
| // Tests for GzippedLogFileWriterTest only. |
| class GzippedLogFileWriterTest : public LogFileWriterTest { |
| public: |
| ~GzippedLogFileWriterTest() override = default; |
| }; |
| |
| TEST_F(GzippedLogFileWriterTest, FactoryDeletesFileIfMaxSizeBelowMin) { |
| Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION); |
| |
| const size_t min_size = log_file_writer_factory_->MinFileSizeBytes(); |
| ASSERT_GE(min_size, 1u); |
| |
| auto writer = CreateWriter(min_size - 1); |
| ASSERT_FALSE(writer); |
| |
| EXPECT_FALSE(base::PathExists(path_)); |
| } |
| |
| TEST_F(GzippedLogFileWriterTest, MaxSizeReachedReturnsFalseWhenMaxNotReached) { |
| Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION); |
| |
| auto writer = CreateWriter(kMaxRemoteLogFileSizeBytes); |
| ASSERT_TRUE(writer); |
| |
| const std::string log = "log"; |
| ASSERT_TRUE(writer->Write(log)); |
| EXPECT_FALSE(writer->MaxSizeReached()); |
| } |
| |
| TEST_F(GzippedLogFileWriterTest, MaxSizeReachedReturnsTrueWhenMaxReached) { |
| // By using a 0 estimation, we allow the compressor to keep going to |
| // the point of budget saturation. |
| Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(GzippedSize(log)); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(writer->Write(log)); // (CallToWriteSuccedsWhenCapacityReached) |
| EXPECT_TRUE(writer->MaxSizeReached()); |
| } |
| |
| TEST_F(GzippedLogFileWriterTest, CallToWriteSuccedsWhenCapacityReached) { |
| Init(WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(GzippedSize(log)); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_TRUE(writer->Write(log)); |
| |
| ASSERT_TRUE(writer->Close()); |
| ExpectFileContents(path_, log); |
| } |
| |
| // Also tests the scenario WriteCompleteMessagesOnly. |
| TEST_F(GzippedLogFileWriterTest, |
| CallToWriteFailsWhenCapacityWouldBeExceededButEstimationPreventedWrite) { |
| Init(WebRtcEventLogCompression::GZIP_PERFECT_ESTIMATION); |
| |
| const std::string log1 = "abcde"; |
| const std::string log2 = "fghij"; |
| const std::vector<std::string> logs = {log1, log2}; |
| |
| // Find out the size necessary for compressing log1 and log2 in two calls. |
| const size_t compressed_len = GzippedSize(logs); // Vector version. |
| |
| auto writer = CreateWriter(compressed_len - 1); |
| ASSERT_TRUE(writer); |
| |
| ASSERT_TRUE(writer->Write(log1)); |
| |
| EXPECT_FALSE(writer->Write(log2)); |
| |
| // The second write was succesfully prevented; no error should have occurred, |
| // and it should be possible to produce a meaningful gzipped log file. |
| EXPECT_TRUE(writer->Close()); |
| |
| ExpectFileContents(path_, log1); // Only the in-budget part was written. |
| } |
| |
| // This tests the case when the estimation fails to warn us of a pending |
| // over-budget write, which leaves us unable to produce a valid compression |
| // footer for the truncated file. This forces us to discard the file. |
| TEST_F(GzippedLogFileWriterTest, |
| CallToWriteFailsWhenCapacityExceededDespiteEstimationAllowingIt) { |
| // By using a 0 estimation, we allow the compressor to keep going to |
| // the point of budget saturation. |
| Init(WebRtcEventLogCompression::GZIP_NULL_ESTIMATION); |
| |
| const std::string log = "log"; |
| |
| auto writer = CreateWriter(GzippedSize(log) - 1); |
| ASSERT_TRUE(writer); |
| |
| EXPECT_FALSE(writer->Write(log)); |
| |
| EXPECT_FALSE(writer->Close()); |
| EXPECT_FALSE(base::PathExists(path_)); // Errored files deleted by Close(). |
| } |
| |
| } // namespace webrtc_event_logging |