1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 7 #include "base/files/file.h" 8 #include "base/files/file_path.h" 9 #include "base/files/file_util.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/logging.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_split.h" 14 #include "base/time/time.h" 15 #include "chrome/browser/media/webrtc_log_uploader.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 const char kTestTime[] = "time"; 19 const char kTestReportId[] = "report-id"; 20 const char kTestLocalId[] = "local-id"; 21 22 class WebRtcLogUploaderTest : public testing::Test { 23 public: 24 WebRtcLogUploaderTest() {} 25 26 bool VerifyNumberOfLines(int expected_lines) { 27 std::vector<std::string> lines = GetLinesFromListFile(); 28 EXPECT_EQ(expected_lines, static_cast<int>(lines.size())); 29 return expected_lines == static_cast<int>(lines.size()); 30 } 31 32 bool VerifyLastLineHasAllInfo() { 33 std::string last_line = GetLastLineFromListFile(); 34 if (last_line.empty()) 35 return false; 36 std::vector<std::string> line_parts; 37 base::SplitString(last_line, ',', &line_parts); 38 EXPECT_EQ(3u, line_parts.size()); 39 if (3u != line_parts.size()) 40 return false; 41 // The time (line_parts[0]) is the time when the info was written to the 42 // file which we don't know, so just verify that it's not empty. 43 EXPECT_FALSE(line_parts[0].empty()); 44 EXPECT_STREQ(kTestReportId, line_parts[1].c_str()); 45 EXPECT_STREQ(kTestLocalId, line_parts[2].c_str()); 46 return true; 47 } 48 49 bool VerifyLastLineHasLocalIdOnly() { 50 std::string last_line = GetLastLineFromListFile(); 51 if (last_line.empty()) 52 return false; 53 std::vector<std::string> line_parts; 54 base::SplitString(last_line, ',', &line_parts); 55 EXPECT_EQ(3u, line_parts.size()); 56 if (3u != line_parts.size()) 57 return false; 58 EXPECT_TRUE(line_parts[0].empty()); 59 EXPECT_TRUE(line_parts[1].empty()); 60 EXPECT_STREQ(kTestLocalId, line_parts[2].c_str()); 61 return true; 62 } 63 64 bool VerifyLastLineHasUploadTimeAndIdOnly() { 65 std::string last_line = GetLastLineFromListFile(); 66 if (last_line.empty()) 67 return false; 68 std::vector<std::string> line_parts; 69 base::SplitString(last_line, ',', &line_parts); 70 EXPECT_EQ(3u, line_parts.size()); 71 if (3u != line_parts.size()) 72 return false; 73 EXPECT_FALSE(line_parts[0].empty()); 74 EXPECT_STREQ(kTestReportId, line_parts[1].c_str()); 75 EXPECT_TRUE(line_parts[2].empty()); 76 return true; 77 } 78 79 bool AddLinesToTestFile(int number_of_lines) { 80 base::File test_list_file(test_list_path_, 81 base::File::FLAG_OPEN | base::File::FLAG_APPEND); 82 EXPECT_TRUE(test_list_file.IsValid()); 83 if (!test_list_file.IsValid()) 84 return false; 85 86 for (int i = 0; i < number_of_lines; ++i) { 87 EXPECT_EQ(static_cast<int>(sizeof(kTestTime)) - 1, 88 test_list_file.WriteAtCurrentPos(kTestTime, 89 sizeof(kTestTime) - 1)); 90 EXPECT_EQ(1, test_list_file.WriteAtCurrentPos(",", 1)); 91 EXPECT_EQ(static_cast<int>(sizeof(kTestReportId)) - 1, 92 test_list_file.WriteAtCurrentPos(kTestReportId, 93 sizeof(kTestReportId) - 1)); 94 EXPECT_EQ(1, test_list_file.WriteAtCurrentPos(",", 1)); 95 EXPECT_EQ(static_cast<int>(sizeof(kTestLocalId)) - 1, 96 test_list_file.WriteAtCurrentPos(kTestLocalId, 97 sizeof(kTestLocalId) - 1)); 98 EXPECT_EQ(1, test_list_file.WriteAtCurrentPos("\n", 1)); 99 } 100 return true; 101 } 102 103 std::vector<std::string> GetLinesFromListFile() { 104 std::string contents; 105 int read = base::ReadFileToString(test_list_path_, &contents); 106 EXPECT_GT(read, 0); 107 if (read == 0) 108 return std::vector<std::string>(); 109 // Since every line should end with '\n', the last line should be empty. So 110 // we expect at least two lines including the final empty. Remove the empty 111 // line before returning. 112 std::vector<std::string> lines; 113 base::SplitString(contents, '\n', &lines); 114 EXPECT_GT(lines.size(), 1u); 115 if (lines.size() < 2) 116 return std::vector<std::string>(); 117 EXPECT_TRUE(lines[lines.size() - 1].empty()); 118 if (!lines[lines.size() - 1].empty()) 119 return std::vector<std::string>(); 120 lines.pop_back(); 121 return lines; 122 } 123 124 std::string GetLastLineFromListFile() { 125 std::vector<std::string> lines = GetLinesFromListFile(); 126 EXPECT_GT(lines.size(), 0u); 127 if (lines.empty()) 128 return std::string(); 129 return lines[lines.size() - 1]; 130 } 131 132 void VerifyRtpDumpInMultipart(const std::string& post_data, 133 const std::string& dump_name, 134 const std::string& dump_content) { 135 std::vector<std::string> lines; 136 base::SplitStringUsingSubstr(post_data, "\r\n", &lines); 137 138 std::string name_line = "Content-Disposition: form-data; name=\""; 139 name_line.append(dump_name); 140 name_line.append("\""); 141 name_line.append("; filename=\""); 142 name_line.append(dump_name); 143 name_line.append(".gz\""); 144 145 size_t i = 0; 146 for (; i < lines.size(); ++i) { 147 if (lines[i] == name_line) 148 break; 149 } 150 151 // The RTP dump takes 4 lines: content-disposition, content-type, empty 152 // line, dump content. 153 EXPECT_LT(i, lines.size() - 3); 154 155 EXPECT_EQ("Content-Type: application/gzip", lines[i + 1]); 156 EXPECT_EQ("", lines[i + 2]); 157 EXPECT_EQ(dump_content, lines[i + 3]); 158 } 159 160 base::FilePath test_list_path_; 161 }; 162 163 TEST_F(WebRtcLogUploaderTest, AddLocallyStoredLogInfoToUploadListFile) { 164 // Get a temporary filename. We don't want the file to exist to begin with 165 // since that's the normal use case, hence the delete. 166 ASSERT_TRUE(base::CreateTemporaryFile(&test_list_path_)); 167 EXPECT_TRUE(base::DeleteFile(test_list_path_, false)); 168 scoped_ptr<WebRtcLogUploader> webrtc_log_uploader(new WebRtcLogUploader()); 169 170 webrtc_log_uploader->AddLocallyStoredLogInfoToUploadListFile(test_list_path_, 171 kTestLocalId); 172 webrtc_log_uploader->AddLocallyStoredLogInfoToUploadListFile(test_list_path_, 173 kTestLocalId); 174 ASSERT_TRUE(VerifyNumberOfLines(2)); 175 ASSERT_TRUE(VerifyLastLineHasLocalIdOnly()); 176 177 const int expected_line_limit = 50; 178 ASSERT_TRUE(AddLinesToTestFile(expected_line_limit - 2)); 179 ASSERT_TRUE(VerifyNumberOfLines(expected_line_limit)); 180 ASSERT_TRUE(VerifyLastLineHasAllInfo()); 181 182 webrtc_log_uploader->AddLocallyStoredLogInfoToUploadListFile(test_list_path_, 183 kTestLocalId); 184 ASSERT_TRUE(VerifyNumberOfLines(expected_line_limit)); 185 ASSERT_TRUE(VerifyLastLineHasLocalIdOnly()); 186 187 ASSERT_TRUE(AddLinesToTestFile(10)); 188 ASSERT_TRUE(VerifyNumberOfLines(60)); 189 ASSERT_TRUE(VerifyLastLineHasAllInfo()); 190 191 webrtc_log_uploader->AddLocallyStoredLogInfoToUploadListFile(test_list_path_, 192 kTestLocalId); 193 ASSERT_TRUE(VerifyNumberOfLines(expected_line_limit)); 194 ASSERT_TRUE(VerifyLastLineHasLocalIdOnly()); 195 196 webrtc_log_uploader->StartShutdown(); 197 } 198 199 TEST_F(WebRtcLogUploaderTest, AddUploadedLogInfoToUploadListFile) { 200 // Get a temporary filename. We don't want the file to exist to begin with 201 // since that's the normal use case, hence the delete. 202 ASSERT_TRUE(base::CreateTemporaryFile(&test_list_path_)); 203 EXPECT_TRUE(base::DeleteFile(test_list_path_, false)); 204 scoped_ptr<WebRtcLogUploader> webrtc_log_uploader(new WebRtcLogUploader()); 205 206 webrtc_log_uploader->AddLocallyStoredLogInfoToUploadListFile(test_list_path_, 207 kTestLocalId); 208 ASSERT_TRUE(VerifyNumberOfLines(1)); 209 ASSERT_TRUE(VerifyLastLineHasLocalIdOnly()); 210 211 webrtc_log_uploader->AddUploadedLogInfoToUploadListFile( 212 test_list_path_, kTestLocalId, kTestReportId); 213 ASSERT_TRUE(VerifyNumberOfLines(1)); 214 ASSERT_TRUE(VerifyLastLineHasAllInfo()); 215 216 // Use a local ID that should not be found in the list. 217 webrtc_log_uploader->AddUploadedLogInfoToUploadListFile( 218 test_list_path_, "dummy id", kTestReportId); 219 ASSERT_TRUE(VerifyNumberOfLines(2)); 220 ASSERT_TRUE(VerifyLastLineHasUploadTimeAndIdOnly()); 221 222 webrtc_log_uploader->StartShutdown(); 223 } 224 225 TEST_F(WebRtcLogUploaderTest, AddRtpDumpsToPostedData) { 226 base::ScopedTempDir temp_dir; 227 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 228 229 scoped_ptr<WebRtcLogUploader> webrtc_log_uploader(new WebRtcLogUploader()); 230 231 std::string post_data; 232 webrtc_log_uploader->OverrideUploadWithBufferForTesting(&post_data); 233 234 // Create the fake dump files. 235 const base::FilePath incoming_dump = temp_dir.path().AppendASCII("recv"); 236 const base::FilePath outgoing_dump = temp_dir.path().AppendASCII("send"); 237 const std::string incoming_dump_content = "dummy incoming"; 238 const std::string outgoing_dump_content = "dummy outgoing"; 239 240 base::WriteFile(incoming_dump, 241 &incoming_dump_content[0], 242 incoming_dump_content.size()); 243 base::WriteFile(outgoing_dump, 244 &outgoing_dump_content[0], 245 outgoing_dump_content.size()); 246 247 WebRtcLogUploadDoneData upload_done_data; 248 upload_done_data.log_path = temp_dir.path().AppendASCII("log"); 249 250 upload_done_data.incoming_rtp_dump = incoming_dump; 251 upload_done_data.outgoing_rtp_dump = outgoing_dump; 252 253 const size_t log_length = 100; 254 scoped_ptr<unsigned char[]> log(new unsigned char[log_length]); 255 memset(log.get(), 0, log_length); 256 257 webrtc_log_uploader->LoggingStoppedDoUpload( 258 log.Pass(), 259 log_length, 260 std::map<std::string, std::string>(), 261 upload_done_data); 262 263 VerifyRtpDumpInMultipart(post_data, "rtpdump_recv", incoming_dump_content); 264 VerifyRtpDumpInMultipart(post_data, "rtpdump_send", outgoing_dump_content); 265 266 webrtc_log_uploader->StartShutdown(); 267 } 268