mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-25 22:30:49 +08:00
6c57c083e6
Bug: crashpad:42310127 Change-Id: I8a060afd6d976379064c4177a40b337942252087 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/5951643 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Peter Boström <pbos@chromium.org>
1029 lines
36 KiB
C++
1029 lines
36 KiB
C++
// Copyright 2015 The Crashpad Authors
|
||
//
|
||
// 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 "build/build_config.h"
|
||
#include "client/settings.h"
|
||
#include "gtest/gtest.h"
|
||
#include "test/errors.h"
|
||
#include "test/file.h"
|
||
#include "test/filesystem.h"
|
||
#include "test/scoped_temp_dir.h"
|
||
#include "util/file/file_io.h"
|
||
#include "util/file/filesystem.h"
|
||
|
||
#if BUILDFLAG(IS_IOS)
|
||
#include "util/mac/xattr.h"
|
||
#endif
|
||
|
||
namespace crashpad {
|
||
namespace test {
|
||
namespace {
|
||
|
||
class CrashReportDatabaseTest : public testing::Test {
|
||
public:
|
||
CrashReportDatabaseTest() {}
|
||
|
||
CrashReportDatabaseTest(const CrashReportDatabaseTest&) = delete;
|
||
CrashReportDatabaseTest& operator=(const CrashReportDatabaseTest&) = delete;
|
||
|
||
protected:
|
||
// testing::Test:
|
||
void SetUp() override {
|
||
db_ = CrashReportDatabase::Initialize(path());
|
||
ASSERT_TRUE(db_);
|
||
}
|
||
|
||
void ResetDatabase() { db_.reset(); }
|
||
|
||
CrashReportDatabase* db() { return db_.get(); }
|
||
base::FilePath path() const {
|
||
return temp_dir_.path().Append(FILE_PATH_LITERAL("crashpad_test_database"));
|
||
}
|
||
|
||
void CreateCrashReport(CrashReportDatabase::Report* report) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
ASSERT_EQ(db_->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
static constexpr char kTest[] = "test";
|
||
ASSERT_TRUE(new_report->Writer()->Write(kTest, sizeof(kTest)));
|
||
|
||
char contents[sizeof(kTest)];
|
||
FileReaderInterface* reader = new_report->Reader();
|
||
ASSERT_TRUE(reader->ReadExactly(contents, sizeof(contents)));
|
||
EXPECT_EQ(memcmp(contents, kTest, sizeof(contents)), 0);
|
||
EXPECT_EQ(reader->ReadExactly(contents, 1), 0);
|
||
|
||
UUID uuid;
|
||
EXPECT_EQ(db_->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(db_->LookUpCrashReport(uuid, report),
|
||
CrashReportDatabase::kNoError);
|
||
ExpectPreparedCrashReport(*report);
|
||
}
|
||
|
||
void UploadReport(const UUID& uuid, bool successful, const std::string& id) {
|
||
Settings* const settings = db_->GetSettings();
|
||
ASSERT_TRUE(settings);
|
||
time_t times[2];
|
||
ASSERT_TRUE(settings->GetLastUploadAttemptTime(×[0]));
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> report;
|
||
ASSERT_EQ(db_->GetReportForUploading(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_NE(report->uuid, UUID());
|
||
EXPECT_FALSE(report->file_path.empty());
|
||
EXPECT_TRUE(FileExists(report->file_path)) << report->file_path.value();
|
||
EXPECT_GT(report->creation_time, 0);
|
||
if (successful) {
|
||
EXPECT_EQ(db_->RecordUploadComplete(std::move(report), id),
|
||
CrashReportDatabase::kNoError);
|
||
} else {
|
||
report.reset();
|
||
}
|
||
|
||
ASSERT_TRUE(settings->GetLastUploadAttemptTime(×[1]));
|
||
EXPECT_NE(times[1], 0);
|
||
EXPECT_GE(times[1], times[0]);
|
||
}
|
||
|
||
void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) {
|
||
EXPECT_NE(report.uuid, UUID());
|
||
EXPECT_FALSE(report.file_path.empty());
|
||
EXPECT_TRUE(FileExists(report.file_path)) << report.file_path.value();
|
||
EXPECT_TRUE(report.id.empty());
|
||
EXPECT_GT(report.creation_time, 0);
|
||
EXPECT_FALSE(report.uploaded);
|
||
EXPECT_EQ(report.last_upload_attempt_time, 0);
|
||
EXPECT_EQ(report.upload_attempts, 0);
|
||
EXPECT_FALSE(report.upload_explicitly_requested);
|
||
EXPECT_GE(report.total_size, 0u);
|
||
}
|
||
|
||
void RelocateDatabase() {
|
||
ResetDatabase();
|
||
temp_dir_.Rename();
|
||
SetUp();
|
||
}
|
||
|
||
CrashReportDatabase::OperationStatus RequestUpload(const UUID& uuid) {
|
||
CrashReportDatabase::OperationStatus os = db()->RequestUpload(uuid);
|
||
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db_->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
return os;
|
||
}
|
||
|
||
private:
|
||
ScopedTempDir temp_dir_;
|
||
std::unique_ptr<CrashReportDatabase> db_;
|
||
};
|
||
|
||
TEST_F(CrashReportDatabaseTest, Initialize) {
|
||
// Initialize the database for the first time, creating it.
|
||
ASSERT_TRUE(db());
|
||
|
||
Settings* settings = db()->GetSettings();
|
||
|
||
UUID client_ids[3];
|
||
ASSERT_TRUE(settings->GetClientID(&client_ids[0]));
|
||
EXPECT_NE(client_ids[0], UUID());
|
||
|
||
time_t last_upload_attempt_time;
|
||
ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
|
||
EXPECT_EQ(last_upload_attempt_time, 0);
|
||
|
||
// Close and reopen the database at the same path.
|
||
ResetDatabase();
|
||
EXPECT_FALSE(db());
|
||
auto db = CrashReportDatabase::InitializeWithoutCreating(path());
|
||
ASSERT_TRUE(db);
|
||
|
||
settings = db->GetSettings();
|
||
|
||
ASSERT_TRUE(settings->GetClientID(&client_ids[1]));
|
||
EXPECT_EQ(client_ids[1], client_ids[0]);
|
||
|
||
ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
|
||
EXPECT_EQ(last_upload_attempt_time, 0);
|
||
|
||
// Check that the database can also be opened by the method that is permitted
|
||
// to create it.
|
||
db = CrashReportDatabase::Initialize(path());
|
||
ASSERT_TRUE(db);
|
||
|
||
settings = db->GetSettings();
|
||
|
||
ASSERT_TRUE(settings->GetClientID(&client_ids[2]));
|
||
EXPECT_EQ(client_ids[2], client_ids[0]);
|
||
|
||
ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
|
||
EXPECT_EQ(last_upload_attempt_time, 0);
|
||
|
||
std::vector<CrashReportDatabase::Report> reports;
|
||
EXPECT_EQ(db->GetPendingReports(&reports), CrashReportDatabase::kNoError);
|
||
EXPECT_TRUE(reports.empty());
|
||
reports.clear();
|
||
EXPECT_EQ(db->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
|
||
EXPECT_TRUE(reports.empty());
|
||
|
||
// InitializeWithoutCreating() shouldn’t create a nonexistent database.
|
||
base::FilePath non_database_path =
|
||
path().DirName().Append(FILE_PATH_LITERAL("not_a_database"));
|
||
db = CrashReportDatabase::InitializeWithoutCreating(non_database_path);
|
||
EXPECT_FALSE(db);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, Settings) {
|
||
// Initialize three databases and ensure settings.dat isn't created yet.
|
||
ASSERT_TRUE(db());
|
||
|
||
base::FilePath settings_path =
|
||
path().Append(FILE_PATH_LITERAL("settings.dat"));
|
||
EXPECT_FALSE(FileExists(settings_path));
|
||
|
||
std::unique_ptr<CrashReportDatabase> db2 =
|
||
CrashReportDatabase::Initialize(path());
|
||
ASSERT_TRUE(db2);
|
||
EXPECT_FALSE(FileExists(settings_path));
|
||
|
||
std::unique_ptr<CrashReportDatabase> db3 =
|
||
CrashReportDatabase::Initialize(path());
|
||
ASSERT_TRUE(db3);
|
||
EXPECT_FALSE(FileExists(settings_path));
|
||
|
||
// Ensure settings.dat exists after getter.
|
||
Settings* settings = db3->GetSettings();
|
||
ASSERT_TRUE(settings);
|
||
EXPECT_TRUE(FileExists(settings_path));
|
||
|
||
time_t last_upload_attempt_time = 42;
|
||
ASSERT_TRUE(settings->SetLastUploadAttemptTime(last_upload_attempt_time));
|
||
|
||
// Ensure the first two databases read the same value.
|
||
ASSERT_TRUE(
|
||
db2->GetSettings()->GetLastUploadAttemptTime(&last_upload_attempt_time));
|
||
EXPECT_EQ(last_upload_attempt_time, 42);
|
||
ASSERT_TRUE(
|
||
db()->GetSettings()->GetLastUploadAttemptTime(&last_upload_attempt_time));
|
||
EXPECT_EQ(last_upload_attempt_time, 42);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, NewCrashReport) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
UUID expect_uuid = new_report->ReportID();
|
||
UUID uuid;
|
||
EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(uuid, expect_uuid);
|
||
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
ExpectPreparedCrashReport(report);
|
||
|
||
std::vector<CrashReportDatabase::Report> reports;
|
||
EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(reports.size(), 1u);
|
||
EXPECT_EQ(reports[0].uuid, report.uuid);
|
||
|
||
reports.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
|
||
EXPECT_TRUE(reports.empty());
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, LookUpCrashReport) {
|
||
UUID uuid;
|
||
|
||
{
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
uuid = report.uuid;
|
||
}
|
||
|
||
{
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(report.uuid, uuid);
|
||
EXPECT_NE(report.file_path.value().find(path().value()), std::string::npos);
|
||
EXPECT_EQ(report.id, std::string());
|
||
EXPECT_FALSE(report.uploaded);
|
||
EXPECT_EQ(report.last_upload_attempt_time, 0);
|
||
EXPECT_EQ(report.upload_attempts, 0);
|
||
EXPECT_FALSE(report.upload_explicitly_requested);
|
||
}
|
||
|
||
UploadReport(uuid, true, "test");
|
||
|
||
{
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(report.uuid, uuid);
|
||
EXPECT_NE(report.file_path.value().find(path().value()), std::string::npos);
|
||
EXPECT_EQ(report.id, "test");
|
||
EXPECT_TRUE(report.uploaded);
|
||
EXPECT_NE(report.last_upload_attempt_time, 0);
|
||
EXPECT_EQ(report.upload_attempts, 1);
|
||
EXPECT_FALSE(report.upload_explicitly_requested);
|
||
}
|
||
}
|
||
|
||
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.
|
||
UploadReport(reports[1].uuid, false, std::string());
|
||
UploadReport(reports[2].uuid, true, "abc123");
|
||
|
||
std::vector<CrashReportDatabase::Report> query(3);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(query[0].id, std::string());
|
||
EXPECT_EQ(query[1].id, std::string());
|
||
EXPECT_EQ(query[2].id, "abc123");
|
||
|
||
EXPECT_FALSE(query[0].uploaded);
|
||
EXPECT_FALSE(query[1].uploaded);
|
||
EXPECT_TRUE(query[2].uploaded);
|
||
|
||
EXPECT_EQ(query[0].last_upload_attempt_time, 0);
|
||
EXPECT_NE(query[1].last_upload_attempt_time, 0);
|
||
EXPECT_NE(query[2].last_upload_attempt_time, 0);
|
||
|
||
EXPECT_EQ(query[0].upload_attempts, 0);
|
||
EXPECT_EQ(query[1].upload_attempts, 1);
|
||
EXPECT_EQ(query[2].upload_attempts, 1);
|
||
|
||
// Attempt to upload and fail again.
|
||
UploadReport(reports[1].uuid, false, std::string());
|
||
|
||
time_t report_2_upload_time = query[2].last_upload_attempt_time;
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_FALSE(query[0].uploaded);
|
||
EXPECT_FALSE(query[1].uploaded);
|
||
EXPECT_TRUE(query[2].uploaded);
|
||
|
||
EXPECT_EQ(query[0].last_upload_attempt_time, 0);
|
||
EXPECT_GE(query[1].last_upload_attempt_time, report_2_upload_time);
|
||
EXPECT_EQ(query[2].last_upload_attempt_time, report_2_upload_time);
|
||
|
||
EXPECT_EQ(query[0].upload_attempts, 0);
|
||
EXPECT_EQ(query[1].upload_attempts, 2);
|
||
EXPECT_EQ(query[2].upload_attempts, 1);
|
||
|
||
// Third time's the charm: upload and succeed.
|
||
UploadReport(reports[1].uuid, true, "666hahaha");
|
||
|
||
time_t report_1_upload_time = query[1].last_upload_attempt_time;
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_FALSE(query[0].uploaded);
|
||
EXPECT_TRUE(query[1].uploaded);
|
||
EXPECT_TRUE(query[2].uploaded);
|
||
|
||
EXPECT_EQ(query[0].last_upload_attempt_time, 0);
|
||
EXPECT_GE(query[1].last_upload_attempt_time, report_1_upload_time);
|
||
EXPECT_EQ(query[2].last_upload_attempt_time, report_2_upload_time);
|
||
|
||
EXPECT_EQ(query[0].upload_attempts, 0);
|
||
EXPECT_EQ(query[1].upload_attempts, 3);
|
||
EXPECT_EQ(query[2].upload_attempts, 1);
|
||
}
|
||
|
||
// This test covers both query functions since they are related.
|
||
TEST_F(CrashReportDatabaseTest, GetCompletedAndNotUploadedReports) {
|
||
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<CrashReportDatabase::Report> pending;
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
|
||
std::vector<CrashReportDatabase::Report> completed;
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(pending.size(), reports.size());
|
||
EXPECT_EQ(completed.size(), 0u);
|
||
|
||
// Upload one report successfully.
|
||
UploadReport(report_1_uuid, true, "report1");
|
||
|
||
pending.clear();
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
completed.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(pending.size(), 4u);
|
||
ASSERT_EQ(completed.size(), 1u);
|
||
|
||
for (const auto& report : pending) {
|
||
EXPECT_NE(report.uuid, report_1_uuid);
|
||
EXPECT_FALSE(report.file_path.empty());
|
||
}
|
||
EXPECT_EQ(completed[0].uuid, report_1_uuid);
|
||
EXPECT_EQ(completed[0].id, "report1");
|
||
EXPECT_EQ(completed[0].uploaded, true);
|
||
EXPECT_GT(completed[0].last_upload_attempt_time, 0);
|
||
EXPECT_EQ(completed[0].upload_attempts, 1);
|
||
|
||
// Fail to upload one report.
|
||
UploadReport(report_2_uuid, false, std::string());
|
||
|
||
pending.clear();
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
completed.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(pending.size(), 4u);
|
||
ASSERT_EQ(completed.size(), 1u);
|
||
|
||
for (const auto& report : pending) {
|
||
if (report.upload_attempts != 0) {
|
||
EXPECT_EQ(report.uuid, report_2_uuid);
|
||
EXPECT_GT(report.last_upload_attempt_time, 0);
|
||
EXPECT_FALSE(report.uploaded);
|
||
EXPECT_TRUE(report.id.empty());
|
||
}
|
||
EXPECT_FALSE(report.file_path.empty());
|
||
}
|
||
|
||
// Upload a second report.
|
||
UploadReport(report_4_uuid, true, "report_4");
|
||
|
||
pending.clear();
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
completed.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(pending.size(), 3u);
|
||
ASSERT_EQ(completed.size(), 2u);
|
||
|
||
// Succeed the failed report.
|
||
UploadReport(report_2_uuid, true, "report 2");
|
||
|
||
pending.clear();
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
completed.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(pending.size(), 2u);
|
||
ASSERT_EQ(completed.size(), 3u);
|
||
|
||
for (const auto& report : pending) {
|
||
EXPECT_TRUE(report.uuid == report_0_uuid || report.uuid == report_3_uuid);
|
||
EXPECT_FALSE(report.file_path.empty());
|
||
}
|
||
|
||
// Skip upload for one report.
|
||
EXPECT_EQ(db()->SkipReportUpload(
|
||
report_3_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
pending.clear();
|
||
EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
|
||
completed.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
ASSERT_EQ(pending.size(), 1u);
|
||
ASSERT_EQ(completed.size(), 4u);
|
||
|
||
EXPECT_EQ(pending[0].uuid, report_0_uuid);
|
||
|
||
for (const auto& report : completed) {
|
||
if (report.uuid == report_3_uuid) {
|
||
EXPECT_FALSE(report.uploaded);
|
||
EXPECT_EQ(report.upload_attempts, 0);
|
||
EXPECT_EQ(report.last_upload_attempt_time, 0);
|
||
} else {
|
||
EXPECT_TRUE(report.uploaded);
|
||
EXPECT_GT(report.upload_attempts, 0);
|
||
EXPECT_GT(report.last_upload_attempt_time, 0);
|
||
}
|
||
EXPECT_FALSE(report.file_path.empty());
|
||
}
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, DuelingUploads) {
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report_2;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2),
|
||
CrashReportDatabase::kBusyError);
|
||
EXPECT_FALSE(upload_report_2);
|
||
|
||
EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()),
|
||
CrashReportDatabase::kNoError);
|
||
}
|
||
|
||
#if BUILDFLAG(IS_IOS)
|
||
TEST_F(CrashReportDatabaseTest, InterruptedIOSUploads) {
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
// Set upload_start_time to 10 minutes ago.
|
||
time_t ten_minutes_ago = time(nullptr) - 10 * 60;
|
||
ASSERT_TRUE(
|
||
WriteXattrTimeT(report.file_path,
|
||
"org.chromium.crashpad.database.upload_start_time",
|
||
ten_minutes_ago));
|
||
|
||
std::vector<CrashReportDatabase::Report> reports;
|
||
EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(reports.size(), 1u);
|
||
reports.clear();
|
||
EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
|
||
EXPECT_TRUE(reports.empty());
|
||
|
||
// Getting a stale report will automatically skip it.
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report_2;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2),
|
||
CrashReportDatabase::kReportNotFound);
|
||
EXPECT_FALSE(upload_report_2);
|
||
|
||
// Confirm report was moved from pending to completed.
|
||
EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
|
||
EXPECT_TRUE(reports.empty());
|
||
EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(reports.size(), 1u);
|
||
|
||
EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()),
|
||
CrashReportDatabase::kReportNotFound);
|
||
}
|
||
#endif
|
||
|
||
TEST_F(CrashReportDatabaseTest, UploadAlreadyUploaded) {
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report_2;
|
||
EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2),
|
||
CrashReportDatabase::kReportNotFound);
|
||
EXPECT_FALSE(upload_report_2.get());
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, MoveDatabase) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
UUID uuid;
|
||
EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
RelocateDatabase();
|
||
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
ExpectPreparedCrashReport(report);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, ReportRemoved) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
UUID uuid;
|
||
EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_TRUE(LoggingRemoveFile(report.file_path));
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kReportNotFound);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, DeleteReport) {
|
||
CrashReportDatabase::Report keep_pending;
|
||
CrashReportDatabase::Report delete_pending;
|
||
CrashReportDatabase::Report keep_completed;
|
||
CrashReportDatabase::Report delete_completed;
|
||
|
||
CreateCrashReport(&keep_pending);
|
||
CreateCrashReport(&delete_pending);
|
||
CreateCrashReport(&keep_completed);
|
||
CreateCrashReport(&delete_completed);
|
||
|
||
EXPECT_TRUE(FileExists(keep_pending.file_path));
|
||
EXPECT_TRUE(FileExists(delete_pending.file_path));
|
||
EXPECT_TRUE(FileExists(keep_completed.file_path));
|
||
EXPECT_TRUE(FileExists(delete_completed.file_path));
|
||
|
||
UploadReport(keep_completed.uuid, true, "1");
|
||
UploadReport(delete_completed.uuid, true, "2");
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(keep_completed.uuid, &keep_completed),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(delete_completed.uuid, &delete_completed),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_TRUE(FileExists(keep_completed.file_path));
|
||
EXPECT_TRUE(FileExists(delete_completed.file_path));
|
||
|
||
EXPECT_EQ(db()->DeleteReport(delete_pending.uuid),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_FALSE(FileExists(delete_pending.file_path));
|
||
EXPECT_EQ(db()->LookUpCrashReport(delete_pending.uuid, &delete_pending),
|
||
CrashReportDatabase::kReportNotFound);
|
||
EXPECT_EQ(db()->DeleteReport(delete_pending.uuid),
|
||
CrashReportDatabase::kReportNotFound);
|
||
|
||
EXPECT_EQ(db()->DeleteReport(delete_completed.uuid),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_FALSE(FileExists(delete_completed.file_path));
|
||
EXPECT_EQ(db()->LookUpCrashReport(delete_completed.uuid, &delete_completed),
|
||
CrashReportDatabase::kReportNotFound);
|
||
EXPECT_EQ(db()->DeleteReport(delete_completed.uuid),
|
||
CrashReportDatabase::kReportNotFound);
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(keep_pending.uuid, &keep_pending),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(db()->LookUpCrashReport(keep_completed.uuid, &keep_completed),
|
||
CrashReportDatabase::kNoError);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, DeleteReportEmptyingDatabase) {
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
|
||
EXPECT_TRUE(FileExists(report.file_path));
|
||
|
||
UploadReport(report.uuid, true, "1");
|
||
|
||
EXPECT_EQ(db()->LookUpCrashReport(report.uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_TRUE(FileExists(report.file_path));
|
||
|
||
// This causes an empty database to be written, make sure this is handled.
|
||
EXPECT_EQ(db()->DeleteReport(report.uuid), CrashReportDatabase::kNoError);
|
||
EXPECT_FALSE(FileExists(report.file_path));
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, ReadEmptyDatabase) {
|
||
CrashReportDatabase::Report report;
|
||
CreateCrashReport(&report);
|
||
EXPECT_EQ(db()->DeleteReport(report.uuid), CrashReportDatabase::kNoError);
|
||
|
||
// Deleting and the creating another report causes an empty database to be
|
||
// loaded. Make sure this is handled.
|
||
|
||
CrashReportDatabase::Report report2;
|
||
CreateCrashReport(&report2);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, RequestUpload) {
|
||
std::vector<CrashReportDatabase::Report> reports(2);
|
||
CreateCrashReport(&reports[0]);
|
||
CreateCrashReport(&reports[1]);
|
||
|
||
const UUID& report_0_uuid = reports[0].uuid;
|
||
const UUID& report_1_uuid = reports[1].uuid;
|
||
|
||
// Skipped report gets back to pending state after RequestUpload is called.
|
||
EXPECT_EQ(db()->SkipReportUpload(
|
||
report_1_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
std::vector<CrashReportDatabase::Report> pending_reports;
|
||
CrashReportDatabase::OperationStatus os =
|
||
db()->GetPendingReports(&pending_reports);
|
||
EXPECT_EQ(os, CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(pending_reports.size(), 1u);
|
||
EXPECT_EQ(report_0_uuid, pending_reports[0].uuid);
|
||
|
||
pending_reports.clear();
|
||
EXPECT_EQ(RequestUpload(report_1_uuid), CrashReportDatabase::kNoError);
|
||
os = db()->GetPendingReports(&pending_reports);
|
||
EXPECT_EQ(os, CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(pending_reports.size(), 2u);
|
||
|
||
// Check individual reports.
|
||
const CrashReportDatabase::Report* explicitly_requested_report;
|
||
const CrashReportDatabase::Report* pending_report;
|
||
if (pending_reports[0].uuid == report_0_uuid) {
|
||
pending_report = &pending_reports[0];
|
||
explicitly_requested_report = &pending_reports[1];
|
||
} else {
|
||
pending_report = &pending_reports[1];
|
||
explicitly_requested_report = &pending_reports[0];
|
||
}
|
||
|
||
EXPECT_EQ(pending_report->uuid, report_0_uuid);
|
||
EXPECT_FALSE(pending_report->upload_explicitly_requested);
|
||
|
||
EXPECT_EQ(explicitly_requested_report->uuid, report_1_uuid);
|
||
EXPECT_TRUE(explicitly_requested_report->upload_explicitly_requested);
|
||
|
||
// Explicitly requested reports will not have upload_explicitly_requested bit
|
||
// after getting skipped.
|
||
EXPECT_EQ(db()->SkipReportUpload(
|
||
report_1_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
|
||
CrashReportDatabase::kNoError);
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(report_1_uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_FALSE(report.upload_explicitly_requested);
|
||
|
||
// Pending report gets correctly affected after RequestUpload is called.
|
||
pending_reports.clear();
|
||
EXPECT_EQ(RequestUpload(report_0_uuid), CrashReportDatabase::kNoError);
|
||
os = db()->GetPendingReports(&pending_reports);
|
||
EXPECT_EQ(os, CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(pending_reports.size(), 1u);
|
||
EXPECT_EQ(report_0_uuid, pending_reports[0].uuid);
|
||
EXPECT_TRUE(pending_reports[0].upload_explicitly_requested);
|
||
|
||
// Already uploaded report cannot be requested for the new upload.
|
||
UploadReport(report_0_uuid, true, "1");
|
||
EXPECT_EQ(RequestUpload(report_0_uuid),
|
||
CrashReportDatabase::kCannotRequestUpload);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, Attachments) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
FileWriter* attach_some_file = new_report->AddAttachment("some_file");
|
||
ASSERT_NE(attach_some_file, nullptr);
|
||
static constexpr char test_data[] = "test data";
|
||
attach_some_file->Write(test_data, sizeof(test_data));
|
||
|
||
FileWriter* failed_attach = new_report->AddAttachment("not/a valid fi!e");
|
||
EXPECT_EQ(failed_attach, nullptr);
|
||
|
||
UUID expect_uuid = new_report->ReportID();
|
||
UUID uuid;
|
||
ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(uuid, expect_uuid);
|
||
|
||
CrashReportDatabase::Report report;
|
||
EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
ExpectPreparedCrashReport(report);
|
||
|
||
std::vector<CrashReportDatabase::Report> reports;
|
||
EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
|
||
ASSERT_EQ(reports.size(), 1u);
|
||
EXPECT_EQ(reports[0].uuid, report.uuid);
|
||
|
||
std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
|
||
ASSERT_EQ(db()->GetReportForUploading(reports[0].uuid, &upload_report),
|
||
CrashReportDatabase::kNoError);
|
||
std::map<std::string, FileReader*> result_attachments =
|
||
upload_report->GetAttachments();
|
||
EXPECT_EQ(result_attachments.size(), 1u);
|
||
EXPECT_NE(result_attachments.find("some_file"), result_attachments.end());
|
||
char result_buffer[sizeof(test_data)];
|
||
result_attachments["some_file"]->Read(result_buffer, sizeof(result_buffer));
|
||
EXPECT_EQ(memcmp(test_data, result_buffer, sizeof(test_data)), 0);
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, OrphanedAttachments) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
FileWriter* file1 = new_report->AddAttachment("file1");
|
||
ASSERT_NE(file1, nullptr);
|
||
FileWriter* file2 = new_report->AddAttachment("file2");
|
||
ASSERT_NE(file2, nullptr);
|
||
|
||
UUID expect_uuid = new_report->ReportID();
|
||
UUID uuid;
|
||
ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(uuid, expect_uuid);
|
||
|
||
CrashReportDatabase::Report report;
|
||
ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
ASSERT_TRUE(LoggingRemoveFile(report.file_path));
|
||
|
||
#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
|
||
// CrashReportDatabaseMac stores metadata in xattrs and does not have .meta
|
||
// files.
|
||
// CrashReportDatabaseWin stores metadata in a global metadata file and not
|
||
// per report.
|
||
ASSERT_TRUE(LoggingRemoveFile(base::FilePath(
|
||
report.file_path.RemoveFinalExtension().value() + ".meta")));
|
||
#endif
|
||
|
||
ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kReportNotFound);
|
||
|
||
#if BUILDFLAG(IS_WIN)
|
||
const std::wstring uuid_string = uuid.ToWString();
|
||
#else
|
||
const std::string uuid_string = uuid.ToString();
|
||
#endif
|
||
base::FilePath report_attachments_dir(
|
||
path().Append(FILE_PATH_LITERAL("attachments")).Append(uuid_string));
|
||
base::FilePath file_path1(
|
||
report_attachments_dir.Append(FILE_PATH_LITERAL("file1")));
|
||
base::FilePath file_path2(
|
||
report_attachments_dir.Append(FILE_PATH_LITERAL("file2")));
|
||
EXPECT_TRUE(FileExists(file_path1));
|
||
EXPECT_TRUE(FileExists(file_path1));
|
||
|
||
#if BUILDFLAG(IS_WIN)
|
||
// On Windows, reports removed from metadata are counted, even if the file
|
||
// is not on the disk.
|
||
EXPECT_EQ(db()->CleanDatabase(0), 1);
|
||
#else
|
||
EXPECT_EQ(db()->CleanDatabase(0), 0);
|
||
#endif
|
||
|
||
EXPECT_FALSE(FileExists(file_path1));
|
||
EXPECT_FALSE(FileExists(file_path2));
|
||
EXPECT_FALSE(FileExists(report_attachments_dir));
|
||
}
|
||
|
||
// This test uses knowledge of the database format to break it, so it only
|
||
// applies to the unfified database implementation.
|
||
#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
|
||
TEST_F(CrashReportDatabaseTest, CleanBrokenDatabase) {
|
||
// Remove report files if metadata goes missing.
|
||
CrashReportDatabase::Report report;
|
||
ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
|
||
|
||
const base::FilePath metadata(
|
||
report.file_path.RemoveFinalExtension().value() +
|
||
FILE_PATH_LITERAL(".meta"));
|
||
ASSERT_TRUE(PathExists(report.file_path));
|
||
ASSERT_TRUE(PathExists(metadata));
|
||
|
||
ASSERT_TRUE(LoggingRemoveFile(metadata));
|
||
EXPECT_EQ(db()->CleanDatabase(0), 1);
|
||
|
||
EXPECT_FALSE(PathExists(report.file_path));
|
||
EXPECT_FALSE(PathExists(metadata));
|
||
|
||
// Remove metadata files if reports go missing.
|
||
ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
|
||
const base::FilePath metadata2(
|
||
report.file_path.RemoveFinalExtension().value() +
|
||
FILE_PATH_LITERAL(".meta"));
|
||
ASSERT_TRUE(PathExists(report.file_path));
|
||
ASSERT_TRUE(PathExists(metadata2));
|
||
|
||
ASSERT_TRUE(LoggingRemoveFile(report.file_path));
|
||
EXPECT_EQ(db()->CleanDatabase(0), 1);
|
||
|
||
EXPECT_FALSE(PathExists(report.file_path));
|
||
EXPECT_FALSE(PathExists(metadata2));
|
||
|
||
// Remove stale new files.
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
new_report->Writer()->Close();
|
||
EXPECT_EQ(db()->CleanDatabase(0), 1);
|
||
|
||
// Remove stale lock files and their associated reports.
|
||
ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
|
||
const base::FilePath metadata3(
|
||
report.file_path.RemoveFinalExtension().value() +
|
||
FILE_PATH_LITERAL(".meta"));
|
||
ASSERT_TRUE(PathExists(report.file_path));
|
||
ASSERT_TRUE(PathExists(metadata3));
|
||
|
||
const base::FilePath lockpath(
|
||
report.file_path.RemoveFinalExtension().value() +
|
||
FILE_PATH_LITERAL(".lock"));
|
||
ScopedFileHandle handle(LoggingOpenFileForWrite(
|
||
lockpath, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly));
|
||
ASSERT_TRUE(handle.is_valid());
|
||
|
||
time_t expired_timestamp = time(nullptr) - 60 * 60 * 24 * 3;
|
||
|
||
ASSERT_TRUE(LoggingWriteFile(
|
||
handle.get(), &expired_timestamp, sizeof(expired_timestamp)));
|
||
ASSERT_TRUE(LoggingCloseFile(handle.release()));
|
||
|
||
EXPECT_EQ(db()->CleanDatabase(0), 1);
|
||
|
||
EXPECT_FALSE(PathExists(report.file_path));
|
||
EXPECT_FALSE(PathExists(metadata3));
|
||
}
|
||
#endif // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
|
||
|
||
TEST_F(CrashReportDatabaseTest, TotalSize_MainReportOnly) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
// Main report.
|
||
static constexpr char main_report_data[] = "dlbvandslhb";
|
||
ASSERT_TRUE(
|
||
new_report->Writer()->Write(main_report_data, sizeof(main_report_data)));
|
||
|
||
UUID uuid;
|
||
ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
CrashReportDatabase::Report report;
|
||
ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
EXPECT_EQ(report.total_size, sizeof(main_report_data));
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, GetReportSize_RightSizeWithAttachments) {
|
||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||
ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
// Main report.
|
||
static constexpr char main_report_data[] = "dlbvandslhb";
|
||
ASSERT_TRUE(
|
||
new_report->Writer()->Write(main_report_data, sizeof(main_report_data)));
|
||
|
||
// First attachment.
|
||
FileWriter* attachment_1 = new_report->AddAttachment("my_attachment_1");
|
||
ASSERT_NE(attachment_1, nullptr);
|
||
static constexpr char attachment_1_data[] = "vKDnidhvbiudshoihbvdsoiuh nhh";
|
||
attachment_1->Write(attachment_1_data, sizeof(attachment_1_data));
|
||
|
||
// Second attachment.
|
||
FileWriter* attachment_2 = new_report->AddAttachment("my_attachment_2");
|
||
ASSERT_NE(attachment_2, nullptr);
|
||
static constexpr char attachment_2_data[] = "sgvsvgusiyguysigfkhpmo-[";
|
||
attachment_2->Write(attachment_2_data, sizeof(attachment_2_data));
|
||
|
||
UUID uuid;
|
||
ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
|
||
CrashReportDatabase::kNoError);
|
||
|
||
CrashReportDatabase::Report report;
|
||
ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
|
||
CrashReportDatabase::kNoError);
|
||
EXPECT_EQ(report.total_size,
|
||
sizeof(main_report_data) + sizeof(attachment_1_data) +
|
||
sizeof(attachment_2_data));
|
||
}
|
||
|
||
TEST_F(CrashReportDatabaseTest, InitializeFromLargerFileRetainsClientId) {
|
||
// Initialize the database for the first time, creating it.
|
||
ASSERT_TRUE(db());
|
||
|
||
const base::FilePath settings_path =
|
||
path().Append(FILE_PATH_LITERAL("settings.dat"));
|
||
EXPECT_FALSE(FileExists(settings_path));
|
||
|
||
Settings* settings = db()->GetSettings();
|
||
ASSERT_TRUE(settings);
|
||
EXPECT_TRUE(FileExists(settings_path));
|
||
|
||
UUID client_id;
|
||
ASSERT_TRUE(settings->GetClientID(&client_id));
|
||
EXPECT_NE(client_id, UUID());
|
||
|
||
// Close and reopen the database at the same path.
|
||
ResetDatabase();
|
||
EXPECT_FALSE(db());
|
||
EXPECT_TRUE(FileExists(settings_path));
|
||
|
||
// Append some data, to ensure that we can open settings even if a future
|
||
// version has added additional field to Settings (forwards compatible).
|
||
FileWriter settings_writer;
|
||
ASSERT_TRUE(settings_writer.Open(
|
||
settings_path, FileWriteMode::kReuseOrFail, FilePermissions::kOwnerOnly));
|
||
ASSERT_NE(settings_writer.Seek(0, SEEK_END), 0);
|
||
constexpr uint64_t extra_garbage = 0xBADF00D;
|
||
ASSERT_TRUE(settings_writer.Write(&extra_garbage, sizeof(extra_garbage)));
|
||
settings_writer.Close();
|
||
|
||
auto db = CrashReportDatabase::InitializeWithoutCreating(path());
|
||
ASSERT_TRUE(db);
|
||
|
||
settings = db->GetSettings();
|
||
ASSERT_TRUE(settings);
|
||
|
||
// Make sure that the reopened settings retained the original client id and
|
||
// wasn't recreated.
|
||
UUID reopened_client_id;
|
||
ASSERT_TRUE(settings->GetClientID(&reopened_client_id));
|
||
EXPECT_EQ(client_id, reopened_client_id);
|
||
}
|
||
|
||
} // namespace
|
||
} // namespace test
|
||
} // namespace crashpad
|