Chromium Code Reviews| Index: client/prune_crash_reports_test.cc |
| diff --git a/client/prune_crash_reports_test.cc b/client/prune_crash_reports_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2da7a88dc8f44da72397b853cc7c4335d48ccca5 |
| --- /dev/null |
| +++ b/client/prune_crash_reports_test.cc |
| @@ -0,0 +1,264 @@ |
| +// 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/prune_crash_reports.h" |
| + |
| +#include <stdlib.h> |
| + |
| +#include <algorithm> |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "gtest/gtest.h" |
| +#include "test/scoped_temp_dir.h" |
| +#include "util/file/file_io.h" |
| + |
| +namespace crashpad { |
| +namespace test { |
| +namespace { |
| + |
| +class TestDatabase : public CrashReportDatabase { |
|
Mark Mentovai
2015/10/07 03:54:28
I don’t know if gmock would make the TestDatabase
Robert Sesek
2015/10/07 16:24:35
Gmock is never easy to deal with. But it is less c
|
| + public: |
| + TestDatabase() |
| + : pending_reports_(), completed_reports_(), deleted_reports_() {} |
| + ~TestDatabase() override {} |
| + |
| + std::vector<Report>* pending_reports() { return &pending_reports_; } |
| + std::vector<Report>* completed_reports() { return &completed_reports_; } |
| + |
| + const std::vector<UUID>& deleted_reports() { return deleted_reports_; } |
| + |
| + // CrashReportDatabase: |
| + Settings* GetSettings() override { return nullptr; } |
| + OperationStatus PrepareNewCrashReport(NewReport** report) override { |
| + return kDatabaseError; |
| + } |
| + |
| + OperationStatus FinishedWritingCrashReport(NewReport* report, |
| + UUID* uuid) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus ErrorWritingCrashReport(NewReport* report) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus LookUpCrashReport(const UUID& uuid, |
| + Report* report) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus GetPendingReports(std::vector<Report>* reports) override { |
| + *reports = pending_reports_; |
| + return kNoError; |
| + } |
| + OperationStatus GetCompletedReports(std::vector<Report>* reports) override { |
| + *reports = completed_reports_; |
| + return kNoError; |
| + } |
| + OperationStatus GetReportForUploading(const UUID& uuid, |
| + const Report** report) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus RecordUploadAttempt(const Report* report, |
| + bool successful, |
| + const std::string& id) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus SkipReportUpload(const UUID& uuid) override { |
| + return kDatabaseError; |
| + } |
| + OperationStatus DeleteReport(const UUID& uuid) override { |
| + auto condition = [uuid](const CrashReportDatabase::Report& report) { |
| + return report.uuid == uuid; |
| + }; |
| + |
| + auto it = std::remove_if(pending_reports_.begin(), pending_reports_.end(), |
| + condition); |
| + if (it != pending_reports_.end()) |
| + pending_reports_.erase(it); |
| + |
| + it = std::remove_if(completed_reports_.begin(), completed_reports_.end(), |
| + condition); |
| + if (it != completed_reports_.end()) |
| + completed_reports_.erase(it); |
| + |
| + deleted_reports_.push_back(uuid); |
| + return kNoError; |
| + } |
| + |
| + private: |
| + std::vector<Report> pending_reports_; |
| + std::vector<Report> completed_reports_; |
| + std::vector<UUID> deleted_reports_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestDatabase); |
| +}; |
| + |
| +time_t NDaysAgo(int num_days) { |
| + return time(nullptr) - (num_days * 60 * 60 * 24); |
| +} |
| + |
| +TEST(PruneCrashReports, AgeCondition) { |
| + CrashReportDatabase::Report report_80_days; |
| + report_80_days.creation_time = NDaysAgo(80); |
| + |
| + CrashReportDatabase::Report report_10_days; |
| + report_10_days.creation_time = NDaysAgo(10); |
| + |
| + CrashReportDatabase::Report report_30_days; |
| + report_30_days.creation_time = NDaysAgo(30); |
| + |
| + AgePruneCondition condition(30); |
| + EXPECT_TRUE(condition.ShouldPruneReport(report_80_days)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_10_days)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_30_days)); |
| +} |
| + |
| +TEST(PruneCrashReports, SizeCondition) { |
| + ScopedTempDir temp_dir; |
| + |
| + CrashReportDatabase::Report report_128; |
| + report_128.file_path = temp_dir.path().Append(FILE_PATH_LITERAL("file128")); |
| + CrashReportDatabase::Report report_1024; |
| + report_1024.file_path = temp_dir.path().Append(FILE_PATH_LITERAL("file1024")); |
| + |
| + { |
| + ScopedFileHandle scoped_file_128( |
| + LoggingOpenFileForWrite(report_128.file_path, |
| + FileWriteMode::kCreateOrFail, |
| + FilePermissions::kOwnerOnly)); |
| + ASSERT_TRUE(scoped_file_128.is_valid()); |
| + |
| + std::string string; |
| + for (int i = 0; i < 128; ++i) |
| + string.push_back(i); |
|
scottmg
2015/10/06 22:22:07
warning converting int to char here on Windows.
Robert Sesek
2015/10/07 16:24:35
Done.
|
| + ASSERT_TRUE(LoggingWriteFile(scoped_file_128.get(), |
| + string.c_str(), string.length())); |
| + |
| + ScopedFileHandle scoped_file_1024( |
| + LoggingOpenFileForWrite(report_1024.file_path, |
| + FileWriteMode::kCreateOrFail, |
| + FilePermissions::kOwnerOnly)); |
| + ASSERT_TRUE(scoped_file_1024.is_valid()); |
| + |
| + for (int i = 0; i < 1024; i += string.size()) { |
| + ASSERT_TRUE(LoggingWriteFile(scoped_file_1024.get(), |
| + string.c_str(), string.length())); |
| + } |
| + } |
| + |
| + { |
| + DatabaseSizePruneCondition condition(512); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_128)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_128)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_128)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_128)); |
| + EXPECT_TRUE(condition.ShouldPruneReport(report_128)); |
| + } |
| + |
| + { |
| + DatabaseSizePruneCondition condition(512); |
| + EXPECT_TRUE(condition.ShouldPruneReport(report_1024)); |
| + } |
| + |
| + { |
| + DatabaseSizePruneCondition condition(2100); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_1024)); |
| + EXPECT_FALSE(condition.ShouldPruneReport(report_1024)); |
| + EXPECT_TRUE(condition.ShouldPruneReport(report_128)); |
| + } |
| +} |
| + |
| +class StaticCondition : public PruneCondition { |
| + public: |
| + explicit StaticCondition(bool value) : value_(value) {} |
| + ~StaticCondition() {} |
| + |
| + bool ShouldPruneReport(const CrashReportDatabase::Report& report) override { |
| + return value_; |
| + } |
| + |
| + private: |
| + bool value_; |
| +}; |
| + |
| +TEST(PruneCrashReports, BinaryAND) { |
| + BinaryPruneCondition false_false(BinaryPruneCondition::AND, |
| + new StaticCondition(false), new StaticCondition(false)); |
| + BinaryPruneCondition false_true(BinaryPruneCondition::AND, |
| + new StaticCondition(false), new StaticCondition(true)); |
| + BinaryPruneCondition true_false(BinaryPruneCondition::AND, |
| + new StaticCondition(true), new StaticCondition(false)); |
| + BinaryPruneCondition true_true(BinaryPruneCondition::AND, |
| + new StaticCondition(true), new StaticCondition(true)); |
| + |
| + CrashReportDatabase::Report report; |
| + |
| + EXPECT_FALSE(false_false.ShouldPruneReport(report)); |
| + EXPECT_FALSE(false_true.ShouldPruneReport(report)); |
| + EXPECT_FALSE(true_false.ShouldPruneReport(report)); |
| + EXPECT_TRUE(true_true.ShouldPruneReport(report)); |
| +} |
| + |
| +TEST(PruneCrashReports, BinaryOR) { |
| + BinaryPruneCondition false_false(BinaryPruneCondition::OR, |
| + new StaticCondition(false), new StaticCondition(false)); |
| + BinaryPruneCondition false_true(BinaryPruneCondition::OR, |
| + new StaticCondition(false), new StaticCondition(true)); |
| + BinaryPruneCondition true_false(BinaryPruneCondition::OR, |
| + new StaticCondition(true), new StaticCondition(false)); |
| + BinaryPruneCondition true_true(BinaryPruneCondition::OR, |
| + new StaticCondition(true), new StaticCondition(true)); |
| + |
| + CrashReportDatabase::Report report; |
| + |
| + EXPECT_FALSE(false_false.ShouldPruneReport(report)); |
| + EXPECT_TRUE(false_true.ShouldPruneReport(report)); |
| + EXPECT_TRUE(true_false.ShouldPruneReport(report)); |
| + EXPECT_TRUE(true_true.ShouldPruneReport(report)); |
| +} |
| + |
| +TEST(PruneCrashReports, PruneOrder) { |
| + TestDatabase db; |
| + |
| + std::vector<CrashReportDatabase::Report> reports; |
| + for (int i = 0; i < 10; ++i) { |
| + CrashReportDatabase::Report temp; |
| + temp.uuid.data_1 = i; |
| + temp.creation_time = NDaysAgo(i * 10); |
| + reports.push_back(temp); |
| + } |
| + |
| + // The randomness from std::rand() is not, so use arc4random instead. |
| + std::random_shuffle(reports.begin(), reports.end(), [](int rand_max) { |
| + return arc4random() % rand_max; |
|
scottmg
2015/10/06 22:22:07
arc4random doesn't exist on Windows.
scottmg
2015/10/06 22:35:29
(Should have mentioned we have base/rand_util.h wh
Robert Sesek
2015/10/07 16:24:35
Done.
|
| + }); |
| + db.pending_reports()->insert(db.pending_reports()->end(), |
| + reports.begin(), reports.begin() + 5); |
| + db.completed_reports()->insert(db.completed_reports()->end(), |
| + reports.begin() + 5, reports.end()); |
| + |
| + StaticCondition delete_all(true); |
| + PruneCrashReportDatabase(&db, &delete_all); |
| + |
| + ASSERT_EQ(reports.size(), db.deleted_reports().size()); |
| + for (size_t i = 0; i < reports.size(); ++i) { |
| + EXPECT_EQ(i, db.deleted_reports()[i].data_1); |
| + } |
| + |
| + EXPECT_TRUE(db.pending_reports()->empty()); |
| + EXPECT_TRUE(db.completed_reports()->empty()); |
| +} |
| + |
| +} // namespace |
| +} // namespace test |
| +} // namespace crashpad |