Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: client/prune_crash_reports_test.cc

Issue 1392653002: Add functionality to prune old crash reports from the database. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« client/prune_crash_reports.cc ('K') | « client/prune_crash_reports.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« client/prune_crash_reports.cc ('K') | « client/prune_crash_reports.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698