Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "client/crash_report_database.h" | |
| 16 | |
| 17 #include <sys/stat.h> | |
| 18 | |
| 19 #include "gtest/gtest.h" | |
| 20 #include "util/file/file_io.h" | |
| 21 #include "util/test/scoped_temp_dir.h" | |
| 22 | |
| 23 namespace crashpad { | |
| 24 namespace test { | |
| 25 namespace { | |
| 26 | |
| 27 bool FileExistsAtPath(const base::FilePath& path) { | |
| 28 #if defined(OS_POSIX) | |
| 29 struct stat st; | |
| 30 return lstat(path.value().c_str(), &st) == 0; | |
| 31 #else | |
| 32 #error "Not implemented" | |
| 33 #endif | |
| 34 } | |
| 35 | |
| 36 void CreateFile(const base::FilePath& path) { | |
| 37 FileHandle handle = LoggingOpenFileForWrite(path, | |
| 38 FileWriteMode::kCreateOrFail, | |
| 39 FilePermissions::kWorldReadable); | |
| 40 ASSERT_GE(handle, 0); | |
| 41 ASSERT_TRUE( | |
| 42 LoggingWriteFile(handle, path.value().c_str(), path.value().length())); | |
| 43 ASSERT_TRUE(LoggingCloseFile(handle)); | |
| 44 } | |
| 45 | |
| 46 class CrashReportDatabaseTest : public testing::Test { | |
| 47 protected: | |
| 48 // testing::Test: | |
| 49 void SetUp() override { | |
| 50 db_ = CrashReportDatabase::Initialize(path()); | |
| 51 ASSERT_TRUE(db_.get()); | |
| 52 } | |
| 53 | |
| 54 void ResetDatabase() { | |
| 55 db_.reset(); | |
| 56 } | |
| 57 | |
| 58 CrashReportDatabase* db() const { return db_.get(); } | |
| 59 const base::FilePath& path() const { return temp_dir_.path(); } | |
| 60 | |
| 61 void CreateCrashReport(CrashReportDatabase::Report* report) { | |
| 62 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 63 db_->PrepareNewCrashReport(report)); | |
| 64 ExpectPreparedCrashReport(*report); | |
| 65 CreateFile(report->file_path); | |
| 66 ASSERT_TRUE(FileExistsAtPath(report->file_path)); | |
| 67 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 68 db_->FinishedWritingCrashReport(report->uuid)); | |
| 69 } | |
| 70 | |
| 71 void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) { | |
| 72 EXPECT_NE(UUID(), report.uuid); | |
| 73 EXPECT_FALSE(report.file_path.empty()); | |
| 74 EXPECT_FALSE(FileExistsAtPath(report.file_path)); | |
| 75 EXPECT_TRUE(report.id.empty()); | |
| 76 EXPECT_FALSE(report.uploaded); | |
| 77 EXPECT_EQ(0, report.last_upload_attempt_time); | |
| 78 EXPECT_EQ(0, report.upload_attempts); | |
| 79 } | |
| 80 | |
| 81 private: | |
| 82 ScopedTempDir temp_dir_; | |
| 83 scoped_ptr<CrashReportDatabase> db_; | |
| 84 }; | |
| 85 | |
| 86 TEST_F(CrashReportDatabaseTest, Initialize) { | |
| 87 // Initialize the database for the first time, creating it. | |
| 88 EXPECT_TRUE(db()); | |
| 89 | |
| 90 // Close and reopen the database at the same path. | |
| 91 ResetDatabase(); | |
| 92 EXPECT_FALSE(db()); | |
| 93 auto db = CrashReportDatabase::Initialize(path()); | |
| 94 EXPECT_TRUE(db.get()); | |
| 95 | |
| 96 std::vector<const CrashReportDatabase::Report> reports; | |
| 97 EXPECT_EQ(CrashReportDatabase::kNoError, db->GetNotUploadedReports(&reports)); | |
| 98 EXPECT_TRUE(reports.empty()); | |
| 99 EXPECT_EQ(CrashReportDatabase::kNoError, db->GetUploadedReports(&reports)); | |
| 100 EXPECT_TRUE(reports.empty()); | |
| 101 } | |
| 102 | |
| 103 TEST_F(CrashReportDatabaseTest, PrepareNewCrashReport) { | |
| 104 CrashReportDatabase::Report report; | |
| 105 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 106 db()->PrepareNewCrashReport(&report)); | |
| 107 ExpectPreparedCrashReport(report); | |
| 108 | |
| 109 CrashReportDatabase::Report query; | |
| 110 EXPECT_EQ(CrashReportDatabase::kReportNotFound, | |
| 111 db()->LookUpCrashReport(report.uuid, &query)); | |
| 112 } | |
| 113 | |
| 114 TEST_F(CrashReportDatabaseTest, FinishedWritingCrashReport) { | |
| 115 CrashReportDatabase::Report report; | |
| 116 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 117 db()->PrepareNewCrashReport(&report)); | |
| 118 ExpectPreparedCrashReport(report); | |
| 119 | |
| 120 CrashReportDatabase::Report query; | |
| 121 EXPECT_EQ(CrashReportDatabase::kReportNotFound, | |
| 122 db()->LookUpCrashReport(report.uuid, &query)); | |
| 123 | |
| 124 CreateFile(report.file_path); | |
| 125 | |
| 126 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 127 db()->FinishedWritingCrashReport(report.uuid)); | |
| 128 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 129 db()->LookUpCrashReport(report.uuid, &query)); | |
| 130 EXPECT_EQ(report.uuid, query.uuid); | |
| 131 EXPECT_TRUE(report.id.empty()); | |
| 132 EXPECT_FALSE(report.uploaded); | |
| 133 EXPECT_EQ(0, report.last_upload_attempt_time); | |
| 134 EXPECT_EQ(0, report.upload_attempts); | |
| 135 | |
| 136 std::vector<const CrashReportDatabase::Report> reports; | |
| 137 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 138 db()->GetNotUploadedReports(&reports)); | |
| 139 ASSERT_EQ(1u, reports.size()); | |
| 140 EXPECT_EQ(report.uuid, reports[0].uuid); | |
| 141 | |
| 142 reports.clear(); | |
| 143 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 144 db()->GetUploadedReports(&reports)); | |
| 145 EXPECT_TRUE(reports.empty()); | |
| 146 } | |
| 147 | |
| 148 TEST_F(CrashReportDatabaseTest, LookUpCrashReport) { | |
| 149 UUID uuid; | |
| 150 | |
| 151 { | |
| 152 CrashReportDatabase::Report report; | |
| 153 CreateCrashReport(&report); | |
| 154 uuid = report.uuid; | |
| 155 } | |
| 156 | |
| 157 { | |
| 158 CrashReportDatabase::Report report; | |
| 159 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 160 db()->LookUpCrashReport(uuid, &report)); | |
| 161 EXPECT_EQ(uuid, report.uuid); | |
| 162 EXPECT_NE(std::string::npos, report.file_path.value().find(path().value())); | |
| 163 EXPECT_EQ("", report.id); | |
| 164 EXPECT_FALSE(report.uploaded); | |
| 165 EXPECT_EQ(0, report.last_upload_attempt_time); | |
| 166 EXPECT_EQ(0, report.upload_attempts); | |
| 167 } | |
| 168 | |
| 169 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 170 db()->RecordUploadAttempt(uuid, true, "test")); | |
| 171 | |
| 172 { | |
| 173 CrashReportDatabase::Report report; | |
| 174 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 175 db()->LookUpCrashReport(uuid, &report)); | |
| 176 EXPECT_EQ(uuid, report.uuid); | |
| 177 EXPECT_NE(std::string::npos, report.file_path.value().find(path().value())); | |
| 178 EXPECT_EQ("test", report.id); | |
| 179 EXPECT_TRUE(report.uploaded); | |
| 180 EXPECT_NE(0, report.last_upload_attempt_time); | |
| 181 EXPECT_EQ(1, report.upload_attempts); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 TEST_F(CrashReportDatabaseTest, FinishedWritingCrashReportError) { | |
| 186 CrashReportDatabase::Report report; | |
| 187 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 188 db()->PrepareNewCrashReport(&report)); | |
| 189 ExpectPreparedCrashReport(report); | |
| 190 | |
| 191 EXPECT_EQ(CrashReportDatabase::kReportNotFound, | |
| 192 db()->FinishedWritingCrashReport(report.uuid)); | |
| 193 } | |
| 194 | |
| 195 TEST_F(CrashReportDatabaseTest, RecordUploadAttempt) { | |
| 196 std::vector<CrashReportDatabase::Report> reports(3); | |
| 197 CreateCrashReport(&reports[0]); | |
| 198 CreateCrashReport(&reports[1]); | |
| 199 CreateCrashReport(&reports[2]); | |
| 200 | |
| 201 // Record two attempts: one successful, one not. | |
| 202 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 203 db()->RecordUploadAttempt(reports[1].uuid, false, "")); | |
| 204 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 205 db()->RecordUploadAttempt(reports[2].uuid, true, "abc123")); | |
| 206 | |
| 207 std::vector<CrashReportDatabase::Report> query(3); | |
| 208 | |
| 209 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 210 db()->LookUpCrashReport(reports[0].uuid, &query[0])); | |
| 211 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 212 db()->LookUpCrashReport(reports[1].uuid, &query[1])); | |
| 213 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 214 db()->LookUpCrashReport(reports[2].uuid, &query[2])); | |
| 215 | |
| 216 EXPECT_EQ("", query[0].id); | |
| 217 EXPECT_EQ("", query[1].id); | |
| 218 EXPECT_EQ("abc123", query[2].id); | |
| 219 | |
| 220 EXPECT_FALSE(query[0].uploaded); | |
| 221 EXPECT_FALSE(query[1].uploaded); | |
| 222 EXPECT_TRUE(query[2].uploaded); | |
| 223 | |
| 224 EXPECT_EQ(0, query[0].last_upload_attempt_time); | |
| 225 EXPECT_NE(0, query[1].last_upload_attempt_time); | |
| 226 EXPECT_NE(0, query[2].last_upload_attempt_time); | |
| 227 | |
| 228 EXPECT_EQ(0, query[0].upload_attempts); | |
| 229 EXPECT_EQ(1, query[1].upload_attempts); | |
| 230 EXPECT_EQ(1, query[2].upload_attempts); | |
| 231 | |
| 232 // Attempt to upload and fail again. | |
| 233 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 234 db()->RecordUploadAttempt(reports[1].uuid, false, "")); | |
| 235 | |
| 236 time_t report_2_upload_time = query[2].last_upload_attempt_time; | |
| 237 | |
| 238 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 239 db()->LookUpCrashReport(reports[0].uuid, &query[0])); | |
| 240 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 241 db()->LookUpCrashReport(reports[1].uuid, &query[1])); | |
| 242 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 243 db()->LookUpCrashReport(reports[2].uuid, &query[2])); | |
| 244 | |
| 245 EXPECT_FALSE(query[0].uploaded); | |
| 246 EXPECT_FALSE(query[1].uploaded); | |
| 247 EXPECT_TRUE(query[2].uploaded); | |
| 248 | |
| 249 EXPECT_EQ(0, query[0].last_upload_attempt_time); | |
| 250 EXPECT_GE(query[1].last_upload_attempt_time, report_2_upload_time); | |
| 251 EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time); | |
| 252 | |
| 253 EXPECT_EQ(0, query[0].upload_attempts); | |
| 254 EXPECT_EQ(2, query[1].upload_attempts); | |
| 255 EXPECT_EQ(1, query[2].upload_attempts); | |
| 256 | |
| 257 // Third time's the charm: upload and succeed. | |
| 258 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 259 db()->RecordUploadAttempt(reports[1].uuid, true, "666hahaha")); | |
| 260 | |
| 261 time_t report_1_upload_time = query[1].last_upload_attempt_time; | |
| 262 | |
| 263 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 264 db()->LookUpCrashReport(reports[0].uuid, &query[0])); | |
| 265 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 266 db()->LookUpCrashReport(reports[1].uuid, &query[1])); | |
| 267 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 268 db()->LookUpCrashReport(reports[2].uuid, &query[2])); | |
| 269 | |
| 270 EXPECT_FALSE(query[0].uploaded); | |
| 271 EXPECT_TRUE(query[1].uploaded); | |
| 272 EXPECT_TRUE(query[2].uploaded); | |
| 273 | |
| 274 EXPECT_EQ(0, query[0].last_upload_attempt_time); | |
| 275 EXPECT_GE(query[1].last_upload_attempt_time, report_1_upload_time); | |
| 276 EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time); | |
| 277 | |
| 278 EXPECT_EQ(0, query[0].upload_attempts); | |
| 279 EXPECT_EQ(3, query[1].upload_attempts); | |
| 280 EXPECT_EQ(1, query[2].upload_attempts); | |
| 281 } | |
| 282 | |
| 283 // This test covers both query functions since they are related. | |
| 284 TEST_F(CrashReportDatabaseTest, GetUploadedAndNotUploadedReports) { | |
| 285 std::vector<CrashReportDatabase::Report> reports(5); | |
| 286 CreateCrashReport(&reports[0]); | |
| 287 CreateCrashReport(&reports[1]); | |
| 288 CreateCrashReport(&reports[2]); | |
| 289 CreateCrashReport(&reports[3]); | |
| 290 CreateCrashReport(&reports[4]); | |
| 291 | |
| 292 const UUID& report_0_uuid = reports[0].uuid; | |
| 293 const UUID& report_1_uuid = reports[1].uuid; | |
| 294 const UUID& report_2_uuid = reports[2].uuid; | |
| 295 const UUID& report_3_uuid = reports[3].uuid; | |
| 296 const UUID& report_4_uuid = reports[4].uuid; | |
| 297 | |
| 298 std::vector<const CrashReportDatabase::Report> not_uploaded; | |
| 299 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 300 db()->GetNotUploadedReports(¬_uploaded)); | |
| 301 | |
| 302 std::vector<const CrashReportDatabase::Report> uploaded; | |
| 303 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 304 db()->GetUploadedReports(&uploaded)); | |
| 305 | |
| 306 EXPECT_EQ(reports.size(), not_uploaded.size()); | |
| 307 EXPECT_EQ(0u, uploaded.size()); | |
| 308 | |
| 309 // Upload one report successfully. | |
| 310 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 311 db()->RecordUploadAttempt(report_1_uuid, true, "report1")); | |
| 312 | |
| 313 not_uploaded.clear(); | |
| 314 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 315 db()->GetNotUploadedReports(¬_uploaded)); | |
| 316 uploaded.clear(); | |
| 317 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 318 db()->GetUploadedReports(&uploaded)); | |
| 319 | |
| 320 EXPECT_EQ(4u, not_uploaded.size()); | |
| 321 ASSERT_EQ(1u, uploaded.size()); | |
| 322 | |
| 323 for (const auto& report : not_uploaded) | |
| 324 EXPECT_NE(report_1_uuid, report.uuid); | |
| 325 EXPECT_EQ(report_1_uuid, uploaded[0].uuid); | |
| 326 EXPECT_EQ("report1", uploaded[0].id); | |
| 327 EXPECT_EQ(true, uploaded[0].uploaded); | |
| 328 EXPECT_GT(uploaded[0].last_upload_attempt_time, 0); | |
| 329 EXPECT_EQ(1, uploaded[0].upload_attempts); | |
| 330 | |
| 331 const CrashReportDatabase::Report uploaded_report_1 = uploaded[0]; | |
| 332 | |
| 333 // Fail to upload one report. | |
|
Robert Sesek
2015/01/06 23:40:29
After this, things could be more thorough. I didn'
| |
| 334 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 335 db()->RecordUploadAttempt(report_2_uuid, false, "")); | |
| 336 | |
| 337 not_uploaded.clear(); | |
| 338 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 339 db()->GetNotUploadedReports(¬_uploaded)); | |
| 340 uploaded.clear(); | |
| 341 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 342 db()->GetUploadedReports(&uploaded)); | |
| 343 | |
| 344 EXPECT_EQ(4u, not_uploaded.size()); | |
| 345 ASSERT_EQ(1u, uploaded.size()); | |
| 346 | |
| 347 for (const auto& report : not_uploaded) { | |
| 348 if (report.upload_attempts != 0) { | |
| 349 EXPECT_EQ(report_2_uuid, report.uuid); | |
| 350 EXPECT_GT(report.last_upload_attempt_time, 0); | |
| 351 EXPECT_FALSE(report.uploaded); | |
| 352 EXPECT_TRUE(report.id.empty()); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 // Upload a second report. | |
| 357 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 358 db()->RecordUploadAttempt(report_4_uuid, true, "report_4")); | |
| 359 | |
| 360 not_uploaded.clear(); | |
| 361 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 362 db()->GetNotUploadedReports(¬_uploaded)); | |
| 363 uploaded.clear(); | |
| 364 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 365 db()->GetUploadedReports(&uploaded)); | |
| 366 | |
| 367 EXPECT_EQ(3u, not_uploaded.size()); | |
| 368 ASSERT_EQ(2u, uploaded.size()); | |
| 369 | |
| 370 // Succeed the failed report. | |
| 371 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 372 db()->RecordUploadAttempt(report_2_uuid, true, "report 2")); | |
| 373 | |
| 374 not_uploaded.clear(); | |
| 375 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 376 db()->GetNotUploadedReports(¬_uploaded)); | |
| 377 uploaded.clear(); | |
| 378 EXPECT_EQ(CrashReportDatabase::kNoError, | |
| 379 db()->GetUploadedReports(&uploaded)); | |
| 380 | |
| 381 EXPECT_EQ(2u, not_uploaded.size()); | |
| 382 ASSERT_EQ(3u, uploaded.size()); | |
| 383 | |
| 384 for (const auto& report : not_uploaded) { | |
| 385 EXPECT_TRUE(report.uuid == report_0_uuid || | |
| 386 report.uuid == report_3_uuid); | |
| 387 } | |
| 388 } | |
| 389 | |
| 390 } // namespace | |
| 391 } // namespace test | |
| 392 } // namespace crashpad | |
| OLD | NEW |