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 "build/build_config.h"
18 #include "client/settings.h"
19 #include "gtest/gtest.h"
20 #include "test/errors.h"
21 #include "test/file.h"
22 #include "test/filesystem.h"
23 #include "test/scoped_temp_dir.h"
24 #include "util/file/file_io.h"
25 #include "util/file/filesystem.h"
26
27 namespace crashpad {
28 namespace test {
29 namespace {
30
31 class CrashReportDatabaseTest : public testing::Test {
32 public:
CrashReportDatabaseTest()33 CrashReportDatabaseTest() {}
34
35 protected:
36 // testing::Test:
SetUp()37 void SetUp() override {
38 db_ = CrashReportDatabase::Initialize(path());
39 ASSERT_TRUE(db_);
40 }
41
ResetDatabase()42 void ResetDatabase() { db_.reset(); }
43
db()44 CrashReportDatabase* db() { return db_.get(); }
path() const45 base::FilePath path() const {
46 return temp_dir_.path().Append(FILE_PATH_LITERAL("crashpad_test_database"));
47 }
48
CreateCrashReport(CrashReportDatabase::Report * report)49 void CreateCrashReport(CrashReportDatabase::Report* report) {
50 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
51 ASSERT_EQ(db_->PrepareNewCrashReport(&new_report),
52 CrashReportDatabase::kNoError);
53 static constexpr char kTest[] = "test";
54 ASSERT_TRUE(new_report->Writer()->Write(kTest, sizeof(kTest)));
55
56 char contents[sizeof(kTest)];
57 FileReaderInterface* reader = new_report->Reader();
58 ASSERT_TRUE(reader->ReadExactly(contents, sizeof(contents)));
59 EXPECT_EQ(memcmp(contents, kTest, sizeof(contents)), 0);
60 EXPECT_EQ(reader->ReadExactly(contents, 1), 0);
61
62 UUID uuid;
63 EXPECT_EQ(db_->FinishedWritingCrashReport(std::move(new_report), &uuid),
64 CrashReportDatabase::kNoError);
65
66 EXPECT_EQ(db_->LookUpCrashReport(uuid, report),
67 CrashReportDatabase::kNoError);
68 ExpectPreparedCrashReport(*report);
69 }
70
UploadReport(const UUID & uuid,bool successful,const std::string & id)71 void UploadReport(const UUID& uuid, bool successful, const std::string& id) {
72 Settings* const settings = db_->GetSettings();
73 ASSERT_TRUE(settings);
74 time_t times[2];
75 ASSERT_TRUE(settings->GetLastUploadAttemptTime(×[0]));
76
77 std::unique_ptr<const CrashReportDatabase::UploadReport> report;
78 ASSERT_EQ(db_->GetReportForUploading(uuid, &report),
79 CrashReportDatabase::kNoError);
80 EXPECT_NE(report->uuid, UUID());
81 EXPECT_FALSE(report->file_path.empty());
82 EXPECT_TRUE(FileExists(report->file_path)) << report->file_path.value();
83 EXPECT_GT(report->creation_time, 0);
84 if (successful) {
85 EXPECT_EQ(db_->RecordUploadComplete(std::move(report), id),
86 CrashReportDatabase::kNoError);
87 } else {
88 report.reset();
89 }
90
91 ASSERT_TRUE(settings->GetLastUploadAttemptTime(×[1]));
92 EXPECT_NE(times[1], 0);
93 EXPECT_GE(times[1], times[0]);
94 }
95
ExpectPreparedCrashReport(const CrashReportDatabase::Report & report)96 void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) {
97 EXPECT_NE(report.uuid, UUID());
98 EXPECT_FALSE(report.file_path.empty());
99 EXPECT_TRUE(FileExists(report.file_path)) << report.file_path.value();
100 EXPECT_TRUE(report.id.empty());
101 EXPECT_GT(report.creation_time, 0);
102 EXPECT_FALSE(report.uploaded);
103 EXPECT_EQ(report.last_upload_attempt_time, 0);
104 EXPECT_EQ(report.upload_attempts, 0);
105 EXPECT_FALSE(report.upload_explicitly_requested);
106 EXPECT_GE(report.total_size, 0u);
107 }
108
RelocateDatabase()109 void RelocateDatabase() {
110 ResetDatabase();
111 temp_dir_.Rename();
112 SetUp();
113 }
114
RequestUpload(const UUID & uuid)115 CrashReportDatabase::OperationStatus RequestUpload(const UUID& uuid) {
116 CrashReportDatabase::OperationStatus os = db()->RequestUpload(uuid);
117
118 CrashReportDatabase::Report report;
119 EXPECT_EQ(db_->LookUpCrashReport(uuid, &report),
120 CrashReportDatabase::kNoError);
121
122 return os;
123 }
124
125 private:
126 ScopedTempDir temp_dir_;
127 std::unique_ptr<CrashReportDatabase> db_;
128
129 DISALLOW_COPY_AND_ASSIGN(CrashReportDatabaseTest);
130 };
131
TEST_F(CrashReportDatabaseTest,Initialize)132 TEST_F(CrashReportDatabaseTest, Initialize) {
133 // Initialize the database for the first time, creating it.
134 ASSERT_TRUE(db());
135
136 Settings* settings = db()->GetSettings();
137
138 UUID client_ids[3];
139 ASSERT_TRUE(settings->GetClientID(&client_ids[0]));
140 EXPECT_NE(client_ids[0], UUID());
141
142 time_t last_upload_attempt_time;
143 ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
144 EXPECT_EQ(last_upload_attempt_time, 0);
145
146 // Close and reopen the database at the same path.
147 ResetDatabase();
148 EXPECT_FALSE(db());
149 auto db = CrashReportDatabase::InitializeWithoutCreating(path());
150 ASSERT_TRUE(db);
151
152 settings = db->GetSettings();
153
154 ASSERT_TRUE(settings->GetClientID(&client_ids[1]));
155 EXPECT_EQ(client_ids[1], client_ids[0]);
156
157 ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
158 EXPECT_EQ(last_upload_attempt_time, 0);
159
160 // Check that the database can also be opened by the method that is permitted
161 // to create it.
162 db = CrashReportDatabase::Initialize(path());
163 ASSERT_TRUE(db);
164
165 settings = db->GetSettings();
166
167 ASSERT_TRUE(settings->GetClientID(&client_ids[2]));
168 EXPECT_EQ(client_ids[2], client_ids[0]);
169
170 ASSERT_TRUE(settings->GetLastUploadAttemptTime(&last_upload_attempt_time));
171 EXPECT_EQ(last_upload_attempt_time, 0);
172
173 std::vector<CrashReportDatabase::Report> reports;
174 EXPECT_EQ(db->GetPendingReports(&reports), CrashReportDatabase::kNoError);
175 EXPECT_TRUE(reports.empty());
176 reports.clear();
177 EXPECT_EQ(db->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
178 EXPECT_TRUE(reports.empty());
179
180 // InitializeWithoutCreating() shouldn’t create a nonexistent database.
181 base::FilePath non_database_path =
182 path().DirName().Append(FILE_PATH_LITERAL("not_a_database"));
183 db = CrashReportDatabase::InitializeWithoutCreating(non_database_path);
184 EXPECT_FALSE(db);
185 }
186
TEST_F(CrashReportDatabaseTest,NewCrashReport)187 TEST_F(CrashReportDatabaseTest, NewCrashReport) {
188 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
189 EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
190 CrashReportDatabase::kNoError);
191 UUID expect_uuid = new_report->ReportID();
192 UUID uuid;
193 EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
194 CrashReportDatabase::kNoError);
195 EXPECT_EQ(uuid, expect_uuid);
196
197 CrashReportDatabase::Report report;
198 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
199 CrashReportDatabase::kNoError);
200 ExpectPreparedCrashReport(report);
201
202 std::vector<CrashReportDatabase::Report> reports;
203 EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
204 ASSERT_EQ(reports.size(), 1u);
205 EXPECT_EQ(reports[0].uuid, report.uuid);
206
207 reports.clear();
208 EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError);
209 EXPECT_TRUE(reports.empty());
210 }
211
TEST_F(CrashReportDatabaseTest,LookUpCrashReport)212 TEST_F(CrashReportDatabaseTest, LookUpCrashReport) {
213 UUID uuid;
214
215 {
216 CrashReportDatabase::Report report;
217 CreateCrashReport(&report);
218 uuid = report.uuid;
219 }
220
221 {
222 CrashReportDatabase::Report report;
223 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
224 CrashReportDatabase::kNoError);
225 EXPECT_EQ(report.uuid, uuid);
226 EXPECT_NE(report.file_path.value().find(path().value()), std::string::npos);
227 EXPECT_EQ(report.id, std::string());
228 EXPECT_FALSE(report.uploaded);
229 EXPECT_EQ(report.last_upload_attempt_time, 0);
230 EXPECT_EQ(report.upload_attempts, 0);
231 EXPECT_FALSE(report.upload_explicitly_requested);
232 }
233
234 UploadReport(uuid, true, "test");
235
236 {
237 CrashReportDatabase::Report report;
238 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
239 CrashReportDatabase::kNoError);
240 EXPECT_EQ(report.uuid, uuid);
241 EXPECT_NE(report.file_path.value().find(path().value()), std::string::npos);
242 EXPECT_EQ(report.id, "test");
243 EXPECT_TRUE(report.uploaded);
244 EXPECT_NE(report.last_upload_attempt_time, 0);
245 EXPECT_EQ(report.upload_attempts, 1);
246 EXPECT_FALSE(report.upload_explicitly_requested);
247 }
248 }
249
TEST_F(CrashReportDatabaseTest,RecordUploadAttempt)250 TEST_F(CrashReportDatabaseTest, RecordUploadAttempt) {
251 std::vector<CrashReportDatabase::Report> reports(3);
252 CreateCrashReport(&reports[0]);
253 CreateCrashReport(&reports[1]);
254 CreateCrashReport(&reports[2]);
255
256 // Record two attempts: one successful, one not.
257 UploadReport(reports[1].uuid, false, std::string());
258 UploadReport(reports[2].uuid, true, "abc123");
259
260 std::vector<CrashReportDatabase::Report> query(3);
261 EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
262 CrashReportDatabase::kNoError);
263 EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
264 CrashReportDatabase::kNoError);
265 EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
266 CrashReportDatabase::kNoError);
267
268 EXPECT_EQ(query[0].id, std::string());
269 EXPECT_EQ(query[1].id, std::string());
270 EXPECT_EQ(query[2].id, "abc123");
271
272 EXPECT_FALSE(query[0].uploaded);
273 EXPECT_FALSE(query[1].uploaded);
274 EXPECT_TRUE(query[2].uploaded);
275
276 EXPECT_EQ(query[0].last_upload_attempt_time, 0);
277 EXPECT_NE(query[1].last_upload_attempt_time, 0);
278 EXPECT_NE(query[2].last_upload_attempt_time, 0);
279
280 EXPECT_EQ(query[0].upload_attempts, 0);
281 EXPECT_EQ(query[1].upload_attempts, 1);
282 EXPECT_EQ(query[2].upload_attempts, 1);
283
284 // Attempt to upload and fail again.
285 UploadReport(reports[1].uuid, false, std::string());
286
287 time_t report_2_upload_time = query[2].last_upload_attempt_time;
288
289 EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
290 CrashReportDatabase::kNoError);
291 EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
292 CrashReportDatabase::kNoError);
293 EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
294 CrashReportDatabase::kNoError);
295
296 EXPECT_FALSE(query[0].uploaded);
297 EXPECT_FALSE(query[1].uploaded);
298 EXPECT_TRUE(query[2].uploaded);
299
300 EXPECT_EQ(query[0].last_upload_attempt_time, 0);
301 EXPECT_GE(query[1].last_upload_attempt_time, report_2_upload_time);
302 EXPECT_EQ(query[2].last_upload_attempt_time, report_2_upload_time);
303
304 EXPECT_EQ(query[0].upload_attempts, 0);
305 EXPECT_EQ(query[1].upload_attempts, 2);
306 EXPECT_EQ(query[2].upload_attempts, 1);
307
308 // Third time's the charm: upload and succeed.
309 UploadReport(reports[1].uuid, true, "666hahaha");
310
311 time_t report_1_upload_time = query[1].last_upload_attempt_time;
312
313 EXPECT_EQ(db()->LookUpCrashReport(reports[0].uuid, &query[0]),
314 CrashReportDatabase::kNoError);
315 EXPECT_EQ(db()->LookUpCrashReport(reports[1].uuid, &query[1]),
316 CrashReportDatabase::kNoError);
317 EXPECT_EQ(db()->LookUpCrashReport(reports[2].uuid, &query[2]),
318 CrashReportDatabase::kNoError);
319
320 EXPECT_FALSE(query[0].uploaded);
321 EXPECT_TRUE(query[1].uploaded);
322 EXPECT_TRUE(query[2].uploaded);
323
324 EXPECT_EQ(query[0].last_upload_attempt_time, 0);
325 EXPECT_GE(query[1].last_upload_attempt_time, report_1_upload_time);
326 EXPECT_EQ(query[2].last_upload_attempt_time, report_2_upload_time);
327
328 EXPECT_EQ(query[0].upload_attempts, 0);
329 EXPECT_EQ(query[1].upload_attempts, 3);
330 EXPECT_EQ(query[2].upload_attempts, 1);
331 }
332
333 // This test covers both query functions since they are related.
TEST_F(CrashReportDatabaseTest,GetCompletedAndNotUploadedReports)334 TEST_F(CrashReportDatabaseTest, GetCompletedAndNotUploadedReports) {
335 std::vector<CrashReportDatabase::Report> reports(5);
336 CreateCrashReport(&reports[0]);
337 CreateCrashReport(&reports[1]);
338 CreateCrashReport(&reports[2]);
339 CreateCrashReport(&reports[3]);
340 CreateCrashReport(&reports[4]);
341
342 const UUID& report_0_uuid = reports[0].uuid;
343 const UUID& report_1_uuid = reports[1].uuid;
344 const UUID& report_2_uuid = reports[2].uuid;
345 const UUID& report_3_uuid = reports[3].uuid;
346 const UUID& report_4_uuid = reports[4].uuid;
347
348 std::vector<CrashReportDatabase::Report> pending;
349 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
350
351 std::vector<CrashReportDatabase::Report> completed;
352 EXPECT_EQ(db()->GetCompletedReports(&completed),
353 CrashReportDatabase::kNoError);
354
355 EXPECT_EQ(pending.size(), reports.size());
356 EXPECT_EQ(completed.size(), 0u);
357
358 // Upload one report successfully.
359 UploadReport(report_1_uuid, true, "report1");
360
361 pending.clear();
362 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
363 completed.clear();
364 EXPECT_EQ(db()->GetCompletedReports(&completed),
365 CrashReportDatabase::kNoError);
366
367 EXPECT_EQ(pending.size(), 4u);
368 ASSERT_EQ(completed.size(), 1u);
369
370 for (const auto& report : pending) {
371 EXPECT_NE(report.uuid, report_1_uuid);
372 EXPECT_FALSE(report.file_path.empty());
373 }
374 EXPECT_EQ(completed[0].uuid, report_1_uuid);
375 EXPECT_EQ(completed[0].id, "report1");
376 EXPECT_EQ(completed[0].uploaded, true);
377 EXPECT_GT(completed[0].last_upload_attempt_time, 0);
378 EXPECT_EQ(completed[0].upload_attempts, 1);
379
380 // Fail to upload one report.
381 UploadReport(report_2_uuid, false, std::string());
382
383 pending.clear();
384 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
385 completed.clear();
386 EXPECT_EQ(db()->GetCompletedReports(&completed),
387 CrashReportDatabase::kNoError);
388
389 EXPECT_EQ(pending.size(), 4u);
390 ASSERT_EQ(completed.size(), 1u);
391
392 for (const auto& report : pending) {
393 if (report.upload_attempts != 0) {
394 EXPECT_EQ(report.uuid, report_2_uuid);
395 EXPECT_GT(report.last_upload_attempt_time, 0);
396 EXPECT_FALSE(report.uploaded);
397 EXPECT_TRUE(report.id.empty());
398 }
399 EXPECT_FALSE(report.file_path.empty());
400 }
401
402 // Upload a second report.
403 UploadReport(report_4_uuid, true, "report_4");
404
405 pending.clear();
406 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
407 completed.clear();
408 EXPECT_EQ(db()->GetCompletedReports(&completed),
409 CrashReportDatabase::kNoError);
410
411 EXPECT_EQ(pending.size(), 3u);
412 ASSERT_EQ(completed.size(), 2u);
413
414 // Succeed the failed report.
415 UploadReport(report_2_uuid, true, "report 2");
416
417 pending.clear();
418 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
419 completed.clear();
420 EXPECT_EQ(db()->GetCompletedReports(&completed),
421 CrashReportDatabase::kNoError);
422
423 EXPECT_EQ(pending.size(), 2u);
424 ASSERT_EQ(completed.size(), 3u);
425
426 for (const auto& report : pending) {
427 EXPECT_TRUE(report.uuid == report_0_uuid || report.uuid == report_3_uuid);
428 EXPECT_FALSE(report.file_path.empty());
429 }
430
431 // Skip upload for one report.
432 EXPECT_EQ(db()->SkipReportUpload(
433 report_3_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
434 CrashReportDatabase::kNoError);
435
436 pending.clear();
437 EXPECT_EQ(db()->GetPendingReports(&pending), CrashReportDatabase::kNoError);
438 completed.clear();
439 EXPECT_EQ(db()->GetCompletedReports(&completed),
440 CrashReportDatabase::kNoError);
441
442 ASSERT_EQ(pending.size(), 1u);
443 ASSERT_EQ(completed.size(), 4u);
444
445 EXPECT_EQ(pending[0].uuid, report_0_uuid);
446
447 for (const auto& report : completed) {
448 if (report.uuid == report_3_uuid) {
449 EXPECT_FALSE(report.uploaded);
450 EXPECT_EQ(report.upload_attempts, 0);
451 EXPECT_EQ(report.last_upload_attempt_time, 0);
452 } else {
453 EXPECT_TRUE(report.uploaded);
454 EXPECT_GT(report.upload_attempts, 0);
455 EXPECT_GT(report.last_upload_attempt_time, 0);
456 }
457 EXPECT_FALSE(report.file_path.empty());
458 }
459 }
460
TEST_F(CrashReportDatabaseTest,DuelingUploads)461 TEST_F(CrashReportDatabaseTest, DuelingUploads) {
462 CrashReportDatabase::Report report;
463 CreateCrashReport(&report);
464
465 std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
466 EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report),
467 CrashReportDatabase::kNoError);
468
469 std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report_2;
470 EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2),
471 CrashReportDatabase::kBusyError);
472 EXPECT_FALSE(upload_report_2);
473
474 EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()),
475 CrashReportDatabase::kNoError);
476 }
477
TEST_F(CrashReportDatabaseTest,UploadAlreadyUploaded)478 TEST_F(CrashReportDatabaseTest, UploadAlreadyUploaded) {
479 CrashReportDatabase::Report report;
480 CreateCrashReport(&report);
481
482 std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
483 EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report),
484 CrashReportDatabase::kNoError);
485 EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()),
486 CrashReportDatabase::kNoError);
487
488 std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report_2;
489 EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2),
490 CrashReportDatabase::kReportNotFound);
491 EXPECT_FALSE(upload_report_2.get());
492 }
493
TEST_F(CrashReportDatabaseTest,MoveDatabase)494 TEST_F(CrashReportDatabaseTest, MoveDatabase) {
495 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
496 EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
497 CrashReportDatabase::kNoError);
498 UUID uuid;
499 EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
500 CrashReportDatabase::kNoError);
501
502 RelocateDatabase();
503
504 CrashReportDatabase::Report report;
505 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
506 CrashReportDatabase::kNoError);
507 ExpectPreparedCrashReport(report);
508 }
509
TEST_F(CrashReportDatabaseTest,ReportRemoved)510 TEST_F(CrashReportDatabaseTest, ReportRemoved) {
511 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
512 EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
513 CrashReportDatabase::kNoError);
514
515 UUID uuid;
516 EXPECT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
517 CrashReportDatabase::kNoError);
518
519 CrashReportDatabase::Report report;
520 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
521 CrashReportDatabase::kNoError);
522
523 EXPECT_TRUE(LoggingRemoveFile(report.file_path));
524
525 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
526 CrashReportDatabase::kReportNotFound);
527 }
528
TEST_F(CrashReportDatabaseTest,DeleteReport)529 TEST_F(CrashReportDatabaseTest, DeleteReport) {
530 CrashReportDatabase::Report keep_pending;
531 CrashReportDatabase::Report delete_pending;
532 CrashReportDatabase::Report keep_completed;
533 CrashReportDatabase::Report delete_completed;
534
535 CreateCrashReport(&keep_pending);
536 CreateCrashReport(&delete_pending);
537 CreateCrashReport(&keep_completed);
538 CreateCrashReport(&delete_completed);
539
540 EXPECT_TRUE(FileExists(keep_pending.file_path));
541 EXPECT_TRUE(FileExists(delete_pending.file_path));
542 EXPECT_TRUE(FileExists(keep_completed.file_path));
543 EXPECT_TRUE(FileExists(delete_completed.file_path));
544
545 UploadReport(keep_completed.uuid, true, "1");
546 UploadReport(delete_completed.uuid, true, "2");
547
548 EXPECT_EQ(db()->LookUpCrashReport(keep_completed.uuid, &keep_completed),
549 CrashReportDatabase::kNoError);
550 EXPECT_EQ(db()->LookUpCrashReport(delete_completed.uuid, &delete_completed),
551 CrashReportDatabase::kNoError);
552
553 EXPECT_TRUE(FileExists(keep_completed.file_path));
554 EXPECT_TRUE(FileExists(delete_completed.file_path));
555
556 EXPECT_EQ(db()->DeleteReport(delete_pending.uuid),
557 CrashReportDatabase::kNoError);
558 EXPECT_FALSE(FileExists(delete_pending.file_path));
559 EXPECT_EQ(db()->LookUpCrashReport(delete_pending.uuid, &delete_pending),
560 CrashReportDatabase::kReportNotFound);
561 EXPECT_EQ(db()->DeleteReport(delete_pending.uuid),
562 CrashReportDatabase::kReportNotFound);
563
564 EXPECT_EQ(db()->DeleteReport(delete_completed.uuid),
565 CrashReportDatabase::kNoError);
566 EXPECT_FALSE(FileExists(delete_completed.file_path));
567 EXPECT_EQ(db()->LookUpCrashReport(delete_completed.uuid, &delete_completed),
568 CrashReportDatabase::kReportNotFound);
569 EXPECT_EQ(db()->DeleteReport(delete_completed.uuid),
570 CrashReportDatabase::kReportNotFound);
571
572 EXPECT_EQ(db()->LookUpCrashReport(keep_pending.uuid, &keep_pending),
573 CrashReportDatabase::kNoError);
574 EXPECT_EQ(db()->LookUpCrashReport(keep_completed.uuid, &keep_completed),
575 CrashReportDatabase::kNoError);
576 }
577
TEST_F(CrashReportDatabaseTest,DeleteReportEmptyingDatabase)578 TEST_F(CrashReportDatabaseTest, DeleteReportEmptyingDatabase) {
579 CrashReportDatabase::Report report;
580 CreateCrashReport(&report);
581
582 EXPECT_TRUE(FileExists(report.file_path));
583
584 UploadReport(report.uuid, true, "1");
585
586 EXPECT_EQ(db()->LookUpCrashReport(report.uuid, &report),
587 CrashReportDatabase::kNoError);
588
589 EXPECT_TRUE(FileExists(report.file_path));
590
591 // This causes an empty database to be written, make sure this is handled.
592 EXPECT_EQ(db()->DeleteReport(report.uuid), CrashReportDatabase::kNoError);
593 EXPECT_FALSE(FileExists(report.file_path));
594 }
595
TEST_F(CrashReportDatabaseTest,ReadEmptyDatabase)596 TEST_F(CrashReportDatabaseTest, ReadEmptyDatabase) {
597 CrashReportDatabase::Report report;
598 CreateCrashReport(&report);
599 EXPECT_EQ(db()->DeleteReport(report.uuid), CrashReportDatabase::kNoError);
600
601 // Deleting and the creating another report causes an empty database to be
602 // loaded. Make sure this is handled.
603
604 CrashReportDatabase::Report report2;
605 CreateCrashReport(&report2);
606 }
607
TEST_F(CrashReportDatabaseTest,RequestUpload)608 TEST_F(CrashReportDatabaseTest, RequestUpload) {
609 std::vector<CrashReportDatabase::Report> reports(2);
610 CreateCrashReport(&reports[0]);
611 CreateCrashReport(&reports[1]);
612
613 const UUID& report_0_uuid = reports[0].uuid;
614 const UUID& report_1_uuid = reports[1].uuid;
615
616 // Skipped report gets back to pending state after RequestUpload is called.
617 EXPECT_EQ(db()->SkipReportUpload(
618 report_1_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
619 CrashReportDatabase::kNoError);
620
621 std::vector<CrashReportDatabase::Report> pending_reports;
622 CrashReportDatabase::OperationStatus os =
623 db()->GetPendingReports(&pending_reports);
624 EXPECT_EQ(os, CrashReportDatabase::kNoError);
625 ASSERT_EQ(pending_reports.size(), 1u);
626 EXPECT_EQ(report_0_uuid, pending_reports[0].uuid);
627
628 pending_reports.clear();
629 EXPECT_EQ(RequestUpload(report_1_uuid), CrashReportDatabase::kNoError);
630 os = db()->GetPendingReports(&pending_reports);
631 EXPECT_EQ(os, CrashReportDatabase::kNoError);
632 ASSERT_EQ(pending_reports.size(), 2u);
633
634 // Check individual reports.
635 const CrashReportDatabase::Report* explicitly_requested_report;
636 const CrashReportDatabase::Report* pending_report;
637 if (pending_reports[0].uuid == report_0_uuid) {
638 pending_report = &pending_reports[0];
639 explicitly_requested_report = &pending_reports[1];
640 } else {
641 pending_report = &pending_reports[1];
642 explicitly_requested_report = &pending_reports[0];
643 }
644
645 EXPECT_EQ(pending_report->uuid, report_0_uuid);
646 EXPECT_FALSE(pending_report->upload_explicitly_requested);
647
648 EXPECT_EQ(explicitly_requested_report->uuid, report_1_uuid);
649 EXPECT_TRUE(explicitly_requested_report->upload_explicitly_requested);
650
651 // Explicitly requested reports will not have upload_explicitly_requested bit
652 // after getting skipped.
653 EXPECT_EQ(db()->SkipReportUpload(
654 report_1_uuid, Metrics::CrashSkippedReason::kUploadsDisabled),
655 CrashReportDatabase::kNoError);
656 CrashReportDatabase::Report report;
657 EXPECT_EQ(db()->LookUpCrashReport(report_1_uuid, &report),
658 CrashReportDatabase::kNoError);
659 EXPECT_FALSE(report.upload_explicitly_requested);
660
661 // Pending report gets correctly affected after RequestUpload is called.
662 pending_reports.clear();
663 EXPECT_EQ(RequestUpload(report_0_uuid), CrashReportDatabase::kNoError);
664 os = db()->GetPendingReports(&pending_reports);
665 EXPECT_EQ(os, CrashReportDatabase::kNoError);
666 EXPECT_EQ(pending_reports.size(), 1u);
667 EXPECT_EQ(report_0_uuid, pending_reports[0].uuid);
668 EXPECT_TRUE(pending_reports[0].upload_explicitly_requested);
669
670 // Already uploaded report cannot be requested for the new upload.
671 UploadReport(report_0_uuid, true, "1");
672 EXPECT_EQ(RequestUpload(report_0_uuid),
673 CrashReportDatabase::kCannotRequestUpload);
674 }
675
TEST_F(CrashReportDatabaseTest,Attachments)676 TEST_F(CrashReportDatabaseTest, Attachments) {
677 #if defined(OS_APPLE) || defined(OS_WIN)
678 // Attachments aren't supported on Mac and Windows yet.
679 GTEST_SKIP();
680 #else
681 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
682 ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
683 CrashReportDatabase::kNoError);
684
685 FileWriter* attach_some_file = new_report->AddAttachment("some_file");
686 ASSERT_NE(attach_some_file, nullptr);
687 static constexpr char test_data[] = "test data";
688 attach_some_file->Write(test_data, sizeof(test_data));
689
690 FileWriter* failed_attach = new_report->AddAttachment("not/a valid fi!e");
691 EXPECT_EQ(failed_attach, nullptr);
692
693 UUID expect_uuid = new_report->ReportID();
694 UUID uuid;
695 ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
696 CrashReportDatabase::kNoError);
697 EXPECT_EQ(uuid, expect_uuid);
698
699 CrashReportDatabase::Report report;
700 EXPECT_EQ(db()->LookUpCrashReport(uuid, &report),
701 CrashReportDatabase::kNoError);
702 ExpectPreparedCrashReport(report);
703
704 std::vector<CrashReportDatabase::Report> reports;
705 EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError);
706 ASSERT_EQ(reports.size(), 1u);
707 EXPECT_EQ(reports[0].uuid, report.uuid);
708
709 std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
710 ASSERT_EQ(db()->GetReportForUploading(reports[0].uuid, &upload_report),
711 CrashReportDatabase::kNoError);
712 std::map<std::string, FileReader*> result_attachments =
713 upload_report->GetAttachments();
714 EXPECT_EQ(result_attachments.size(), 1u);
715 EXPECT_NE(result_attachments.find("some_file"), result_attachments.end());
716 char result_buffer[sizeof(test_data)];
717 result_attachments["some_file"]->Read(result_buffer, sizeof(result_buffer));
718 EXPECT_EQ(memcmp(test_data, result_buffer, sizeof(test_data)), 0);
719 #endif
720 }
721
TEST_F(CrashReportDatabaseTest,OrphanedAttachments)722 TEST_F(CrashReportDatabaseTest, OrphanedAttachments) {
723 #if defined(OS_APPLE) || defined(OS_WIN)
724 // Attachments aren't supported on Mac and Windows yet.
725 GTEST_SKIP();
726 #else
727 // TODO: This is using paths that are specific to the generic implementation
728 // and will need to be generalized for Mac and Windows.
729 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
730 ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
731 CrashReportDatabase::kNoError);
732
733 FileWriter* file1 = new_report->AddAttachment("file1");
734 ASSERT_NE(file1, nullptr);
735 FileWriter* file2 = new_report->AddAttachment("file2");
736 ASSERT_NE(file2, nullptr);
737
738 UUID expect_uuid = new_report->ReportID();
739 UUID uuid;
740 ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
741 CrashReportDatabase::kNoError);
742 EXPECT_EQ(uuid, expect_uuid);
743
744 CrashReportDatabase::Report report;
745 ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
746 CrashReportDatabase::kNoError);
747
748 ASSERT_TRUE(LoggingRemoveFile(report.file_path));
749
750 ASSERT_TRUE(LoggingRemoveFile(base::FilePath(
751 report.file_path.RemoveFinalExtension().value() + ".meta")));
752
753 ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
754 CrashReportDatabase::kReportNotFound);
755
756 base::FilePath report_attachments_dir(
757 path().Append("attachments").Append(uuid.ToString()));
758 base::FilePath file_path1(report_attachments_dir.Append("file1"));
759 base::FilePath file_path2(report_attachments_dir.Append("file2"));
760 EXPECT_TRUE(FileExists(file_path1));
761 EXPECT_TRUE(FileExists(file_path1));
762
763 EXPECT_EQ(db()->CleanDatabase(0), 0);
764
765 EXPECT_FALSE(FileExists(file_path1));
766 EXPECT_FALSE(FileExists(file_path2));
767 EXPECT_FALSE(FileExists(report_attachments_dir));
768 #endif
769 }
770
771 // This test uses knowledge of the database format to break it, so it only
772 // applies to the unfified database implementation.
773 #if !defined(OS_APPLE) && !defined(OS_WIN)
TEST_F(CrashReportDatabaseTest,CleanBrokenDatabase)774 TEST_F(CrashReportDatabaseTest, CleanBrokenDatabase) {
775 // Remove report files if metadata goes missing.
776 CrashReportDatabase::Report report;
777 ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
778
779 const base::FilePath metadata(
780 report.file_path.RemoveFinalExtension().value() +
781 FILE_PATH_LITERAL(".meta"));
782 ASSERT_TRUE(PathExists(report.file_path));
783 ASSERT_TRUE(PathExists(metadata));
784
785 ASSERT_TRUE(LoggingRemoveFile(metadata));
786 EXPECT_EQ(db()->CleanDatabase(0), 1);
787
788 EXPECT_FALSE(PathExists(report.file_path));
789 EXPECT_FALSE(PathExists(metadata));
790
791 // Remove metadata files if reports go missing.
792 ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
793 const base::FilePath metadata2(
794 report.file_path.RemoveFinalExtension().value() +
795 FILE_PATH_LITERAL(".meta"));
796 ASSERT_TRUE(PathExists(report.file_path));
797 ASSERT_TRUE(PathExists(metadata2));
798
799 ASSERT_TRUE(LoggingRemoveFile(report.file_path));
800 EXPECT_EQ(db()->CleanDatabase(0), 1);
801
802 EXPECT_FALSE(PathExists(report.file_path));
803 EXPECT_FALSE(PathExists(metadata2));
804
805 // Remove stale new files.
806 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
807 EXPECT_EQ(db()->PrepareNewCrashReport(&new_report),
808 CrashReportDatabase::kNoError);
809 new_report->Writer()->Close();
810 EXPECT_EQ(db()->CleanDatabase(0), 1);
811
812 // Remove stale lock files and their associated reports.
813 ASSERT_NO_FATAL_FAILURE(CreateCrashReport(&report));
814 const base::FilePath metadata3(
815 report.file_path.RemoveFinalExtension().value() +
816 FILE_PATH_LITERAL(".meta"));
817 ASSERT_TRUE(PathExists(report.file_path));
818 ASSERT_TRUE(PathExists(metadata3));
819
820 const base::FilePath lockpath(
821 report.file_path.RemoveFinalExtension().value() +
822 FILE_PATH_LITERAL(".lock"));
823 ScopedFileHandle handle(LoggingOpenFileForWrite(
824 lockpath, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly));
825 ASSERT_TRUE(handle.is_valid());
826
827 time_t expired_timestamp = time(nullptr) - 60 * 60 * 24 * 3;
828
829 ASSERT_TRUE(LoggingWriteFile(
830 handle.get(), &expired_timestamp, sizeof(expired_timestamp)));
831 ASSERT_TRUE(LoggingCloseFile(handle.get()));
832 ignore_result(handle.release());
833
834 EXPECT_EQ(db()->CleanDatabase(0), 1);
835
836 EXPECT_FALSE(PathExists(report.file_path));
837 EXPECT_FALSE(PathExists(metadata3));
838 }
839 #endif // !OS_APPLE && !OS_WIN
840
TEST_F(CrashReportDatabaseTest,TotalSize_MainReportOnly)841 TEST_F(CrashReportDatabaseTest, TotalSize_MainReportOnly) {
842 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
843 ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
844 CrashReportDatabase::kNoError);
845
846 // Main report.
847 static constexpr char main_report_data[] = "dlbvandslhb";
848 ASSERT_TRUE(
849 new_report->Writer()->Write(main_report_data, sizeof(main_report_data)));
850
851 UUID uuid;
852 ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
853 CrashReportDatabase::kNoError);
854
855 CrashReportDatabase::Report report;
856 ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
857 CrashReportDatabase::kNoError);
858
859 EXPECT_EQ(report.total_size, sizeof(main_report_data));
860 }
861
TEST_F(CrashReportDatabaseTest,GetReportSize_RightSizeWithAttachments)862 TEST_F(CrashReportDatabaseTest, GetReportSize_RightSizeWithAttachments) {
863 #if defined(OS_APPLE) || defined(OS_WIN)
864 // Attachments aren't supported on Mac and Windows yet.
865 return;
866 #else
867 std::unique_ptr<CrashReportDatabase::NewReport> new_report;
868 ASSERT_EQ(db()->PrepareNewCrashReport(&new_report),
869 CrashReportDatabase::kNoError);
870
871 // Main report.
872 static constexpr char main_report_data[] = "dlbvandslhb";
873 ASSERT_TRUE(
874 new_report->Writer()->Write(main_report_data, sizeof(main_report_data)));
875
876 // First attachment.
877 FileWriter* attachment_1 = new_report->AddAttachment("my_attachment_1");
878 ASSERT_NE(attachment_1, nullptr);
879 static constexpr char attachment_1_data[] = "vKDnidhvbiudshoihbvdsoiuh nhh";
880 attachment_1->Write(attachment_1_data, sizeof(attachment_1_data));
881
882 // Second attachment.
883 FileWriter* attachment_2 = new_report->AddAttachment("my_attachment_2");
884 ASSERT_NE(attachment_2, nullptr);
885 static constexpr char attachment_2_data[] = "sgvsvgusiyguysigfkhpmo-[";
886 attachment_2->Write(attachment_2_data, sizeof(attachment_2_data));
887
888 UUID uuid;
889 ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid),
890 CrashReportDatabase::kNoError);
891
892 CrashReportDatabase::Report report;
893 ASSERT_EQ(db()->LookUpCrashReport(uuid, &report),
894 CrashReportDatabase::kNoError);
895 EXPECT_EQ(report.total_size,
896 sizeof(main_report_data) + sizeof(attachment_1_data) +
897 sizeof(attachment_2_data));
898 #endif
899 }
900
901 } // namespace
902 } // namespace test
903 } // namespace crashpad
904