|  | /* | 
|  | *  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 <cstdio> | 
|  | #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 |