| 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 |