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

Side by Side Diff: client/crash_report_database_test.cc

Issue 842513002: Create CrashReportDatabase interface, a test, and a Mac implementation. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address comments Created 5 years, 10 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 unified diff | Download patch
« no previous file with comments | « client/crash_report_database_mac.mm ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 CrashReportDatabase::NewReport* new_report;
63 EXPECT_EQ(CrashReportDatabase::kNoError,
64 db_->PrepareNewCrashReport(&new_report));
65 const char kTest[] = "test";
66 ASSERT_TRUE(LoggingWriteFile(new_report->handle, kTest, sizeof(kTest)));
67
68 UUID uuid;
69 EXPECT_EQ(CrashReportDatabase::kNoError,
70 db_->FinishedWritingCrashReport(new_report, &uuid));
71
72 EXPECT_EQ(CrashReportDatabase::kNoError,
73 db_->LookUpCrashReport(uuid, report));
74 ExpectPreparedCrashReport(*report);
75 ASSERT_TRUE(FileExistsAtPath(report->file_path));
76 }
77
78 void UploadReport(const UUID& uuid, bool successful, const std::string& id) {
79 const CrashReportDatabase::Report* report = nullptr;
80 EXPECT_EQ(CrashReportDatabase::kNoError,
81 db_->GetReportForUploading(uuid, &report));
82 EXPECT_TRUE(report);
83 EXPECT_NE(UUID(), report->uuid);
84 EXPECT_FALSE(report->file_path.empty());
85 EXPECT_TRUE(FileExistsAtPath(report->file_path))
86 << report->file_path.value();
87 EXPECT_GT(report->creation_time, 0);
88 EXPECT_EQ(CrashReportDatabase::kNoError,
89 db_->RecordUploadAttempt(report, successful, id));
90 }
91
92 void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) {
93 EXPECT_NE(UUID(), report.uuid);
94 EXPECT_FALSE(report.file_path.empty());
95 EXPECT_TRUE(FileExistsAtPath(report.file_path)) << report.file_path.value();
96 EXPECT_TRUE(report.id.empty());
97 EXPECT_GT(report.creation_time, 0);
98 EXPECT_FALSE(report.uploaded);
99 EXPECT_EQ(0, report.last_upload_attempt_time);
100 EXPECT_EQ(0, report.upload_attempts);
101 }
102
103 private:
104 ScopedTempDir temp_dir_;
105 scoped_ptr<CrashReportDatabase> db_;
106 };
107
108 TEST_F(CrashReportDatabaseTest, Initialize) {
109 // Initialize the database for the first time, creating it.
110 EXPECT_TRUE(db());
111
112 // Close and reopen the database at the same path.
113 ResetDatabase();
114 EXPECT_FALSE(db());
115 auto db = CrashReportDatabase::Initialize(path());
116 EXPECT_TRUE(db.get());
117
118 std::vector<const CrashReportDatabase::Report> reports;
119 EXPECT_EQ(CrashReportDatabase::kNoError, db->GetPendingReports(&reports));
120 EXPECT_TRUE(reports.empty());
121 EXPECT_EQ(CrashReportDatabase::kNoError, db->GetCompletedReports(&reports));
122 EXPECT_TRUE(reports.empty());
123 }
124
125 TEST_F(CrashReportDatabaseTest, NewCrashReport) {
126 CrashReportDatabase::NewReport* new_report;
127 EXPECT_EQ(CrashReportDatabase::kNoError,
128 db()->PrepareNewCrashReport(&new_report));
129 UUID uuid;
130 EXPECT_EQ(CrashReportDatabase::kNoError,
131 db()->FinishedWritingCrashReport(new_report, &uuid));
132
133 CrashReportDatabase::Report report;
134 EXPECT_EQ(CrashReportDatabase::kNoError,
135 db()->LookUpCrashReport(uuid, &report));
136 ExpectPreparedCrashReport(report);
137
138 std::vector<const CrashReportDatabase::Report> reports;
139 EXPECT_EQ(CrashReportDatabase::kNoError,
140 db()->GetPendingReports(&reports));
141 ASSERT_EQ(1u, reports.size());
142 EXPECT_EQ(report.uuid, reports[0].uuid);
143
144 reports.clear();
145 EXPECT_EQ(CrashReportDatabase::kNoError,
146 db()->GetCompletedReports(&reports));
147 EXPECT_TRUE(reports.empty());
148 }
149
150 TEST_F(CrashReportDatabaseTest, LookUpCrashReport) {
151 UUID uuid;
152
153 {
154 CrashReportDatabase::Report report;
155 CreateCrashReport(&report);
156 uuid = report.uuid;
157 }
158
159 {
160 CrashReportDatabase::Report report;
161 EXPECT_EQ(CrashReportDatabase::kNoError,
162 db()->LookUpCrashReport(uuid, &report));
163 EXPECT_EQ(uuid, report.uuid);
164 EXPECT_NE(std::string::npos, report.file_path.value().find(path().value()));
165 EXPECT_EQ("", report.id);
166 EXPECT_FALSE(report.uploaded);
167 EXPECT_EQ(0, report.last_upload_attempt_time);
168 EXPECT_EQ(0, report.upload_attempts);
169 }
170
171 UploadReport(uuid, true, "test");
172
173 {
174 CrashReportDatabase::Report report;
175 EXPECT_EQ(CrashReportDatabase::kNoError,
176 db()->LookUpCrashReport(uuid, &report));
177 EXPECT_EQ(uuid, report.uuid);
178 EXPECT_NE(std::string::npos, report.file_path.value().find(path().value()));
179 EXPECT_EQ("test", report.id);
180 EXPECT_TRUE(report.uploaded);
181 EXPECT_NE(0, report.last_upload_attempt_time);
182 EXPECT_EQ(1, report.upload_attempts);
183 }
184 }
185
186 TEST_F(CrashReportDatabaseTest, RecordUploadAttempt) {
187 std::vector<CrashReportDatabase::Report> reports(3);
188 CreateCrashReport(&reports[0]);
189 CreateCrashReport(&reports[1]);
190 CreateCrashReport(&reports[2]);
191
192 // Record two attempts: one successful, one not.
193 UploadReport(reports[1].uuid, false, "");
194 UploadReport(reports[2].uuid, true, "abc123");
195
196 std::vector<CrashReportDatabase::Report> query(3);
197
198 EXPECT_EQ(CrashReportDatabase::kNoError,
199 db()->LookUpCrashReport(reports[0].uuid, &query[0]));
200 EXPECT_EQ(CrashReportDatabase::kNoError,
201 db()->LookUpCrashReport(reports[1].uuid, &query[1]));
202 EXPECT_EQ(CrashReportDatabase::kNoError,
203 db()->LookUpCrashReport(reports[2].uuid, &query[2]));
204
205 EXPECT_EQ("", query[0].id);
206 EXPECT_EQ("", query[1].id);
207 EXPECT_EQ("abc123", query[2].id);
208
209 EXPECT_FALSE(query[0].uploaded);
210 EXPECT_FALSE(query[1].uploaded);
211 EXPECT_TRUE(query[2].uploaded);
212
213 EXPECT_EQ(0, query[0].last_upload_attempt_time);
214 EXPECT_NE(0, query[1].last_upload_attempt_time);
215 EXPECT_NE(0, query[2].last_upload_attempt_time);
216
217 EXPECT_EQ(0, query[0].upload_attempts);
218 EXPECT_EQ(1, query[1].upload_attempts);
219 EXPECT_EQ(1, query[2].upload_attempts);
220
221 // Attempt to upload and fail again.
222 UploadReport(reports[1].uuid, false, "");
223
224 time_t report_2_upload_time = query[2].last_upload_attempt_time;
225
226 EXPECT_EQ(CrashReportDatabase::kNoError,
227 db()->LookUpCrashReport(reports[0].uuid, &query[0]));
228 EXPECT_EQ(CrashReportDatabase::kNoError,
229 db()->LookUpCrashReport(reports[1].uuid, &query[1]));
230 EXPECT_EQ(CrashReportDatabase::kNoError,
231 db()->LookUpCrashReport(reports[2].uuid, &query[2]));
232
233 EXPECT_FALSE(query[0].uploaded);
234 EXPECT_FALSE(query[1].uploaded);
235 EXPECT_TRUE(query[2].uploaded);
236
237 EXPECT_EQ(0, query[0].last_upload_attempt_time);
238 EXPECT_GE(query[1].last_upload_attempt_time, report_2_upload_time);
239 EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time);
240
241 EXPECT_EQ(0, query[0].upload_attempts);
242 EXPECT_EQ(2, query[1].upload_attempts);
243 EXPECT_EQ(1, query[2].upload_attempts);
244
245 // Third time's the charm: upload and succeed.
246 UploadReport(reports[1].uuid, true, "666hahaha");
247
248 time_t report_1_upload_time = query[1].last_upload_attempt_time;
249
250 EXPECT_EQ(CrashReportDatabase::kNoError,
251 db()->LookUpCrashReport(reports[0].uuid, &query[0]));
252 EXPECT_EQ(CrashReportDatabase::kNoError,
253 db()->LookUpCrashReport(reports[1].uuid, &query[1]));
254 EXPECT_EQ(CrashReportDatabase::kNoError,
255 db()->LookUpCrashReport(reports[2].uuid, &query[2]));
256
257 EXPECT_FALSE(query[0].uploaded);
258 EXPECT_TRUE(query[1].uploaded);
259 EXPECT_TRUE(query[2].uploaded);
260
261 EXPECT_EQ(0, query[0].last_upload_attempt_time);
262 EXPECT_GE(query[1].last_upload_attempt_time, report_1_upload_time);
263 EXPECT_EQ(report_2_upload_time, query[2].last_upload_attempt_time);
264
265 EXPECT_EQ(0, query[0].upload_attempts);
266 EXPECT_EQ(3, query[1].upload_attempts);
267 EXPECT_EQ(1, query[2].upload_attempts);
268 }
269
270 // This test covers both query functions since they are related.
271 TEST_F(CrashReportDatabaseTest, GetCompletedAndNotUploadedReports) {
272 std::vector<CrashReportDatabase::Report> reports(5);
273 CreateCrashReport(&reports[0]);
274 CreateCrashReport(&reports[1]);
275 CreateCrashReport(&reports[2]);
276 CreateCrashReport(&reports[3]);
277 CreateCrashReport(&reports[4]);
278
279 const UUID& report_0_uuid = reports[0].uuid;
280 const UUID& report_1_uuid = reports[1].uuid;
281 const UUID& report_2_uuid = reports[2].uuid;
282 const UUID& report_3_uuid = reports[3].uuid;
283 const UUID& report_4_uuid = reports[4].uuid;
284
285 std::vector<const CrashReportDatabase::Report> pending;
286 EXPECT_EQ(CrashReportDatabase::kNoError,
287 db()->GetPendingReports(&pending));
288
289 std::vector<const CrashReportDatabase::Report> completed;
290 EXPECT_EQ(CrashReportDatabase::kNoError,
291 db()->GetCompletedReports(&completed));
292
293 EXPECT_EQ(reports.size(), pending.size());
294 EXPECT_EQ(0u, completed.size());
295
296 // Upload one report successfully.
297 UploadReport(report_1_uuid, true, "report1");
298
299 pending.clear();
300 EXPECT_EQ(CrashReportDatabase::kNoError,
301 db()->GetPendingReports(&pending));
302 completed.clear();
303 EXPECT_EQ(CrashReportDatabase::kNoError,
304 db()->GetCompletedReports(&completed));
305
306 EXPECT_EQ(4u, pending.size());
307 ASSERT_EQ(1u, completed.size());
308
309 for (const auto& report : pending)
310 EXPECT_NE(report_1_uuid, report.uuid);
311 EXPECT_EQ(report_1_uuid, completed[0].uuid);
312 EXPECT_EQ("report1", completed[0].id);
313 EXPECT_EQ(true, completed[0].uploaded);
314 EXPECT_GT(completed[0].last_upload_attempt_time, 0);
315 EXPECT_EQ(1, completed[0].upload_attempts);
316
317 const CrashReportDatabase::Report completed_report_1 = completed[0];
318
319 // Fail to upload one report.
320 UploadReport(report_2_uuid, false, "");
321
322 pending.clear();
323 EXPECT_EQ(CrashReportDatabase::kNoError,
324 db()->GetPendingReports(&pending));
325 completed.clear();
326 EXPECT_EQ(CrashReportDatabase::kNoError,
327 db()->GetCompletedReports(&completed));
328
329 EXPECT_EQ(4u, pending.size());
330 ASSERT_EQ(1u, completed.size());
331
332 for (const auto& report : pending) {
333 if (report.upload_attempts != 0) {
334 EXPECT_EQ(report_2_uuid, report.uuid);
335 EXPECT_GT(report.last_upload_attempt_time, 0);
336 EXPECT_FALSE(report.uploaded);
337 EXPECT_TRUE(report.id.empty());
338 }
339 }
340
341 // Upload a second report.
342 UploadReport(report_4_uuid, true, "report_4");
343
344 pending.clear();
345 EXPECT_EQ(CrashReportDatabase::kNoError,
346 db()->GetPendingReports(&pending));
347 completed.clear();
348 EXPECT_EQ(CrashReportDatabase::kNoError,
349 db()->GetCompletedReports(&completed));
350
351 EXPECT_EQ(3u, pending.size());
352 ASSERT_EQ(2u, completed.size());
353
354 // Succeed the failed report.
355 UploadReport(report_2_uuid, true, "report 2");
356
357 pending.clear();
358 EXPECT_EQ(CrashReportDatabase::kNoError,
359 db()->GetPendingReports(&pending));
360 completed.clear();
361 EXPECT_EQ(CrashReportDatabase::kNoError,
362 db()->GetCompletedReports(&completed));
363
364 EXPECT_EQ(2u, pending.size());
365 ASSERT_EQ(3u, completed.size());
366
367 for (const auto& report : pending) {
368 EXPECT_TRUE(report.uuid == report_0_uuid ||
369 report.uuid == report_3_uuid);
370 }
371
372 // Skip upload for one report.
373 EXPECT_EQ(CrashReportDatabase::kNoError,
374 db()->SkipReportUpload(report_3_uuid));
375
376 pending.clear();
377 EXPECT_EQ(CrashReportDatabase::kNoError,
378 db()->GetPendingReports(&pending));
379 completed.clear();
380 EXPECT_EQ(CrashReportDatabase::kNoError,
381 db()->GetCompletedReports(&completed));
382
383 ASSERT_EQ(1u, pending.size());
384 ASSERT_EQ(4u, completed.size());
385
386 EXPECT_EQ(report_0_uuid, pending[0].uuid);
387
388 for (const auto& report : completed) {
389 if (report.uuid == report_3_uuid) {
390 EXPECT_FALSE(report.uploaded);
391 EXPECT_EQ(0, report.upload_attempts);
392 EXPECT_EQ(0, report.last_upload_attempt_time);
393 } else {
394 EXPECT_TRUE(report.uploaded);
395 EXPECT_GT(report.upload_attempts, 0);
396 EXPECT_GT(report.last_upload_attempt_time, 0);
397 }
398 }
399 }
400
401 TEST_F(CrashReportDatabaseTest, DuelingUploads) {
402 CrashReportDatabase::Report report;
403 CreateCrashReport(&report);
404
405 const CrashReportDatabase::Report* upload_report;
406 EXPECT_EQ(CrashReportDatabase::kNoError,
407 db()->GetReportForUploading(report.uuid, &upload_report));
408
409 const CrashReportDatabase::Report* upload_report_2 = nullptr;
410 EXPECT_EQ(CrashReportDatabase::kBusyError,
411 db()->GetReportForUploading(report.uuid, &upload_report_2));
412 EXPECT_FALSE(upload_report_2);
413
414 EXPECT_EQ(CrashReportDatabase::kNoError,
415 db()->RecordUploadAttempt(upload_report, true, ""));
416 }
417
418 } // namespace
419 } // namespace test
420 } // namespace crashpad
OLDNEW
« no previous file with comments | « client/crash_report_database_mac.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698