| /* |
| * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "api/rtc_event_log_output_file.h" |
| |
| #include <stdio.h> |
| |
| #include <cstddef> |
| #include <fstream> |
| #include <ios> |
| #include <iterator> |
| #include <memory> |
| #include <string> |
| |
| #include "rtc_base/checks.h" |
| #include "test/gtest.h" |
| #include "test/testsupport/file_utils.h" |
| |
| namespace webrtc { |
| |
| class RtcEventLogOutputFileTest : public ::testing::Test { |
| public: |
| RtcEventLogOutputFileTest() : output_file_name_(GetOutputFilePath()) { |
| // Ensure no leftovers from previous runs, which might not have terminated |
| // in an orderly fashion. |
| remove(output_file_name_.c_str()); |
| } |
| |
| ~RtcEventLogOutputFileTest() override { remove(output_file_name_.c_str()); } |
| |
| protected: |
| std::string GetOutputFilePath() const { |
| auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); |
| return test::OutputPathWithRandomDirectory() + test_info->test_case_name() + |
| test_info->name(); |
| } |
| |
| std::string GetOutputFileContents() const { |
| std::ifstream file(output_file_name_, |
| std::ios_base::in | std::ios_base::binary); |
| RTC_CHECK(file.is_open()); |
| RTC_CHECK(file.good()); |
| std::string file_str((std::istreambuf_iterator<char>(file)), |
| std::istreambuf_iterator<char>()); |
| return file_str; |
| } |
| |
| const std::string output_file_name_; |
| }; |
| |
| TEST_F(RtcEventLogOutputFileTest, NonDefectiveOutputsStartOutActive) { |
| auto output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_); |
| EXPECT_TRUE(output_file->IsActive()); |
| } |
| |
| TEST_F(RtcEventLogOutputFileTest, DefectiveOutputsStartOutInactive) { |
| const std::string illegal_filename = "/////////"; |
| auto output_file = std::make_unique<RtcEventLogOutputFile>(illegal_filename); |
| EXPECT_FALSE(output_file->IsActive()); |
| } |
| |
| // Sanity over opening a file (by filename) with an unlimited size. |
| TEST_F(RtcEventLogOutputFileTest, UnlimitedOutputFile) { |
| const std::string output_str = "one two three"; |
| |
| auto output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_); |
| output_file->Write(output_str); |
| output_file.reset(); // Closing the file flushes the buffer to disk. |
| |
| EXPECT_EQ(GetOutputFileContents(), output_str); |
| } |
| |
| // Do not allow writing more bytes to the file than max file size. |
| TEST_F(RtcEventLogOutputFileTest, LimitedOutputFileCappedToCapacity) { |
| // Fit two bytes, then the third should be rejected. |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); |
| |
| output_file->Write("1"); |
| output_file->Write("2"); |
| output_file->Write("3"); |
| // Unsuccessful writes close the file; no need to delete the output to flush. |
| |
| EXPECT_EQ(GetOutputFileContents(), "12"); |
| } |
| |
| // Make sure that calls to Write() either write everything to the file, or |
| // nothing (short of underlying issues in the module that handles the file, |
| // which would be beyond our control). |
| TEST_F(RtcEventLogOutputFileTest, DoNotWritePartialLines) { |
| const std::string output_str_1 = "0123456789"; |
| const std::string output_str_2 = "abcdefghij"; |
| |
| // Set a file size limit just shy of fitting the entire second line. |
| const size_t size_limit = output_str_1.length() + output_str_2.length() - 1; |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, size_limit); |
| |
| output_file->Write(output_str_1); |
| output_file->Write(output_str_2); |
| // Unsuccessful writes close the file; no need to delete the output to flush. |
| |
| EXPECT_EQ(GetOutputFileContents(), output_str_1); |
| } |
| |
| TEST_F(RtcEventLogOutputFileTest, UnsuccessfulWriteReturnsFalse) { |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); |
| EXPECT_FALSE(output_file->Write("abc")); |
| } |
| |
| TEST_F(RtcEventLogOutputFileTest, SuccessfulWriteReturnsTrue) { |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, 3); |
| EXPECT_TRUE(output_file->Write("abc")); |
| } |
| |
| // Even if capacity is reached, a successful write leaves the output active. |
| TEST_F(RtcEventLogOutputFileTest, FileStillActiveAfterSuccessfulWrite) { |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, 3); |
| ASSERT_TRUE(output_file->Write("abc")); |
| EXPECT_TRUE(output_file->IsActive()); |
| } |
| |
| // Unsuccessful writes switch the output to inactive, even if capacity has |
| // not yet been reached. |
| TEST_F(RtcEventLogOutputFileTest, FileInactiveAfterUnsuccessfulWrite) { |
| auto output_file = |
| std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); |
| ASSERT_FALSE(output_file->Write("abc")); |
| EXPECT_FALSE(output_file->IsActive()); |
| } |
| |
| TEST_F(RtcEventLogOutputFileTest, AllowReasonableFileSizeLimits) { |
| auto output_file = std::make_unique<RtcEventLogOutputFile>( |
| output_file_name_, RtcEventLogOutputFile::kMaxReasonableFileSize); |
| EXPECT_TRUE(output_file->IsActive()); |
| } |
| |
| #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) |
| class RtcEventLogOutputFileDeathTest : public RtcEventLogOutputFileTest {}; |
| |
| TEST_F(RtcEventLogOutputFileDeathTest, WritingToInactiveFileForbidden) { |
| RtcEventLogOutputFile output_file(output_file_name_, 2); |
| ASSERT_FALSE(output_file.Write("abc")); |
| ASSERT_FALSE(output_file.IsActive()); |
| EXPECT_DEATH(output_file.Write("abc"), ""); |
| } |
| |
| TEST_F(RtcEventLogOutputFileDeathTest, DisallowUnreasonableFileSizeLimits) { |
| // Keeping in a temporary unique_ptr to make it clearer that the death is |
| // triggered by construction, not destruction. |
| std::unique_ptr<RtcEventLogOutputFile> output_file; |
| auto create_output_file = [&] { |
| const size_t unreasonable_size = |
| RtcEventLogOutputFile::kMaxReasonableFileSize + 1; |
| output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_, |
| unreasonable_size); |
| }; |
| EXPECT_DEATH(create_output_file(), ""); |
| } |
| #endif |
| |
| } // namespace webrtc |