1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "api/rtc_event_log_output_file.h"
12
13 #include <fstream>
14 #include <iterator>
15 #include <memory>
16 #include <string>
17
18 #include "rtc_base/checks.h"
19 #include "test/gtest.h"
20 #include "test/testsupport/file_utils.h"
21
22 namespace webrtc {
23
24 class RtcEventLogOutputFileTest : public ::testing::Test {
25 public:
RtcEventLogOutputFileTest()26 RtcEventLogOutputFileTest() : output_file_name_(GetOutputFilePath()) {
27 // Ensure no leftovers from previous runs, which might not have terminated
28 // in an orderly fashion.
29 remove(output_file_name_.c_str());
30 }
31
~RtcEventLogOutputFileTest()32 ~RtcEventLogOutputFileTest() override { remove(output_file_name_.c_str()); }
33
34 protected:
GetOutputFilePath() const35 std::string GetOutputFilePath() const {
36 auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
37 return test::OutputPath() + test_info->test_case_name() + test_info->name();
38 }
39
GetOutputFileContents() const40 std::string GetOutputFileContents() const {
41 std::ifstream file(output_file_name_,
42 std::ios_base::in | std::ios_base::binary);
43 RTC_CHECK(file.is_open());
44 RTC_CHECK(file.good());
45 std::string file_str((std::istreambuf_iterator<char>(file)),
46 std::istreambuf_iterator<char>());
47 return file_str;
48 }
49
50 const std::string output_file_name_;
51 };
52
TEST_F(RtcEventLogOutputFileTest,NonDefectiveOutputsStartOutActive)53 TEST_F(RtcEventLogOutputFileTest, NonDefectiveOutputsStartOutActive) {
54 auto output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_);
55 EXPECT_TRUE(output_file->IsActive());
56 }
57
TEST_F(RtcEventLogOutputFileTest,DefectiveOutputsStartOutInactive)58 TEST_F(RtcEventLogOutputFileTest, DefectiveOutputsStartOutInactive) {
59 const std::string illegal_filename = "/////////";
60 auto output_file = std::make_unique<RtcEventLogOutputFile>(illegal_filename);
61 EXPECT_FALSE(output_file->IsActive());
62 }
63
64 // Sanity over opening a file (by filename) with an unlimited size.
TEST_F(RtcEventLogOutputFileTest,UnlimitedOutputFile)65 TEST_F(RtcEventLogOutputFileTest, UnlimitedOutputFile) {
66 const std::string output_str = "one two three";
67
68 auto output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_);
69 output_file->Write(output_str);
70 output_file.reset(); // Closing the file flushes the buffer to disk.
71
72 EXPECT_EQ(GetOutputFileContents(), output_str);
73 }
74
75 // Do not allow writing more bytes to the file than max file size.
TEST_F(RtcEventLogOutputFileTest,LimitedOutputFileCappedToCapacity)76 TEST_F(RtcEventLogOutputFileTest, LimitedOutputFileCappedToCapacity) {
77 // Fit two bytes, then the third should be rejected.
78 auto output_file =
79 std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2);
80
81 output_file->Write("1");
82 output_file->Write("2");
83 output_file->Write("3");
84 // Unsuccessful writes close the file; no need to delete the output to flush.
85
86 EXPECT_EQ(GetOutputFileContents(), "12");
87 }
88
89 // Make sure that calls to Write() either write everything to the file, or
90 // nothing (short of underlying issues in the module that handles the file,
91 // which would be beyond our control).
TEST_F(RtcEventLogOutputFileTest,DoNotWritePartialLines)92 TEST_F(RtcEventLogOutputFileTest, DoNotWritePartialLines) {
93 const std::string output_str_1 = "0123456789";
94 const std::string output_str_2 = "abcdefghij";
95
96 // Set a file size limit just shy of fitting the entire second line.
97 const size_t size_limit = output_str_1.length() + output_str_2.length() - 1;
98 auto output_file =
99 std::make_unique<RtcEventLogOutputFile>(output_file_name_, size_limit);
100
101 output_file->Write(output_str_1);
102 output_file->Write(output_str_2);
103 // Unsuccessful writes close the file; no need to delete the output to flush.
104
105 EXPECT_EQ(GetOutputFileContents(), output_str_1);
106 }
107
TEST_F(RtcEventLogOutputFileTest,UnsuccessfulWriteReturnsFalse)108 TEST_F(RtcEventLogOutputFileTest, UnsuccessfulWriteReturnsFalse) {
109 auto output_file =
110 std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2);
111 EXPECT_FALSE(output_file->Write("abc"));
112 }
113
TEST_F(RtcEventLogOutputFileTest,SuccessfulWriteReturnsTrue)114 TEST_F(RtcEventLogOutputFileTest, SuccessfulWriteReturnsTrue) {
115 auto output_file =
116 std::make_unique<RtcEventLogOutputFile>(output_file_name_, 3);
117 EXPECT_TRUE(output_file->Write("abc"));
118 }
119
120 // Even if capacity is reached, a successful write leaves the output active.
TEST_F(RtcEventLogOutputFileTest,FileStillActiveAfterSuccessfulWrite)121 TEST_F(RtcEventLogOutputFileTest, FileStillActiveAfterSuccessfulWrite) {
122 auto output_file =
123 std::make_unique<RtcEventLogOutputFile>(output_file_name_, 3);
124 ASSERT_TRUE(output_file->Write("abc"));
125 EXPECT_TRUE(output_file->IsActive());
126 }
127
128 // Unsuccessful writes switch the output to inactive, even if capacity has
129 // not yet been reached.
TEST_F(RtcEventLogOutputFileTest,FileInactiveAfterUnsuccessfulWrite)130 TEST_F(RtcEventLogOutputFileTest, FileInactiveAfterUnsuccessfulWrite) {
131 auto output_file =
132 std::make_unique<RtcEventLogOutputFile>(output_file_name_, 2);
133 ASSERT_FALSE(output_file->Write("abc"));
134 EXPECT_FALSE(output_file->IsActive());
135 }
136
TEST_F(RtcEventLogOutputFileTest,AllowReasonableFileSizeLimits)137 TEST_F(RtcEventLogOutputFileTest, AllowReasonableFileSizeLimits) {
138 auto output_file = std::make_unique<RtcEventLogOutputFile>(
139 output_file_name_, RtcEventLogOutputFile::kMaxReasonableFileSize);
140 EXPECT_TRUE(output_file->IsActive());
141 }
142
143 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
144 class RtcEventLogOutputFileDeathTest : public RtcEventLogOutputFileTest {};
145
TEST_F(RtcEventLogOutputFileDeathTest,WritingToInactiveFileForbidden)146 TEST_F(RtcEventLogOutputFileDeathTest, WritingToInactiveFileForbidden) {
147 RtcEventLogOutputFile output_file(output_file_name_, 2);
148 ASSERT_FALSE(output_file.Write("abc"));
149 ASSERT_FALSE(output_file.IsActive());
150 EXPECT_DEATH(output_file.Write("abc"), "");
151 }
152
TEST_F(RtcEventLogOutputFileDeathTest,DisallowUnreasonableFileSizeLimits)153 TEST_F(RtcEventLogOutputFileDeathTest, DisallowUnreasonableFileSizeLimits) {
154 // Keeping in a temporary unique_ptr to make it clearer that the death is
155 // triggered by construction, not destruction.
156 std::unique_ptr<RtcEventLogOutputFile> output_file;
157 auto create_output_file = [&] {
158 const size_t unreasonable_size =
159 RtcEventLogOutputFile::kMaxReasonableFileSize + 1;
160 output_file = std::make_unique<RtcEventLogOutputFile>(output_file_name_,
161 unreasonable_size);
162 };
163 EXPECT_DEATH(create_output_file(), "");
164 }
165 #endif
166
167 } // namespace webrtc
168