Chromium Code Reviews| Index: client/crash_report_database_test.cc |
| diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d240a6a9e60c0d081ba054e33212d38ed8a68297 |
| --- /dev/null |
| +++ b/client/crash_report_database_test.cc |
| @@ -0,0 +1,392 @@ |
| +// Copyright 2015 The Crashpad Authors. All rights reserved. |
| +// |
| +// Licensed under the Apache License, Version 2.0 (the "License"); |
| +// you may not use this file except in compliance with the License. |
| +// You may obtain a copy of the License at |
| +// |
| +// http://www.apache.org/licenses/LICENSE-2.0 |
| +// |
| +// Unless required by applicable law or agreed to in writing, software |
| +// distributed under the License is distributed on an "AS IS" BASIS, |
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| +// See the License for the specific language governing permissions and |
| +// limitations under the License. |
| + |
| +#include "client/crash_report_database.h" |
| + |
| +#include <sys/stat.h> |
| + |
| +#include "gtest/gtest.h" |
| +#include "util/file/file_io.h" |
| +#include "util/test/scoped_temp_dir.h" |
| + |
| +namespace crashpad { |
| +namespace test { |
| +namespace { |
| + |
| +bool FileExistsAtPath(const base::FilePath& path) { |
| +#if defined(OS_POSIX) |
| + struct stat st; |
| + return lstat(path.value().c_str(), &st) == 0; |
| +#else |
| +#error "Not implemented" |
| +#endif |
| +} |
| + |
| +void CreateFile(const base::FilePath& path) { |
| + FileHandle handle = LoggingOpenFileForWrite(path, |
| + FileWriteMode::kCreateOrFail, |
| + FilePermissions::kWorldReadable); |
| + ASSERT_GE(handle, 0); |
| + ASSERT_TRUE( |
| + LoggingWriteFile(handle, path.value().c_str(), path.value().length())); |
| + ASSERT_TRUE(LoggingCloseFile(handle)); |
| +} |
| + |
| +class CrashReportDatabaseTest : public testing::Test { |
| + protected: |
| + // testing::Test: |
| + void SetUp() override { |
| + db_ = CrashReportDatabase::Initialize(path()); |
| + ASSERT_TRUE(db_.get()); |
| + } |
| + |
| + void ResetDatabase() { |
| + db_.reset(); |
| + } |
| + |
| + CrashReportDatabase* db() const { return db_.get(); } |
| + const base::FilePath& path() const { return temp_dir_.path(); } |
| + |
| + void CreateCrashReport(CrashReportDatabase::Report* report) { |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db_->PrepareNewCrashReport(report)); |
| + ExpectPreparedCrashReport(*report); |
| + CreateFile(report->file_path); |
| + ASSERT_TRUE(FileExistsAtPath(report->file_path)); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db_->FinishedWritingCrashReport(report->uuid)); |
| + } |
| + |
| + void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) { |
| + EXPECT_NE(UUID(), report.uuid); |
| + EXPECT_FALSE(report.file_path.empty()); |
| + EXPECT_FALSE(FileExistsAtPath(report.file_path)); |
| + EXPECT_TRUE(report.id.empty()); |
| + EXPECT_FALSE(report.uploaded); |
| + EXPECT_EQ(0, report.last_upload_attempt_time); |
| + EXPECT_EQ(0, report.upload_attempts); |
| + } |
| + |
| + private: |
| + ScopedTempDir temp_dir_; |
| + scoped_ptr<CrashReportDatabase> db_; |
| +}; |
| + |
| +TEST_F(CrashReportDatabaseTest, Initialize) { |
| + // Initialize the database for the first time, creating it. |
| + EXPECT_TRUE(db()); |
| + |
| + // Close and reopen the database at the same path. |
| + ResetDatabase(); |
| + EXPECT_FALSE(db()); |
| + auto db = CrashReportDatabase::Initialize(path()); |
| + EXPECT_TRUE(db.get()); |
| + |
| + std::vector<const CrashReportDatabase::Report> reports; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, db->GetNotUploadedReports(&reports)); |
| + EXPECT_TRUE(reports.empty()); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, db->GetUploadedReports(&reports)); |
| + EXPECT_TRUE(reports.empty()); |
| +} |
| + |
| +TEST_F(CrashReportDatabaseTest, PrepareNewCrashReport) { |
| + CrashReportDatabase::Report report; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->PrepareNewCrashReport(&report)); |
| + ExpectPreparedCrashReport(report); |
| + |
| + CrashReportDatabase::Report query; |
| + EXPECT_EQ(CrashReportDatabase::kReportNotFound, |
| + db()->LookUpCrashReport(report.uuid, &query)); |
| +} |
| + |
| +TEST_F(CrashReportDatabaseTest, FinishedWritingCrashReport) { |
| + CrashReportDatabase::Report report; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->PrepareNewCrashReport(&report)); |
| + ExpectPreparedCrashReport(report); |
| + |
| + CrashReportDatabase::Report query; |
| + EXPECT_EQ(CrashReportDatabase::kReportNotFound, |
| + db()->LookUpCrashReport(report.uuid, &query)); |
| + |
| + CreateFile(report.file_path); |
| + |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->FinishedWritingCrashReport(report.uuid)); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(report.uuid, &query)); |
| + EXPECT_EQ(report.uuid, query.uuid); |
| + EXPECT_TRUE(report.id.empty()); |
| + EXPECT_FALSE(report.uploaded); |
| + EXPECT_EQ(0, report.last_upload_attempt_time); |
| + EXPECT_EQ(0, report.upload_attempts); |
| + |
| + std::vector<const CrashReportDatabase::Report> reports; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(&reports)); |
| + ASSERT_EQ(1u, reports.size()); |
| + EXPECT_EQ(report.uuid, reports[0].uuid); |
| + |
| + reports.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&reports)); |
| + EXPECT_TRUE(reports.empty()); |
| +} |
| + |
| +TEST_F(CrashReportDatabaseTest, LookUpCrashReport) { |
| + UUID uuid; |
| + |
| + { |
| + CrashReportDatabase::Report report; |
| + CreateCrashReport(&report); |
| + uuid = report.uuid; |
| + } |
| + |
| + { |
| + CrashReportDatabase::Report report; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(uuid, &report)); |
| + EXPECT_EQ(uuid, report.uuid); |
| + EXPECT_NE(std::string::npos, report.file_path.value().find(path().value())); |
| + EXPECT_EQ("", report.id); |
| + EXPECT_FALSE(report.uploaded); |
| + EXPECT_EQ(0, report.last_upload_attempt_time); |
| + EXPECT_EQ(0, report.upload_attempts); |
| + } |
| + |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(uuid, true, "test")); |
| + |
| + { |
| + CrashReportDatabase::Report report; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(uuid, &report)); |
| + EXPECT_EQ(uuid, report.uuid); |
| + EXPECT_NE(std::string::npos, report.file_path.value().find(path().value())); |
| + EXPECT_EQ("test", report.id); |
| + EXPECT_TRUE(report.uploaded); |
| + EXPECT_NE(0, report.last_upload_attempt_time); |
| + EXPECT_EQ(1, report.upload_attempts); |
| + } |
| +} |
| + |
| +TEST_F(CrashReportDatabaseTest, FinishedWritingCrashReportError) { |
| + CrashReportDatabase::Report report; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->PrepareNewCrashReport(&report)); |
| + ExpectPreparedCrashReport(report); |
| + |
| + EXPECT_EQ(CrashReportDatabase::kReportNotFound, |
| + db()->FinishedWritingCrashReport(report.uuid)); |
| +} |
| + |
| +TEST_F(CrashReportDatabaseTest, RecordUploadAttempt) { |
| + std::vector<CrashReportDatabase::Report> reports(3); |
| + CreateCrashReport(&reports[0]); |
| + CreateCrashReport(&reports[1]); |
| + CreateCrashReport(&reports[2]); |
| + |
| + // Record two attempts: one successful, one not. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(reports[1].uuid, false, "")); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(reports[2].uuid, true, "abc123")); |
| + |
| + std::vector<CrashReportDatabase::Report> query(3); |
| + |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[0].uuid, &query[0])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[1].uuid, &query[1])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[2].uuid, &query[2])); |
| + |
| + EXPECT_EQ("", query[0].id); |
| + EXPECT_EQ("", query[1].id); |
| + EXPECT_EQ("abc123", query[2].id); |
| + |
| + EXPECT_FALSE(query[0].uploaded); |
| + EXPECT_FALSE(query[1].uploaded); |
| + EXPECT_TRUE(query[2].uploaded); |
| + |
| + EXPECT_EQ(0, query[0].last_upload_attempt_time); |
| + EXPECT_NE(0, query[1].last_upload_attempt_time); |
| + EXPECT_NE(0, query[2].last_upload_attempt_time); |
| + |
| + EXPECT_EQ(0, query[0].upload_attempts); |
| + EXPECT_EQ(1, query[1].upload_attempts); |
| + EXPECT_EQ(1, query[2].upload_attempts); |
| + |
| + // Attempt to upload and fail again. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(reports[1].uuid, false, "")); |
| + |
| + time_t report_2_upload_time = query[2].last_upload_attempt_time; |
| + |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[0].uuid, &query[0])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[1].uuid, &query[1])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[2].uuid, &query[2])); |
| + |
| + EXPECT_FALSE(query[0].uploaded); |
| + EXPECT_FALSE(query[1].uploaded); |
| + EXPECT_TRUE(query[2].uploaded); |
| + |
| + EXPECT_EQ(0, query[0].last_upload_attempt_time); |
| + EXPECT_GE(query[1].last_upload_attempt_time, report_2_upload_time); |
| + EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time); |
| + |
| + EXPECT_EQ(0, query[0].upload_attempts); |
| + EXPECT_EQ(2, query[1].upload_attempts); |
| + EXPECT_EQ(1, query[2].upload_attempts); |
| + |
| + // Third time's the charm: upload and succeed. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(reports[1].uuid, true, "666hahaha")); |
| + |
| + time_t report_1_upload_time = query[1].last_upload_attempt_time; |
| + |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[0].uuid, &query[0])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[1].uuid, &query[1])); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->LookUpCrashReport(reports[2].uuid, &query[2])); |
| + |
| + EXPECT_FALSE(query[0].uploaded); |
| + EXPECT_TRUE(query[1].uploaded); |
| + EXPECT_TRUE(query[2].uploaded); |
| + |
| + EXPECT_EQ(0, query[0].last_upload_attempt_time); |
| + EXPECT_GE(query[1].last_upload_attempt_time, report_1_upload_time); |
| + EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time); |
| + |
| + EXPECT_EQ(0, query[0].upload_attempts); |
| + EXPECT_EQ(3, query[1].upload_attempts); |
| + EXPECT_EQ(1, query[2].upload_attempts); |
| +} |
| + |
| +// This test covers both query functions since they are related. |
| +TEST_F(CrashReportDatabaseTest, GetUploadedAndNotUploadedReports) { |
| + std::vector<CrashReportDatabase::Report> reports(5); |
| + CreateCrashReport(&reports[0]); |
| + CreateCrashReport(&reports[1]); |
| + CreateCrashReport(&reports[2]); |
| + CreateCrashReport(&reports[3]); |
| + CreateCrashReport(&reports[4]); |
| + |
| + const UUID& report_0_uuid = reports[0].uuid; |
| + const UUID& report_1_uuid = reports[1].uuid; |
| + const UUID& report_2_uuid = reports[2].uuid; |
| + const UUID& report_3_uuid = reports[3].uuid; |
| + const UUID& report_4_uuid = reports[4].uuid; |
| + |
| + std::vector<const CrashReportDatabase::Report> not_uploaded; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(¬_uploaded)); |
| + |
| + std::vector<const CrashReportDatabase::Report> uploaded; |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&uploaded)); |
| + |
| + EXPECT_EQ(reports.size(), not_uploaded.size()); |
| + EXPECT_EQ(0u, uploaded.size()); |
| + |
| + // Upload one report successfully. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(report_1_uuid, true, "report1")); |
| + |
| + not_uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(¬_uploaded)); |
| + uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&uploaded)); |
| + |
| + EXPECT_EQ(4u, not_uploaded.size()); |
| + ASSERT_EQ(1u, uploaded.size()); |
| + |
| + for (const auto& report : not_uploaded) |
| + EXPECT_NE(report_1_uuid, report.uuid); |
| + EXPECT_EQ(report_1_uuid, uploaded[0].uuid); |
| + EXPECT_EQ("report1", uploaded[0].id); |
| + EXPECT_EQ(true, uploaded[0].uploaded); |
| + EXPECT_GT(uploaded[0].last_upload_attempt_time, 0); |
| + EXPECT_EQ(1, uploaded[0].upload_attempts); |
| + |
| + const CrashReportDatabase::Report uploaded_report_1 = uploaded[0]; |
| + |
| + // Fail to upload one report. |
|
Robert Sesek
2015/01/06 23:40:29
After this, things could be more thorough. I didn'
|
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(report_2_uuid, false, "")); |
| + |
| + not_uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(¬_uploaded)); |
| + uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&uploaded)); |
| + |
| + EXPECT_EQ(4u, not_uploaded.size()); |
| + ASSERT_EQ(1u, uploaded.size()); |
| + |
| + for (const auto& report : not_uploaded) { |
| + if (report.upload_attempts != 0) { |
| + EXPECT_EQ(report_2_uuid, report.uuid); |
| + EXPECT_GT(report.last_upload_attempt_time, 0); |
| + EXPECT_FALSE(report.uploaded); |
| + EXPECT_TRUE(report.id.empty()); |
| + } |
| + } |
| + |
| + // Upload a second report. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(report_4_uuid, true, "report_4")); |
| + |
| + not_uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(¬_uploaded)); |
| + uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&uploaded)); |
| + |
| + EXPECT_EQ(3u, not_uploaded.size()); |
| + ASSERT_EQ(2u, uploaded.size()); |
| + |
| + // Succeed the failed report. |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->RecordUploadAttempt(report_2_uuid, true, "report 2")); |
| + |
| + not_uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetNotUploadedReports(¬_uploaded)); |
| + uploaded.clear(); |
| + EXPECT_EQ(CrashReportDatabase::kNoError, |
| + db()->GetUploadedReports(&uploaded)); |
| + |
| + EXPECT_EQ(2u, not_uploaded.size()); |
| + ASSERT_EQ(3u, uploaded.size()); |
| + |
| + for (const auto& report : not_uploaded) { |
| + EXPECT_TRUE(report.uuid == report_0_uuid || |
| + report.uuid == report_3_uuid); |
| + } |
| +} |
| + |
| +} // namespace |
| +} // namespace test |
| +} // namespace crashpad |