OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 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 "webrtc/base/arraysize.h" |
| 12 #include "webrtc/base/checks.h" |
| 13 #include "webrtc/base/filerotatingstream.h" |
| 14 #include "webrtc/base/fileutils.h" |
| 15 #include "webrtc/base/gunit.h" |
| 16 #include "webrtc/base/pathutils.h" |
| 17 |
| 18 namespace rtc { |
| 19 |
| 20 class FileRotatingStreamTest : public ::testing::Test { |
| 21 protected: |
| 22 static const char* kFilePrefix; |
| 23 static const size_t kMaxFileSize; |
| 24 |
| 25 void Init(const std::string& dir_name, |
| 26 const std::string& file_prefix, |
| 27 size_t max_file_size, |
| 28 size_t num_log_files) { |
| 29 Pathname test_path; |
| 30 ASSERT_TRUE(Filesystem::GetAppTempFolder(&test_path)); |
| 31 // Append per-test output path in order to run within gtest parallel. |
| 32 test_path.AppendFolder(dir_name); |
| 33 ASSERT_TRUE(Filesystem::CreateFolder(test_path)); |
| 34 dir_path_ = test_path.pathname(); |
| 35 ASSERT_TRUE(dir_path_.size()); |
| 36 stream_.reset(new FileRotatingStream(dir_path_, file_prefix, max_file_size, |
| 37 num_log_files)); |
| 38 } |
| 39 |
| 40 void TearDown() override { |
| 41 stream_.reset(); |
| 42 if (dir_path_.size() && Filesystem::IsFolder(dir_path_) && |
| 43 Filesystem::IsTemporaryPath(dir_path_)) { |
| 44 Filesystem::DeleteFolderAndContents(dir_path_); |
| 45 } |
| 46 } |
| 47 |
| 48 // Writes the data to the stream and flushes it. |
| 49 void WriteAndFlush(const void* data, const size_t data_len) { |
| 50 EXPECT_EQ(SR_SUCCESS, stream_->WriteAll(data, data_len, nullptr, nullptr)); |
| 51 EXPECT_TRUE(stream_->Flush()); |
| 52 } |
| 53 |
| 54 // Checks that the stream reads in the expected contents and then returns an |
| 55 // end of stream result. |
| 56 void VerifyStreamRead(const char* expected_contents, |
| 57 const size_t expected_length, |
| 58 const std::string& dir_path, |
| 59 const char* file_prefix) { |
| 60 scoped_ptr<FileRotatingStream> stream; |
| 61 stream.reset(new FileRotatingStream(dir_path, file_prefix)); |
| 62 ASSERT_TRUE(stream->Open()); |
| 63 scoped_ptr<uint8_t[]> buffer(new uint8_t[expected_length]); |
| 64 EXPECT_EQ(SR_SUCCESS, |
| 65 stream->ReadAll(buffer.get(), expected_length, nullptr, nullptr)); |
| 66 EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length)); |
| 67 EXPECT_EQ(SR_EOS, stream->ReadAll(buffer.get(), 1, nullptr, nullptr)); |
| 68 } |
| 69 |
| 70 void VerifyFileContents(const char* expected_contents, |
| 71 const size_t expected_length, |
| 72 const std::string& file_path) { |
| 73 scoped_ptr<uint8_t[]> buffer(new uint8_t[expected_length]); |
| 74 scoped_ptr<FileStream> stream(Filesystem::OpenFile(file_path, "r")); |
| 75 EXPECT_TRUE(stream); |
| 76 if (!stream) { |
| 77 return; |
| 78 } |
| 79 EXPECT_EQ(rtc::SR_SUCCESS, |
| 80 stream->ReadAll(buffer.get(), expected_length, nullptr, nullptr)); |
| 81 EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length)); |
| 82 size_t file_size = 0; |
| 83 EXPECT_TRUE(stream->GetSize(&file_size)); |
| 84 EXPECT_EQ(file_size, expected_length); |
| 85 } |
| 86 |
| 87 scoped_ptr<FileRotatingStream> stream_; |
| 88 std::string dir_path_; |
| 89 }; |
| 90 |
| 91 const char* FileRotatingStreamTest::kFilePrefix = "FileRotatingStreamTest"; |
| 92 const size_t FileRotatingStreamTest::kMaxFileSize = 2; |
| 93 |
| 94 // Tests that stream state is correct before and after Open / Close. |
| 95 TEST_F(FileRotatingStreamTest, State) { |
| 96 Init("FileRotatingStreamTestState", kFilePrefix, kMaxFileSize, 3); |
| 97 |
| 98 EXPECT_EQ(SS_CLOSED, stream_->GetState()); |
| 99 ASSERT_TRUE(stream_->Open()); |
| 100 EXPECT_EQ(SS_OPEN, stream_->GetState()); |
| 101 stream_->Close(); |
| 102 EXPECT_EQ(SS_CLOSED, stream_->GetState()); |
| 103 } |
| 104 |
| 105 // Tests that nothing is written to file when data of length zero is written. |
| 106 TEST_F(FileRotatingStreamTest, EmptyWrite) { |
| 107 Init("FileRotatingStreamTestEmptyWrite", kFilePrefix, kMaxFileSize, 3); |
| 108 |
| 109 ASSERT_TRUE(stream_->Open()); |
| 110 WriteAndFlush("a", 0); |
| 111 |
| 112 std::string logfile_path = stream_->GetFilePath(0); |
| 113 scoped_ptr<FileStream> stream(Filesystem::OpenFile(logfile_path, "r")); |
| 114 size_t file_size = 0; |
| 115 EXPECT_TRUE(stream->GetSize(&file_size)); |
| 116 EXPECT_EQ(0u, file_size); |
| 117 } |
| 118 |
| 119 // Tests that a write operation followed by a read returns the expected data |
| 120 // and writes to the expected files. |
| 121 TEST_F(FileRotatingStreamTest, WriteAndRead) { |
| 122 Init("FileRotatingStreamTestWriteAndRead", kFilePrefix, kMaxFileSize, 3); |
| 123 |
| 124 ASSERT_TRUE(stream_->Open()); |
| 125 // The test is set up to create three log files of length 2. Write and check |
| 126 // contents. |
| 127 std::string messages[3] = {"aa", "bb", "cc"}; |
| 128 for (size_t i = 0; i < arraysize(messages); ++i) { |
| 129 const std::string& message = messages[i]; |
| 130 WriteAndFlush(message.c_str(), message.size()); |
| 131 // Since the max log size is 2, we will be causing rotation. Read from the |
| 132 // next file. |
| 133 VerifyFileContents(message.c_str(), message.size(), |
| 134 stream_->GetFilePath(1)); |
| 135 } |
| 136 // Check that exactly three files exist. |
| 137 for (size_t i = 0; i < arraysize(messages); ++i) { |
| 138 EXPECT_TRUE(Filesystem::IsFile(stream_->GetFilePath(i))); |
| 139 } |
| 140 std::string message("d"); |
| 141 WriteAndFlush(message.c_str(), message.size()); |
| 142 for (size_t i = 0; i < arraysize(messages); ++i) { |
| 143 EXPECT_TRUE(Filesystem::IsFile(stream_->GetFilePath(i))); |
| 144 } |
| 145 // TODO(tkchin): Maybe check all the files in the dir. |
| 146 |
| 147 // Reopen for read. |
| 148 std::string expected_contents("bbccd"); |
| 149 VerifyStreamRead(expected_contents.c_str(), expected_contents.size(), |
| 150 dir_path_, kFilePrefix); |
| 151 } |
| 152 |
| 153 // Tests that writing data greater than the total capacity of the files |
| 154 // overwrites the files correctly and is read correctly after. |
| 155 TEST_F(FileRotatingStreamTest, WriteOverflowAndRead) { |
| 156 Init("FileRotatingStreamTestWriteOverflowAndRead", kFilePrefix, kMaxFileSize, |
| 157 3); |
| 158 ASSERT_TRUE(stream_->Open()); |
| 159 // This should cause overflow across all three files, such that the first file |
| 160 // we wrote to also gets overwritten. |
| 161 std::string message("foobarbaz"); |
| 162 WriteAndFlush(message.c_str(), message.size()); |
| 163 std::string expected_file_contents("z"); |
| 164 VerifyFileContents(expected_file_contents.c_str(), |
| 165 expected_file_contents.size(), stream_->GetFilePath(0)); |
| 166 std::string expected_stream_contents("arbaz"); |
| 167 VerifyStreamRead(expected_stream_contents.c_str(), |
| 168 expected_stream_contents.size(), dir_path_, kFilePrefix); |
| 169 } |
| 170 |
| 171 // Tests that the returned file paths have the right folder and prefix. |
| 172 TEST_F(FileRotatingStreamTest, GetFilePath) { |
| 173 Init("FileRotatingStreamTestGetFilePath", kFilePrefix, kMaxFileSize, 20); |
| 174 for (auto i = 0; i < 20; ++i) { |
| 175 Pathname path(stream_->GetFilePath(i)); |
| 176 EXPECT_EQ(0, path.folder().compare(dir_path_)); |
| 177 EXPECT_EQ(0, path.filename().compare(0, strlen(kFilePrefix), kFilePrefix)); |
| 178 } |
| 179 } |
| 180 |
| 181 class CallSessionFileRotatingStreamTest : public ::testing::Test { |
| 182 protected: |
| 183 void Init(const std::string& dir_name, size_t max_total_log_size) { |
| 184 Pathname test_path; |
| 185 ASSERT_TRUE(Filesystem::GetAppTempFolder(&test_path)); |
| 186 // Append per-test output path in order to run within gtest parallel. |
| 187 test_path.AppendFolder(dir_name); |
| 188 ASSERT_TRUE(Filesystem::CreateFolder(test_path)); |
| 189 dir_path_ = test_path.pathname(); |
| 190 ASSERT_TRUE(dir_path_.size()); |
| 191 stream_.reset( |
| 192 new CallSessionFileRotatingStream(dir_path_, max_total_log_size)); |
| 193 } |
| 194 |
| 195 virtual void TearDown() { |
| 196 stream_.reset(); |
| 197 if (dir_path_.size() && Filesystem::IsFolder(dir_path_) && |
| 198 Filesystem::IsTemporaryPath(dir_path_)) { |
| 199 Filesystem::DeleteFolderAndContents(dir_path_); |
| 200 } |
| 201 } |
| 202 |
| 203 // Writes the data to the stream and flushes it. |
| 204 void WriteAndFlush(const void* data, const size_t data_len) { |
| 205 EXPECT_EQ(SR_SUCCESS, stream_->WriteAll(data, data_len, nullptr, nullptr)); |
| 206 EXPECT_TRUE(stream_->Flush()); |
| 207 } |
| 208 |
| 209 // Checks that the stream reads in the expected contents and then returns an |
| 210 // end of stream result. |
| 211 void VerifyStreamRead(const char* expected_contents, |
| 212 const size_t expected_length, |
| 213 const std::string& dir_path) { |
| 214 scoped_ptr<CallSessionFileRotatingStream> stream( |
| 215 new CallSessionFileRotatingStream(dir_path)); |
| 216 ASSERT_TRUE(stream->Open()); |
| 217 scoped_ptr<uint8_t[]> buffer(new uint8_t[expected_length]); |
| 218 EXPECT_EQ(SR_SUCCESS, |
| 219 stream->ReadAll(buffer.get(), expected_length, nullptr, nullptr)); |
| 220 EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length)); |
| 221 EXPECT_EQ(SR_EOS, stream->ReadAll(buffer.get(), 1, nullptr, nullptr)); |
| 222 } |
| 223 |
| 224 scoped_ptr<CallSessionFileRotatingStream> stream_; |
| 225 std::string dir_path_; |
| 226 }; |
| 227 |
| 228 // Tests that writing and reading to a stream with the smallest possible |
| 229 // capacity works. |
| 230 TEST_F(CallSessionFileRotatingStreamTest, WriteAndReadSmallest) { |
| 231 Init("CallSessionFileRotatingStreamTestWriteAndReadSmallest", 4); |
| 232 |
| 233 ASSERT_TRUE(stream_->Open()); |
| 234 std::string message("abcde"); |
| 235 WriteAndFlush(message.c_str(), message.size()); |
| 236 std::string expected_contents("abe"); |
| 237 VerifyStreamRead(expected_contents.c_str(), expected_contents.size(), |
| 238 dir_path_); |
| 239 } |
| 240 |
| 241 // Tests that writing and reading to a stream with capacity lesser than 4MB |
| 242 // behaves correctly. |
| 243 TEST_F(CallSessionFileRotatingStreamTest, WriteAndReadSmall) { |
| 244 Init("CallSessionFileRotatingStreamTestWriteAndReadSmall", 8); |
| 245 |
| 246 ASSERT_TRUE(stream_->Open()); |
| 247 std::string message("123456789"); |
| 248 WriteAndFlush(message.c_str(), message.size()); |
| 249 std::string expected_contents("1234789"); |
| 250 VerifyStreamRead(expected_contents.c_str(), expected_contents.size(), |
| 251 dir_path_); |
| 252 } |
| 253 |
| 254 // Tests that writing and reading to a stream with capacity greater than 4MB |
| 255 // behaves correctly. |
| 256 TEST_F(CallSessionFileRotatingStreamTest, WriteAndReadLarge) { |
| 257 Init("CallSessionFileRotatingStreamTestWriteAndReadLarge", 6 * 1024 * 1024); |
| 258 |
| 259 ASSERT_TRUE(stream_->Open()); |
| 260 const size_t buffer_size = 1024 * 1024; |
| 261 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); |
| 262 for (int i = 0; i < 8; i++) { |
| 263 memset(buffer.get(), i, buffer_size); |
| 264 EXPECT_EQ(SR_SUCCESS, |
| 265 stream_->WriteAll(buffer.get(), buffer_size, nullptr, nullptr)); |
| 266 } |
| 267 |
| 268 stream_.reset(new CallSessionFileRotatingStream(dir_path_)); |
| 269 ASSERT_TRUE(stream_->Open()); |
| 270 scoped_ptr<uint8_t[]> expected_buffer(new uint8_t[buffer_size]); |
| 271 int expected_vals[] = {0, 1, 2, 6, 7}; |
| 272 for (size_t i = 0; i < arraysize(expected_vals); ++i) { |
| 273 memset(expected_buffer.get(), expected_vals[i], buffer_size); |
| 274 EXPECT_EQ(SR_SUCCESS, |
| 275 stream_->ReadAll(buffer.get(), buffer_size, nullptr, nullptr)); |
| 276 EXPECT_EQ(0, memcmp(buffer.get(), expected_buffer.get(), buffer_size)); |
| 277 } |
| 278 EXPECT_EQ(SR_EOS, stream_->ReadAll(buffer.get(), 1, nullptr, nullptr)); |
| 279 } |
| 280 |
| 281 // Tests that writing and reading to a stream where only the first file is |
| 282 // written to behaves correctly. |
| 283 TEST_F(CallSessionFileRotatingStreamTest, WriteAndReadFirstHalf) { |
| 284 Init("CallSessionFileRotatingStreamTestWriteAndReadFirstHalf", |
| 285 6 * 1024 * 1024); |
| 286 ASSERT_TRUE(stream_->Open()); |
| 287 const size_t buffer_size = 1024 * 1024; |
| 288 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); |
| 289 for (int i = 0; i < 2; i++) { |
| 290 memset(buffer.get(), i, buffer_size); |
| 291 EXPECT_EQ(SR_SUCCESS, |
| 292 stream_->WriteAll(buffer.get(), buffer_size, nullptr, nullptr)); |
| 293 } |
| 294 |
| 295 stream_.reset(new CallSessionFileRotatingStream(dir_path_)); |
| 296 ASSERT_TRUE(stream_->Open()); |
| 297 scoped_ptr<uint8_t[]> expected_buffer(new uint8_t[buffer_size]); |
| 298 int expected_vals[] = {0, 1}; |
| 299 for (size_t i = 0; i < arraysize(expected_vals); ++i) { |
| 300 memset(expected_buffer.get(), expected_vals[i], buffer_size); |
| 301 EXPECT_EQ(SR_SUCCESS, |
| 302 stream_->ReadAll(buffer.get(), buffer_size, nullptr, nullptr)); |
| 303 EXPECT_EQ(0, memcmp(buffer.get(), expected_buffer.get(), buffer_size)); |
| 304 } |
| 305 EXPECT_EQ(SR_EOS, stream_->ReadAll(buffer.get(), 1, nullptr, nullptr)); |
| 306 } |
| 307 |
| 308 } // namespace rtc |
OLD | NEW |