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. |
| 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 |