OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <fcntl.h> | 5 #include <fcntl.h> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 #include <sys/file.h> | 7 #include <sys/file.h> |
8 #include <sys/stat.h> // mkdir | 8 #include <sys/stat.h> // mkdir |
9 #include <sys/types.h> // | 9 #include <sys/types.h> // |
10 #include <stdio.h> // perror | 10 #include <stdio.h> // perror |
(...skipping 17 matching lines...) Expand all Loading... |
28 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
29 | 29 |
30 namespace chromecast { | 30 namespace chromecast { |
31 namespace { | 31 namespace { |
32 | 32 |
33 const char kLockfileName[] = "lockfile"; | 33 const char kLockfileName[] = "lockfile"; |
34 const char kMetadataName[] = "metadata"; | 34 const char kMetadataName[] = "metadata"; |
35 const char kMinidumpSubdir[] = "minidumps"; | 35 const char kMinidumpSubdir[] = "minidumps"; |
36 | 36 |
37 // A trivial implementation of SynchronizedMinidumpManager, which does no work | 37 // A trivial implementation of SynchronizedMinidumpManager, which does no work |
38 // to the | 38 // to the minidump and exposes its protected members for testing. This simply |
39 // minidump and exposes its protected members for testing. | 39 // adds an entry to the lockfile. |
40 class SynchronizedMinidumpManagerSimple : public SynchronizedMinidumpManager { | 40 class SynchronizedMinidumpManagerSimple : public SynchronizedMinidumpManager { |
41 public: | 41 public: |
42 SynchronizedMinidumpManagerSimple() | 42 SynchronizedMinidumpManagerSimple() |
43 : SynchronizedMinidumpManager(), | 43 : SynchronizedMinidumpManager(), |
44 work_done_(false), | 44 work_done_(false), |
45 add_entry_return_code_(-1), | 45 add_entry_return_code_(-1), |
46 lockfile_path_(dump_path_.Append(kLockfileName).value()) {} | 46 lockfile_path_(dump_path_.Append(kLockfileName).value()) {} |
47 ~SynchronizedMinidumpManagerSimple() override {} | 47 ~SynchronizedMinidumpManagerSimple() override {} |
48 | 48 |
49 void SetDumpInfoToWrite(scoped_ptr<DumpInfo> dump_info) { | 49 void SetDumpInfoToWrite(scoped_ptr<DumpInfo> dump_info) { |
(...skipping 20 matching lines...) Expand all Loading... |
70 bool work_done_; | 70 bool work_done_; |
71 int add_entry_return_code_; | 71 int add_entry_return_code_; |
72 std::string lockfile_path_; | 72 std::string lockfile_path_; |
73 scoped_ptr<DumpInfo> dump_info_; | 73 scoped_ptr<DumpInfo> dump_info_; |
74 }; | 74 }; |
75 | 75 |
76 void DoWorkLockedTask(SynchronizedMinidumpManagerSimple* manager) { | 76 void DoWorkLockedTask(SynchronizedMinidumpManagerSimple* manager) { |
77 manager->DoWorkLocked(); | 77 manager->DoWorkLocked(); |
78 } | 78 } |
79 | 79 |
| 80 // Simple SynchronizedMinidumpManager consumer. Checks if a dump can be uploaded |
| 81 // then removes it from the lockfile. |
| 82 class FakeSynchronizedMinidumpUploader : public SynchronizedMinidumpManager { |
| 83 public: |
| 84 FakeSynchronizedMinidumpUploader() |
| 85 : SynchronizedMinidumpManager(), can_upload_return_val_(false) {} |
| 86 ~FakeSynchronizedMinidumpUploader() override {} |
| 87 |
| 88 int DoWorkLocked() { return AcquireLockAndDoWork(); } |
| 89 |
| 90 // SynchronizedMinidumpManager implementation: |
| 91 int DoWork() override { |
| 92 can_upload_return_val_ = CanUploadDump(); |
| 93 |
| 94 if (RemoveEntryFromLockFile(0) < 0) |
| 95 return -1; |
| 96 |
| 97 if (IncrementNumDumpsInCurrentPeriod() < 0) |
| 98 return -1; |
| 99 |
| 100 return 0; |
| 101 } |
| 102 |
| 103 // Accessors for testing. |
| 104 bool can_upload_return_val() { return can_upload_return_val_; } |
| 105 |
| 106 private: |
| 107 bool can_upload_return_val_; |
| 108 }; |
| 109 |
80 class SleepySynchronizedMinidumpManagerSimple | 110 class SleepySynchronizedMinidumpManagerSimple |
81 : public SynchronizedMinidumpManagerSimple { | 111 : public SynchronizedMinidumpManagerSimple { |
82 public: | 112 public: |
83 SleepySynchronizedMinidumpManagerSimple(int sleep_duration_ms) | 113 SleepySynchronizedMinidumpManagerSimple(int sleep_duration_ms) |
84 : SynchronizedMinidumpManagerSimple(), | 114 : SynchronizedMinidumpManagerSimple(), |
85 sleep_duration_ms_(sleep_duration_ms) {} | 115 sleep_duration_ms_(sleep_duration_ms) {} |
86 ~SleepySynchronizedMinidumpManagerSimple() override {} | 116 ~SleepySynchronizedMinidumpManagerSimple() override {} |
87 | 117 |
88 // SynchronizedMinidumpManager implementation: | 118 // SynchronizedMinidumpManager implementation: |
89 int DoWork() override { | 119 int DoWork() override { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 protected: | 161 protected: |
132 base::FilePath fake_home_dir_; // Path to the test home directory. | 162 base::FilePath fake_home_dir_; // Path to the test home directory. |
133 base::FilePath minidump_dir_; // Path the the minidump directory. | 163 base::FilePath minidump_dir_; // Path the the minidump directory. |
134 base::FilePath lockfile_; // Path to the lockfile in |minidump_dir_|. | 164 base::FilePath lockfile_; // Path to the lockfile in |minidump_dir_|. |
135 base::FilePath metadata_; // Path to the metadata in |minidump_dir_|. | 165 base::FilePath metadata_; // Path to the metadata in |minidump_dir_|. |
136 | 166 |
137 private: | 167 private: |
138 scoped_ptr<base::ScopedPathOverride> path_override_; | 168 scoped_ptr<base::ScopedPathOverride> path_override_; |
139 }; | 169 }; |
140 | 170 |
| 171 // Have |producer| generate |num_dumps| while checking there are no errors. |
| 172 void produce_dumps(SynchronizedMinidumpManagerSimple& producer, int num_dumps) { |
| 173 for (int i = 0; i < num_dumps; ++i) { |
| 174 ASSERT_EQ(0, producer.DoWorkLocked()); |
| 175 ASSERT_EQ(0, producer.add_entry_return_code()); |
| 176 } |
| 177 } |
| 178 |
| 179 // Have |consumer| remove and process |num_dumps| while checking there are no |
| 180 // errors. |
| 181 void consume_dumps(FakeSynchronizedMinidumpUploader& consumer, int num_dumps) { |
| 182 for (int i = 0; i < num_dumps; ++i) { |
| 183 ASSERT_EQ(0, consumer.DoWorkLocked()); |
| 184 ASSERT_EQ(true, consumer.can_upload_return_val()); |
| 185 } |
| 186 } |
| 187 |
141 } // namespace | 188 } // namespace |
142 | 189 |
143 TEST_F(SynchronizedMinidumpManagerTest, FilePathsAreCorrect) { | 190 TEST_F(SynchronizedMinidumpManagerTest, FilePathsAreCorrect) { |
144 SynchronizedMinidumpManagerSimple manager; | 191 SynchronizedMinidumpManagerSimple manager; |
145 | 192 |
146 // Verify file paths for directory and lock file. | 193 // Verify file paths for directory and lock file. |
147 ASSERT_EQ(minidump_dir_.value(), manager.dump_path()); | 194 ASSERT_EQ(minidump_dir_.value(), manager.dump_path()); |
148 ASSERT_EQ(lockfile_.value(), manager.lockfile_path()); | 195 ASSERT_EQ(lockfile_.value(), manager.lockfile_path()); |
149 } | 196 } |
150 | 197 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 EXPECT_EQ(0, manager.add_entry_return_code()); | 424 EXPECT_EQ(0, manager.add_entry_return_code()); |
378 EXPECT_TRUE(manager.work_done()); | 425 EXPECT_TRUE(manager.work_done()); |
379 | 426 |
380 // Test that both entries were logged. | 427 // Test that both entries were logged. |
381 ScopedVector<DumpInfo> dumps; | 428 ScopedVector<DumpInfo> dumps; |
382 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 429 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
383 EXPECT_EQ(2u, dumps.size()); | 430 EXPECT_EQ(2u, dumps.size()); |
384 } | 431 } |
385 | 432 |
386 TEST_F(SynchronizedMinidumpManagerTest, | 433 TEST_F(SynchronizedMinidumpManagerTest, |
387 AddEntryFailsWhenTooManyRecentDumpsPresent) { | 434 Upload_SucceedsWhenDumpLimitsNotExceeded) { |
388 // Sample parameters. | 435 // Sample parameters. |
389 time_t now = time(0); | 436 time_t now = time(0); |
390 MinidumpParams params; | 437 MinidumpParams params; |
391 params.process_name = "process"; | 438 params.process_name = "process"; |
392 | 439 |
393 SynchronizedMinidumpManagerSimple manager; | 440 FakeSynchronizedMinidumpUploader uploader; |
394 manager.SetDumpInfoToWrite( | 441 SynchronizedMinidumpManagerSimple producer; |
| 442 producer.SetDumpInfoToWrite( |
395 make_scoped_ptr(new DumpInfo("dump1", "log1", now, params))); | 443 make_scoped_ptr(new DumpInfo("dump1", "log1", now, params))); |
396 | 444 |
397 for (int i = 0; i < SynchronizedMinidumpManager::kMaxLockfileDumps; ++i) { | 445 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
398 // Adding these should succeed | 446 produce_dumps(producer, max_dumps); |
399 ASSERT_EQ(0, manager.DoWorkLocked()); | 447 consume_dumps(uploader, max_dumps); |
400 ASSERT_EQ(0, manager.add_entry_return_code()); | |
401 } | |
402 | |
403 ASSERT_EQ(0, manager.DoWorkLocked()); | |
404 | |
405 // This one should fail | |
406 ASSERT_GT(0, manager.add_entry_return_code()); | |
407 } | 448 } |
408 | 449 |
409 TEST_F(SynchronizedMinidumpManagerTest, | 450 TEST_F(SynchronizedMinidumpManagerTest, Upload_FailsWhenTooManyRecentDumps) { |
410 AddEntryFailsWhenRatelimitPeriodExceeded) { | |
411 // Sample parameters. | 451 // Sample parameters. |
412 time_t now = time(0); | 452 time_t now = time(0); |
413 MinidumpParams params; | 453 MinidumpParams params; |
414 params.process_name = "process"; | 454 params.process_name = "process"; |
415 | 455 |
416 SynchronizedMinidumpManagerSimple manager; | 456 FakeSynchronizedMinidumpUploader uploader; |
417 manager.SetDumpInfoToWrite( | 457 SynchronizedMinidumpManagerSimple producer; |
| 458 producer.SetDumpInfoToWrite( |
418 make_scoped_ptr(new DumpInfo("dump1", "log1", now, params))); | 459 make_scoped_ptr(new DumpInfo("dump1", "log1", now, params))); |
419 | 460 |
420 // Multiple iters to make sure period resets work correctly | 461 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
421 for (int iter = 0; iter < 3; ++iter) { | 462 produce_dumps(producer, max_dumps + 1); |
422 time_t now = time(nullptr); | 463 consume_dumps(uploader, max_dumps); |
423 | 464 |
424 // Write dump logs to the lockfile. | 465 // Should fail with too many dumps |
425 size_t too_many_recent_dumps = | 466 ASSERT_EQ(0, uploader.DoWorkLocked()); |
426 SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; | 467 ASSERT_EQ(false, uploader.can_upload_return_val()); |
427 for (size_t i = 0; i < too_many_recent_dumps; ++i) { | 468 } |
428 // Adding these should succeed | |
429 ASSERT_EQ(0, manager.DoWorkLocked()); | |
430 ASSERT_EQ(0, manager.add_entry_return_code()); | |
431 | 469 |
432 // Clear dumps so we don't reach max dumps in lockfile | 470 TEST_F(SynchronizedMinidumpManagerTest, UploadSucceedsAfterRateLimitPeriodEnd) { |
433 ASSERT_TRUE(ClearDumps(lockfile_.value())); | 471 // Sample parameters. |
434 } | 472 time_t now = time(0); |
| 473 MinidumpParams params; |
| 474 params.process_name = "process"; |
435 | 475 |
436 ASSERT_EQ(0, manager.DoWorkLocked()); | 476 FakeSynchronizedMinidumpUploader uploader; |
| 477 SynchronizedMinidumpManagerSimple producer; |
| 478 producer.SetDumpInfoToWrite( |
| 479 make_scoped_ptr(new DumpInfo("dump1", "log1", now, params))); |
| 480 |
| 481 const int iters = 3; |
| 482 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
| 483 |
| 484 for (int i = 0; i < iters; ++i) { |
| 485 produce_dumps(producer, max_dumps + 1); |
| 486 consume_dumps(uploader, max_dumps); |
| 487 |
437 // Should fail with too many dumps | 488 // Should fail with too many dumps |
438 ASSERT_GT(0, manager.add_entry_return_code()); | 489 ASSERT_EQ(0, uploader.DoWorkLocked()); |
| 490 ASSERT_EQ(false, uploader.can_upload_return_val()); |
439 | 491 |
440 int64 period = SynchronizedMinidumpManager::kRatelimitPeriodSeconds; | 492 int64 period = SynchronizedMinidumpManager::kRatelimitPeriodSeconds; |
441 | 493 |
442 // Half period shouldn't trigger reset | 494 // Half period shouldn't trigger reset |
| 495 produce_dumps(producer, 1); |
443 SetRatelimitPeriodStart(metadata_.value(), now - period / 2); | 496 SetRatelimitPeriodStart(metadata_.value(), now - period / 2); |
444 ASSERT_EQ(0, manager.DoWorkLocked()); | 497 ASSERT_EQ(0, uploader.DoWorkLocked()); |
445 ASSERT_GT(0, manager.add_entry_return_code()); | 498 ASSERT_EQ(false, uploader.can_upload_return_val()); |
446 | 499 |
447 // Set period starting time to trigger a reset | 500 // Set period starting time to trigger a reset |
448 SetRatelimitPeriodStart(metadata_.value(), now - period); | 501 SetRatelimitPeriodStart(metadata_.value(), now - period); |
449 } | 502 } |
450 | 503 |
451 ASSERT_EQ(0, manager.DoWorkLocked()); | 504 produce_dumps(producer, 1); |
452 ASSERT_EQ(0, manager.add_entry_return_code()); | 505 consume_dumps(uploader, 1); |
453 } | 506 } |
454 | 507 |
455 } // namespace chromecast | 508 } // namespace chromecast |
OLD | NEW |