| 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 "chromecast/crash/linux/synchronized_minidump_manager.h" | 5 #include "chromecast/crash/linux/synchronized_minidump_manager.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <stdio.h> // perror | 9 #include <stdio.h> // perror |
| 10 #include <stdlib.h> | 10 #include <stdlib.h> |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 const char kMinidumpSubdir[] = "minidumps"; | 41 const char kMinidumpSubdir[] = "minidumps"; |
| 42 | 42 |
| 43 // A trivial implementation of SynchronizedMinidumpManager, which does no work | 43 // A trivial implementation of SynchronizedMinidumpManager, which does no work |
| 44 // to the minidump and exposes its protected members for testing. This simply | 44 // to the minidump and exposes its protected members for testing. This simply |
| 45 // adds an entry to the lockfile. | 45 // adds an entry to the lockfile. |
| 46 class SynchronizedMinidumpManagerSimple : public SynchronizedMinidumpManager { | 46 class SynchronizedMinidumpManagerSimple : public SynchronizedMinidumpManager { |
| 47 public: | 47 public: |
| 48 SynchronizedMinidumpManagerSimple() | 48 SynchronizedMinidumpManagerSimple() |
| 49 : SynchronizedMinidumpManager(), | 49 : SynchronizedMinidumpManager(), |
| 50 work_done_(false), | 50 work_done_(false), |
| 51 add_entry_return_code_(-1), | 51 add_entry_return_code_(false), |
| 52 lockfile_path_(dump_path_.Append(kLockfileName).value()) {} | 52 lockfile_path_(dump_path_.Append(kLockfileName).value()) {} |
| 53 ~SynchronizedMinidumpManagerSimple() override {} | 53 ~SynchronizedMinidumpManagerSimple() override {} |
| 54 | 54 |
| 55 void SetDumpInfoToWrite(std::unique_ptr<DumpInfo> dump_info) { | 55 void SetDumpInfoToWrite(std::unique_ptr<DumpInfo> dump_info) { |
| 56 dump_info_ = std::move(dump_info); | 56 dump_info_ = std::move(dump_info); |
| 57 } | 57 } |
| 58 | 58 |
| 59 int DoWorkLocked() { return AcquireLockAndDoWork(); } | 59 bool DoWorkLocked() { return AcquireLockAndDoWork(); } |
| 60 | 60 |
| 61 // SynchronizedMinidumpManager implementation: | 61 // SynchronizedMinidumpManager implementation: |
| 62 int DoWork() override { | 62 bool DoWork() override { |
| 63 if (dump_info_) | 63 if (dump_info_) |
| 64 add_entry_return_code_ = AddEntryToLockFile(*dump_info_); | 64 add_entry_return_code_ = AddEntryToLockFile(*dump_info_); |
| 65 work_done_ = true; | 65 work_done_ = true; |
| 66 return 0; | 66 return true; |
| 67 } | 67 } |
| 68 | 68 |
| 69 // Accessors for testing. | 69 // Accessors for testing. |
| 70 bool HasDumps() { return SynchronizedMinidumpManager::HasDumps(); } | 70 bool HasDumps() { return SynchronizedMinidumpManager::HasDumps(); } |
| 71 const std::string& dump_path() { return dump_path_.value(); } | 71 const std::string& dump_path() { return dump_path_.value(); } |
| 72 const std::string& lockfile_path() { return lockfile_path_; } | 72 const std::string& lockfile_path() { return lockfile_path_; } |
| 73 bool work_done() { return work_done_; } | 73 bool work_done() { return work_done_; } |
| 74 int add_entry_return_code() { return add_entry_return_code_; } | 74 bool add_entry_return_code() { return add_entry_return_code_; } |
| 75 | 75 |
| 76 private: | 76 private: |
| 77 bool work_done_; | 77 bool work_done_; |
| 78 int add_entry_return_code_; | 78 bool add_entry_return_code_; |
| 79 std::string lockfile_path_; | 79 std::string lockfile_path_; |
| 80 std::unique_ptr<DumpInfo> dump_info_; | 80 std::unique_ptr<DumpInfo> dump_info_; |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 void DoWorkLockedTask(SynchronizedMinidumpManagerSimple* manager) { | 83 void DoWorkLockedTask(SynchronizedMinidumpManagerSimple* manager) { |
| 84 manager->DoWorkLocked(); | 84 manager->DoWorkLocked(); |
| 85 } | 85 } |
| 86 | 86 |
| 87 // Simple SynchronizedMinidumpManager consumer. Checks if a dump can be uploaded | 87 // Simple SynchronizedMinidumpManager consumer. Checks if a dump can be uploaded |
| 88 // then removes it from the lockfile. | 88 // then removes it from the lockfile. |
| 89 class FakeSynchronizedMinidumpUploader : public SynchronizedMinidumpManager { | 89 class FakeSynchronizedMinidumpUploader : public SynchronizedMinidumpManager { |
| 90 public: | 90 public: |
| 91 FakeSynchronizedMinidumpUploader() | 91 FakeSynchronizedMinidumpUploader() |
| 92 : SynchronizedMinidumpManager(), can_upload_return_val_(false) {} | 92 : SynchronizedMinidumpManager(), can_upload_return_val_(false) {} |
| 93 ~FakeSynchronizedMinidumpUploader() override {} | 93 ~FakeSynchronizedMinidumpUploader() override {} |
| 94 | 94 |
| 95 int DoWorkLocked() { return AcquireLockAndDoWork(); } | 95 bool DoWorkLocked() { return AcquireLockAndDoWork(); } |
| 96 | 96 |
| 97 // SynchronizedMinidumpManager implementation: | 97 // SynchronizedMinidumpManager implementation: |
| 98 int DoWork() override { | 98 bool DoWork() override { |
| 99 can_upload_return_val_ = CanUploadDump(); | 99 can_upload_return_val_ = CanUploadDump(); |
| 100 | 100 |
| 101 if (RemoveEntryFromLockFile(0) < 0) | 101 if (!RemoveEntryFromLockFile(0)) |
| 102 return -1; | 102 return false; |
| 103 | 103 |
| 104 if (IncrementNumDumpsInCurrentPeriod() < 0) | 104 if (!IncrementNumDumpsInCurrentPeriod()) |
| 105 return -1; | 105 return false; |
| 106 | 106 |
| 107 return 0; | 107 return true; |
| 108 } | 108 } |
| 109 | 109 |
| 110 // Accessors for testing. | 110 // Accessors for testing. |
| 111 bool HasDumps() { return SynchronizedMinidumpManager::HasDumps(); } | 111 bool HasDumps() { return SynchronizedMinidumpManager::HasDumps(); } |
| 112 bool can_upload_return_val() { return can_upload_return_val_; } | 112 bool can_upload_return_val() { return can_upload_return_val_; } |
| 113 | 113 |
| 114 private: | 114 private: |
| 115 bool can_upload_return_val_; | 115 bool can_upload_return_val_; |
| 116 }; | 116 }; |
| 117 | 117 |
| 118 class SleepySynchronizedMinidumpManagerSimple | 118 class SleepySynchronizedMinidumpManagerSimple |
| 119 : public SynchronizedMinidumpManagerSimple { | 119 : public SynchronizedMinidumpManagerSimple { |
| 120 public: | 120 public: |
| 121 SleepySynchronizedMinidumpManagerSimple(int sleep_duration_ms) | 121 SleepySynchronizedMinidumpManagerSimple(int sleep_duration_ms) |
| 122 : SynchronizedMinidumpManagerSimple(), | 122 : SynchronizedMinidumpManagerSimple(), |
| 123 sleep_duration_ms_(sleep_duration_ms) {} | 123 sleep_duration_ms_(sleep_duration_ms) {} |
| 124 ~SleepySynchronizedMinidumpManagerSimple() override {} | 124 ~SleepySynchronizedMinidumpManagerSimple() override {} |
| 125 | 125 |
| 126 // SynchronizedMinidumpManager implementation: | 126 // SynchronizedMinidumpManager implementation: |
| 127 int DoWork() override { | 127 bool DoWork() override { |
| 128 // The lock has been acquired. Fall asleep for |kSleepDurationMs|, then | 128 // The lock has been acquired. Fall asleep for |kSleepDurationMs|, then |
| 129 // write the file. | 129 // write the file. |
| 130 base::PlatformThread::Sleep( | 130 base::PlatformThread::Sleep( |
| 131 base::TimeDelta::FromMilliseconds(sleep_duration_ms_)); | 131 base::TimeDelta::FromMilliseconds(sleep_duration_ms_)); |
| 132 return SynchronizedMinidumpManagerSimple::DoWork(); | 132 return SynchronizedMinidumpManagerSimple::DoWork(); |
| 133 } | 133 } |
| 134 | 134 |
| 135 private: | 135 private: |
| 136 const int sleep_duration_ms_; | 136 const int sleep_duration_ms_; |
| 137 }; | 137 }; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 167 base::FilePath metadata_; // Path to the metadata in |minidump_dir_|. | 167 base::FilePath metadata_; // Path to the metadata in |minidump_dir_|. |
| 168 | 168 |
| 169 private: | 169 private: |
| 170 base::ScopedTempDir fake_home_dir_; | 170 base::ScopedTempDir fake_home_dir_; |
| 171 std::unique_ptr<base::ScopedPathOverride> path_override_; | 171 std::unique_ptr<base::ScopedPathOverride> path_override_; |
| 172 }; | 172 }; |
| 173 | 173 |
| 174 // Have |producer| generate |num_dumps| while checking there are no errors. | 174 // Have |producer| generate |num_dumps| while checking there are no errors. |
| 175 void produce_dumps(SynchronizedMinidumpManagerSimple& producer, int num_dumps) { | 175 void produce_dumps(SynchronizedMinidumpManagerSimple& producer, int num_dumps) { |
| 176 for (int i = 0; i < num_dumps; ++i) { | 176 for (int i = 0; i < num_dumps; ++i) { |
| 177 ASSERT_EQ(0, producer.DoWorkLocked()); | 177 ASSERT_TRUE(producer.DoWorkLocked()); |
| 178 ASSERT_EQ(0, producer.add_entry_return_code()); | 178 ASSERT_TRUE(producer.add_entry_return_code()); |
| 179 } | 179 } |
| 180 } | 180 } |
| 181 | 181 |
| 182 // Have |consumer| remove and process |num_dumps| while checking there are no | 182 // Have |consumer| remove and process |num_dumps| while checking there are no |
| 183 // errors. | 183 // errors. |
| 184 void consume_dumps(FakeSynchronizedMinidumpUploader& consumer, int num_dumps) { | 184 void consume_dumps(FakeSynchronizedMinidumpUploader& consumer, int num_dumps) { |
| 185 for (int i = 0; i < num_dumps; ++i) { | 185 for (int i = 0; i < num_dumps; ++i) { |
| 186 ASSERT_EQ(0, consumer.DoWorkLocked()); | 186 ASSERT_TRUE(consumer.DoWorkLocked()); |
| 187 ASSERT_TRUE(consumer.can_upload_return_val()); | 187 ASSERT_TRUE(consumer.can_upload_return_val()); |
| 188 } | 188 } |
| 189 } | 189 } |
| 190 | 190 |
| 191 } // namespace | 191 } // namespace |
| 192 | 192 |
| 193 TEST_F(SynchronizedMinidumpManagerTest, FilePathsAreCorrect) { | 193 TEST_F(SynchronizedMinidumpManagerTest, FilePathsAreCorrect) { |
| 194 SynchronizedMinidumpManagerSimple manager; | 194 SynchronizedMinidumpManagerSimple manager; |
| 195 | 195 |
| 196 // Verify file paths for directory and lock file. | 196 // Verify file paths for directory and lock file. |
| 197 ASSERT_EQ(minidump_dir_.value(), manager.dump_path()); | 197 ASSERT_EQ(minidump_dir_.value(), manager.dump_path()); |
| 198 ASSERT_EQ(lockfile_.value(), manager.lockfile_path()); | 198 ASSERT_EQ(lockfile_.value(), manager.lockfile_path()); |
| 199 } | 199 } |
| 200 | 200 |
| 201 TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnNonExistentDirectory) { | 201 TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnNonExistentDirectory) { |
| 202 // The directory was created in SetUp(). Delete it and its contents. | 202 // The directory was created in SetUp(). Delete it and its contents. |
| 203 ASSERT_TRUE(base::DeleteFile(minidump_dir_, true)); | 203 ASSERT_TRUE(base::DeleteFile(minidump_dir_, true)); |
| 204 ASSERT_FALSE(base::PathExists(minidump_dir_)); | 204 ASSERT_FALSE(base::PathExists(minidump_dir_)); |
| 205 | 205 |
| 206 SynchronizedMinidumpManagerSimple manager; | 206 SynchronizedMinidumpManagerSimple manager; |
| 207 ASSERT_EQ(0, manager.DoWorkLocked()); | 207 ASSERT_TRUE(manager.DoWorkLocked()); |
| 208 ASSERT_TRUE(manager.work_done()); | 208 ASSERT_TRUE(manager.work_done()); |
| 209 | 209 |
| 210 // Verify the directory and the lockfile both exist. | 210 // Verify the directory and the lockfile both exist. |
| 211 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); | 211 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); |
| 212 ASSERT_TRUE(base::PathExists(lockfile_)); | 212 ASSERT_TRUE(base::PathExists(lockfile_)); |
| 213 } | 213 } |
| 214 | 214 |
| 215 TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnExistingEmptyDirectory) { | 215 TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnExistingEmptyDirectory) { |
| 216 // The lockfile was created in SetUp(). Delete it. | 216 // The lockfile was created in SetUp(). Delete it. |
| 217 ASSERT_TRUE(base::DeleteFile(lockfile_, false)); | 217 ASSERT_TRUE(base::DeleteFile(lockfile_, false)); |
| 218 ASSERT_FALSE(base::PathExists(lockfile_)); | 218 ASSERT_FALSE(base::PathExists(lockfile_)); |
| 219 | 219 |
| 220 SynchronizedMinidumpManagerSimple manager; | 220 SynchronizedMinidumpManagerSimple manager; |
| 221 ASSERT_EQ(0, manager.DoWorkLocked()); | 221 ASSERT_TRUE(manager.DoWorkLocked()); |
| 222 ASSERT_TRUE(manager.work_done()); | 222 ASSERT_TRUE(manager.work_done()); |
| 223 | 223 |
| 224 // Verify the directory and the lockfile both exist. | 224 // Verify the directory and the lockfile both exist. |
| 225 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); | 225 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); |
| 226 ASSERT_TRUE(base::PathExists(lockfile_)); | 226 ASSERT_TRUE(base::PathExists(lockfile_)); |
| 227 } | 227 } |
| 228 | 228 |
| 229 TEST_F(SynchronizedMinidumpManagerTest, | 229 TEST_F(SynchronizedMinidumpManagerTest, |
| 230 AcquireLockOnExistingDirectoryWithLockfile) { | 230 AcquireLockOnExistingDirectoryWithLockfile) { |
| 231 SynchronizedMinidumpManagerSimple manager; | 231 SynchronizedMinidumpManagerSimple manager; |
| 232 ASSERT_EQ(0, manager.DoWorkLocked()); | 232 ASSERT_TRUE(manager.DoWorkLocked()); |
| 233 ASSERT_TRUE(manager.work_done()); | 233 ASSERT_TRUE(manager.work_done()); |
| 234 | 234 |
| 235 // Verify the directory and the lockfile both exist. | 235 // Verify the directory and the lockfile both exist. |
| 236 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); | 236 ASSERT_TRUE(base::DirectoryExists(minidump_dir_)); |
| 237 ASSERT_TRUE(base::PathExists(lockfile_)); | 237 ASSERT_TRUE(base::PathExists(lockfile_)); |
| 238 } | 238 } |
| 239 | 239 |
| 240 TEST_F(SynchronizedMinidumpManagerTest, | 240 TEST_F(SynchronizedMinidumpManagerTest, |
| 241 AddEntryToLockFile_FailsWithInvalidEntry) { | 241 AddEntryToLockFile_FailsWithInvalidEntry) { |
| 242 // Create invalid dump info value | 242 // Create invalid dump info value |
| 243 base::DictionaryValue val; | 243 base::DictionaryValue val; |
| 244 | 244 |
| 245 // Test that the manager tried to log the entry and failed. | 245 // Test that the manager tried to log the entry and failed. |
| 246 SynchronizedMinidumpManagerSimple manager; | 246 SynchronizedMinidumpManagerSimple manager; |
| 247 manager.SetDumpInfoToWrite(base::WrapUnique(new DumpInfo(&val))); | 247 manager.SetDumpInfoToWrite(base::WrapUnique(new DumpInfo(&val))); |
| 248 ASSERT_EQ(0, manager.DoWorkLocked()); | 248 ASSERT_TRUE(manager.DoWorkLocked()); |
| 249 ASSERT_EQ(-1, manager.add_entry_return_code()); | 249 ASSERT_FALSE(manager.add_entry_return_code()); |
| 250 | 250 |
| 251 // Verify the lockfile is untouched. | 251 // Verify the lockfile is untouched. |
| 252 ScopedVector<DumpInfo> dumps; | 252 ScopedVector<DumpInfo> dumps; |
| 253 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 253 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
| 254 ASSERT_EQ(0u, dumps.size()); | 254 ASSERT_EQ(0u, dumps.size()); |
| 255 } | 255 } |
| 256 | 256 |
| 257 TEST_F(SynchronizedMinidumpManagerTest, | 257 TEST_F(SynchronizedMinidumpManagerTest, |
| 258 AddEntryToLockFile_SucceedsWithValidEntries) { | 258 AddEntryToLockFile_SucceedsWithValidEntries) { |
| 259 // Sample parameters. | 259 // Sample parameters. |
| 260 time_t now = time(0); | 260 base::Time now = base::Time::Now(); |
| 261 MinidumpParams params; | 261 MinidumpParams params; |
| 262 params.process_name = "process"; | 262 params.process_name = "process"; |
| 263 | 263 |
| 264 // Write the first entry. | 264 // Write the first entry. |
| 265 SynchronizedMinidumpManagerSimple manager; | 265 SynchronizedMinidumpManagerSimple manager; |
| 266 manager.SetDumpInfoToWrite( | 266 manager.SetDumpInfoToWrite( |
| 267 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); | 267 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); |
| 268 ASSERT_EQ(0, manager.DoWorkLocked()); | 268 ASSERT_TRUE(manager.DoWorkLocked()); |
| 269 ASSERT_EQ(0, manager.add_entry_return_code()); | 269 ASSERT_TRUE(manager.add_entry_return_code()); |
| 270 | 270 |
| 271 // Test that the manager was successful in logging the entry. | 271 // Test that the manager was successful in logging the entry. |
| 272 ScopedVector<DumpInfo> dumps; | 272 ScopedVector<DumpInfo> dumps; |
| 273 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 273 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
| 274 ASSERT_EQ(1u, dumps.size()); | 274 ASSERT_EQ(1u, dumps.size()); |
| 275 | 275 |
| 276 // Write the second entry. | 276 // Write the second entry. |
| 277 manager.SetDumpInfoToWrite( | 277 manager.SetDumpInfoToWrite( |
| 278 base::WrapUnique(new DumpInfo("dump2", "log2", now, params))); | 278 base::WrapUnique(new DumpInfo("dump2", "log2", now, params))); |
| 279 ASSERT_EQ(0, manager.DoWorkLocked()); | 279 ASSERT_TRUE(manager.DoWorkLocked()); |
| 280 ASSERT_EQ(0, manager.add_entry_return_code()); | 280 ASSERT_TRUE(manager.add_entry_return_code()); |
| 281 | 281 |
| 282 // Test that the second entry is also valid. | 282 // Test that the second entry is also valid. |
| 283 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 283 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
| 284 ASSERT_EQ(2u, dumps.size()); | 284 ASSERT_EQ(2u, dumps.size()); |
| 285 } | 285 } |
| 286 | 286 |
| 287 TEST_F(SynchronizedMinidumpManagerTest, | 287 TEST_F(SynchronizedMinidumpManagerTest, AcquireLockFile_WaitsForOtherThread) { |
| 288 AcquireLockFile_FailsWhenNonBlockingAndFileLocked) { | |
| 289 ASSERT_TRUE(CreateFiles(lockfile_.value(), metadata_.value())); | |
| 290 // Lock the lockfile here. Note that the Chromium base::File tools permit | |
| 291 // multiple locks on the same process to succeed, so we must use POSIX system | |
| 292 // calls to accomplish this. | |
| 293 int fd = open(lockfile_.value().c_str(), O_RDWR | O_CREAT, 0660); | |
| 294 ASSERT_GE(fd, 0); | |
| 295 ASSERT_EQ(0, flock(fd, LOCK_EX)); | |
| 296 | |
| 297 SynchronizedMinidumpManagerSimple manager; | |
| 298 manager.set_non_blocking(true); | |
| 299 ASSERT_EQ(-1, manager.DoWorkLocked()); | |
| 300 ASSERT_FALSE(manager.work_done()); | |
| 301 | |
| 302 // Test that the manager was not able to log the crash dump. | |
| 303 ScopedVector<DumpInfo> dumps; | |
| 304 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | |
| 305 ASSERT_EQ(0u, dumps.size()); | |
| 306 } | |
| 307 | |
| 308 TEST_F(SynchronizedMinidumpManagerTest, | |
| 309 AcquireLockFile_WaitsForOtherThreadWhenBlocking) { | |
| 310 // Create some parameters for a minidump. | 288 // Create some parameters for a minidump. |
| 311 time_t now = time(0); | 289 base::Time now = base::Time::Now(); |
| 312 MinidumpParams params; | 290 MinidumpParams params; |
| 313 params.process_name = "process"; | 291 params.process_name = "process"; |
| 314 | 292 |
| 315 // Create a manager that grabs the lock then sleeps. Post a DoWork task to | 293 // Create a manager that grabs the lock then sleeps. Post a DoWork task to |
| 316 // another thread. |sleepy_manager| will grab the lock and hold it for | 294 // another thread. |sleepy_manager| will grab the lock and hold it for |
| 317 // |sleep_time_ms|. It will then write a dump and release the lock. | 295 // |sleep_time_ms|. It will then write a dump and release the lock. |
| 318 const int sleep_time_ms = 100; | 296 const int sleep_time_ms = 100; |
| 319 SleepySynchronizedMinidumpManagerSimple sleepy_manager(sleep_time_ms); | 297 SleepySynchronizedMinidumpManagerSimple sleepy_manager(sleep_time_ms); |
| 320 sleepy_manager.SetDumpInfoToWrite( | 298 sleepy_manager.SetDumpInfoToWrite( |
| 321 base::WrapUnique(new DumpInfo("dump", "log", now, params))); | 299 base::WrapUnique(new DumpInfo("dump", "log", now, params))); |
| 322 base::Thread sleepy_thread("sleepy"); | 300 base::Thread sleepy_thread("sleepy"); |
| 323 sleepy_thread.Start(); | 301 sleepy_thread.Start(); |
| 324 sleepy_thread.task_runner()->PostTask( | 302 sleepy_thread.task_runner()->PostTask( |
| 325 FROM_HERE, | 303 FROM_HERE, |
| 326 base::Bind(&DoWorkLockedTask, base::Unretained(&sleepy_manager))); | 304 base::Bind(&DoWorkLockedTask, base::Unretained(&sleepy_manager))); |
| 327 | 305 |
| 328 // Meanwhile, this thread should wait brielfy to allow the other thread to | 306 // Meanwhile, this thread should wait brielfy to allow the other thread to |
| 329 // grab the lock. | 307 // grab the lock. |
| 330 const int concurrency_delay = 50; | 308 const int concurrency_delay = 50; |
| 331 base::PlatformThread::Sleep( | 309 base::PlatformThread::Sleep( |
| 332 base::TimeDelta::FromMilliseconds(concurrency_delay)); | 310 base::TimeDelta::FromMilliseconds(concurrency_delay)); |
| 333 | 311 |
| 334 // |sleepy_manager| has the lock by now, but has not released it. Attempt to | 312 // |sleepy_manager| has the lock by now, but has not released it. Attempt to |
| 335 // grab it. DoWorkLocked() should block until |manager| has a chance to write | 313 // grab it. DoWorkLocked() should block until |manager| has a chance to write |
| 336 // the dump. | 314 // the dump. |
| 337 SynchronizedMinidumpManagerSimple manager; | 315 SynchronizedMinidumpManagerSimple manager; |
| 338 manager.SetDumpInfoToWrite( | 316 manager.SetDumpInfoToWrite( |
| 339 base::WrapUnique(new DumpInfo("dump", "log", now, params))); | 317 base::WrapUnique(new DumpInfo("dump", "log", now, params))); |
| 340 manager.set_non_blocking(false); | |
| 341 | 318 |
| 342 EXPECT_EQ(0, manager.DoWorkLocked()); | 319 EXPECT_TRUE(manager.DoWorkLocked()); |
| 343 EXPECT_EQ(0, manager.add_entry_return_code()); | 320 EXPECT_TRUE(manager.add_entry_return_code()); |
| 344 EXPECT_TRUE(manager.work_done()); | 321 EXPECT_TRUE(manager.work_done()); |
| 345 | 322 |
| 346 // Check that the other manager was also successful. | 323 // Check that the other manager was also successful. |
| 347 EXPECT_EQ(0, sleepy_manager.add_entry_return_code()); | 324 EXPECT_TRUE(sleepy_manager.add_entry_return_code()); |
| 348 EXPECT_TRUE(sleepy_manager.work_done()); | 325 EXPECT_TRUE(sleepy_manager.work_done()); |
| 349 | 326 |
| 350 // Test that both entries were logged. | 327 // Test that both entries were logged. |
| 351 ScopedVector<DumpInfo> dumps; | 328 ScopedVector<DumpInfo> dumps; |
| 352 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 329 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
| 353 EXPECT_EQ(2u, dumps.size()); | 330 EXPECT_EQ(2u, dumps.size()); |
| 354 } | 331 } |
| 355 | 332 |
| 356 // TODO(slan): These tests are passing but forking them is creating duplicates | 333 // TODO(slan): These tests are passing but forking them is creating duplicates |
| 357 // of all tests in this thread. Figure out how to lock the file more cleanly | 334 // of all tests in this thread. Figure out how to lock the file more cleanly |
| 358 // from another process. | 335 // from another process. |
| 359 TEST_F(SynchronizedMinidumpManagerTest, | 336 TEST_F(SynchronizedMinidumpManagerTest, |
| 360 DISABLED_AcquireLockFile_FailsWhenNonBlockingAndLockedFromOtherProcess) { | 337 DISABLED_AcquireLockFile_WaitsForOtherProcess) { |
| 361 // Fork the process. | |
| 362 pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr); | |
| 363 if (pid != 0) { | |
| 364 // The child process should instantiate a manager which immediately grabs | |
| 365 // the lock, and falls aleep for some period of time, then writes a dump, | |
| 366 // and finally releases the lock. | |
| 367 SleepySynchronizedMinidumpManagerSimple sleepy_manager(100); | |
| 368 ASSERT_EQ(0, sleepy_manager.DoWorkLocked()); | |
| 369 ASSERT_TRUE(sleepy_manager.work_done()); | |
| 370 return; | |
| 371 } | |
| 372 | |
| 373 // Meanwhile, this process should wait brielfy to allow the other thread to | |
| 374 // grab the lock. | |
| 375 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); | |
| 376 | |
| 377 SynchronizedMinidumpManagerSimple manager; | |
| 378 manager.set_non_blocking(true); | |
| 379 ASSERT_EQ(-1, manager.DoWorkLocked()); | |
| 380 ASSERT_FALSE(manager.work_done()); | |
| 381 | |
| 382 // Test that the manager was not able to log the crash dump. | |
| 383 ScopedVector<DumpInfo> dumps; | |
| 384 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | |
| 385 ASSERT_EQ(0u, dumps.size()); | |
| 386 } | |
| 387 | |
| 388 // TODO(slan): These tests are passing but forking them is creating duplicates | |
| 389 // of all tests in this thread. Figure out how to lock the file more cleanly | |
| 390 // from another process. | |
| 391 TEST_F(SynchronizedMinidumpManagerTest, | |
| 392 DISABLED_AcquireLockFile_WaitsForOtherProcessWhenBlocking) { | |
| 393 // Create some parameters for a minidump. | 338 // Create some parameters for a minidump. |
| 394 time_t now = time(0); | 339 base::Time now = base::Time::Now(); |
| 395 MinidumpParams params; | 340 MinidumpParams params; |
| 396 params.process_name = "process"; | 341 params.process_name = "process"; |
| 397 | 342 |
| 398 // Fork the process. | 343 // Fork the process. |
| 399 pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr); | 344 pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr); |
| 400 if (pid != 0) { | 345 if (pid != 0) { |
| 401 // The child process should instantiate a manager which immediately grabs | 346 // The child process should instantiate a manager which immediately grabs |
| 402 // the lock, and falls aleep for some period of time, then writes a dump, | 347 // the lock, and falls aleep for some period of time, then writes a dump, |
| 403 // and finally releases the lock. | 348 // and finally releases the lock. |
| 404 SleepySynchronizedMinidumpManagerSimple sleepy_manager(100); | 349 SleepySynchronizedMinidumpManagerSimple sleepy_manager(100); |
| 405 sleepy_manager.SetDumpInfoToWrite( | 350 sleepy_manager.SetDumpInfoToWrite( |
| 406 base::WrapUnique(new DumpInfo("dump", "log", now, params))); | 351 base::WrapUnique(new DumpInfo("dump", "log", now, params))); |
| 407 ASSERT_EQ(0, sleepy_manager.DoWorkLocked()); | 352 ASSERT_TRUE(sleepy_manager.DoWorkLocked()); |
| 408 ASSERT_TRUE(sleepy_manager.work_done()); | 353 ASSERT_TRUE(sleepy_manager.work_done()); |
| 409 return; | 354 return; |
| 410 } | 355 } |
| 411 | 356 |
| 412 // Meanwhile, this process should wait brielfy to allow the other thread to | 357 // Meanwhile, this process should wait brielfy to allow the other thread to |
| 413 // grab the lock. | 358 // grab the lock. |
| 414 const int concurrency_delay = 50; | 359 const int concurrency_delay = 50; |
| 415 base::PlatformThread::Sleep( | 360 base::PlatformThread::Sleep( |
| 416 base::TimeDelta::FromMilliseconds(concurrency_delay)); | 361 base::TimeDelta::FromMilliseconds(concurrency_delay)); |
| 417 | 362 |
| 418 // |sleepy_manager| has the lock by now, but has not released it. Attempt to | 363 // |sleepy_manager| has the lock by now, but has not released it. Attempt to |
| 419 // grab it. DoWorkLocked() should block until |manager| has a chance to write | 364 // grab it. DoWorkLocked() should block until |manager| has a chance to write |
| 420 // the dump. | 365 // the dump. |
| 421 SynchronizedMinidumpManagerSimple manager; | 366 SynchronizedMinidumpManagerSimple manager; |
| 422 manager.SetDumpInfoToWrite( | 367 manager.SetDumpInfoToWrite( |
| 423 base::WrapUnique(new DumpInfo("dump", "log", now, params))); | 368 base::WrapUnique(new DumpInfo("dump", "log", now, params))); |
| 424 manager.set_non_blocking(false); | |
| 425 | 369 |
| 426 EXPECT_EQ(0, manager.DoWorkLocked()); | 370 EXPECT_TRUE(manager.DoWorkLocked()); |
| 427 EXPECT_EQ(0, manager.add_entry_return_code()); | 371 EXPECT_TRUE(manager.add_entry_return_code()); |
| 428 EXPECT_TRUE(manager.work_done()); | 372 EXPECT_TRUE(manager.work_done()); |
| 429 | 373 |
| 430 // Test that both entries were logged. | 374 // Test that both entries were logged. |
| 431 ScopedVector<DumpInfo> dumps; | 375 ScopedVector<DumpInfo> dumps; |
| 432 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); | 376 ASSERT_TRUE(FetchDumps(lockfile_.value(), &dumps)); |
| 433 EXPECT_EQ(2u, dumps.size()); | 377 EXPECT_EQ(2u, dumps.size()); |
| 434 } | 378 } |
| 435 | 379 |
| 436 TEST_F(SynchronizedMinidumpManagerTest, | 380 TEST_F(SynchronizedMinidumpManagerTest, |
| 437 Upload_SucceedsWhenDumpLimitsNotExceeded) { | 381 Upload_SucceedsWhenDumpLimitsNotExceeded) { |
| 438 // Sample parameters. | 382 // Sample parameters. |
| 439 time_t now = time(0); | 383 base::Time now = base::Time::Now(); |
| 440 MinidumpParams params; | 384 MinidumpParams params; |
| 441 params.process_name = "process"; | 385 params.process_name = "process"; |
| 442 | 386 |
| 443 FakeSynchronizedMinidumpUploader uploader; | 387 FakeSynchronizedMinidumpUploader uploader; |
| 444 SynchronizedMinidumpManagerSimple producer; | 388 SynchronizedMinidumpManagerSimple producer; |
| 445 producer.SetDumpInfoToWrite( | 389 producer.SetDumpInfoToWrite( |
| 446 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); | 390 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); |
| 447 | 391 |
| 448 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; | 392 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
| 449 produce_dumps(producer, max_dumps); | 393 produce_dumps(producer, max_dumps); |
| 450 consume_dumps(uploader, max_dumps); | 394 consume_dumps(uploader, max_dumps); |
| 451 } | 395 } |
| 452 | 396 |
| 453 TEST_F(SynchronizedMinidumpManagerTest, Upload_FailsWhenTooManyRecentDumps) { | 397 TEST_F(SynchronizedMinidumpManagerTest, Upload_FailsWhenTooManyRecentDumps) { |
| 454 // Sample parameters. | 398 // Sample parameters. |
| 455 time_t now = time(0); | 399 base::Time now = base::Time::Now(); |
| 456 MinidumpParams params; | 400 MinidumpParams params; |
| 457 params.process_name = "process"; | 401 params.process_name = "process"; |
| 458 | 402 |
| 459 FakeSynchronizedMinidumpUploader uploader; | 403 FakeSynchronizedMinidumpUploader uploader; |
| 460 SynchronizedMinidumpManagerSimple producer; | 404 SynchronizedMinidumpManagerSimple producer; |
| 461 producer.SetDumpInfoToWrite( | 405 producer.SetDumpInfoToWrite( |
| 462 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); | 406 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); |
| 463 | 407 |
| 464 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; | 408 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
| 465 produce_dumps(producer, max_dumps + 1); | 409 produce_dumps(producer, max_dumps + 1); |
| 466 consume_dumps(uploader, max_dumps); | 410 consume_dumps(uploader, max_dumps); |
| 467 | 411 |
| 468 // Should fail with too many dumps | 412 // Should fail with too many dumps |
| 469 ASSERT_EQ(0, uploader.DoWorkLocked()); | 413 ASSERT_TRUE(uploader.DoWorkLocked()); |
| 470 ASSERT_FALSE(uploader.can_upload_return_val()); | 414 ASSERT_FALSE(uploader.can_upload_return_val()); |
| 471 } | 415 } |
| 472 | 416 |
| 473 TEST_F(SynchronizedMinidumpManagerTest, UploadSucceedsAfterRateLimitPeriodEnd) { | 417 TEST_F(SynchronizedMinidumpManagerTest, UploadSucceedsAfterRateLimitPeriodEnd) { |
| 474 // Sample parameters. | 418 // Sample parameters. |
| 475 time_t now = time(0); | 419 base::Time now = base::Time::Now(); |
| 476 MinidumpParams params; | 420 MinidumpParams params; |
| 477 params.process_name = "process"; | 421 params.process_name = "process"; |
| 478 | 422 |
| 479 FakeSynchronizedMinidumpUploader uploader; | 423 FakeSynchronizedMinidumpUploader uploader; |
| 480 SynchronizedMinidumpManagerSimple producer; | 424 SynchronizedMinidumpManagerSimple producer; |
| 481 producer.SetDumpInfoToWrite( | 425 producer.SetDumpInfoToWrite( |
| 482 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); | 426 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); |
| 483 | 427 |
| 484 const int iters = 3; | 428 const int iters = 3; |
| 485 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; | 429 const int max_dumps = SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps; |
| 486 | 430 |
| 487 for (int i = 0; i < iters; ++i) { | 431 for (int i = 0; i < iters; ++i) { |
| 488 produce_dumps(producer, max_dumps + 1); | 432 produce_dumps(producer, max_dumps + 1); |
| 489 consume_dumps(uploader, max_dumps); | 433 consume_dumps(uploader, max_dumps); |
| 490 | 434 |
| 491 // Should fail with too many dumps | 435 // Should fail with too many dumps |
| 492 ASSERT_EQ(0, uploader.DoWorkLocked()); | 436 ASSERT_TRUE(uploader.DoWorkLocked()); |
| 493 ASSERT_FALSE(uploader.can_upload_return_val()); | 437 ASSERT_FALSE(uploader.can_upload_return_val()); |
| 494 | 438 |
| 495 int64_t period = SynchronizedMinidumpManager::kRatelimitPeriodSeconds; | 439 base::TimeDelta period = base::TimeDelta::FromSeconds( |
| 440 SynchronizedMinidumpManager::kRatelimitPeriodSeconds); |
| 441 base::Time now = base::Time::Now(); |
| 496 | 442 |
| 497 // Half period shouldn't trigger reset | 443 // Half period shouldn't trigger reset |
| 498 produce_dumps(producer, 1); | 444 produce_dumps(producer, 1); |
| 499 SetRatelimitPeriodStart(metadata_.value(), now - period / 2); | 445 SetRatelimitPeriodStart(metadata_.value(), now - period / 2); |
| 500 ASSERT_EQ(0, uploader.DoWorkLocked()); | 446 ASSERT_TRUE(uploader.DoWorkLocked()); |
| 501 ASSERT_FALSE(uploader.can_upload_return_val()); | 447 ASSERT_FALSE(uploader.can_upload_return_val()); |
| 502 | 448 |
| 503 // Set period starting time to trigger a reset | 449 // Set period starting time to trigger a reset |
| 504 SetRatelimitPeriodStart(metadata_.value(), now - period); | 450 SetRatelimitPeriodStart(metadata_.value(), now - period); |
| 505 } | 451 } |
| 506 | 452 |
| 507 produce_dumps(producer, 1); | 453 produce_dumps(producer, 1); |
| 508 consume_dumps(uploader, 1); | 454 consume_dumps(uploader, 1); |
| 509 } | 455 } |
| 510 | 456 |
| 511 TEST_F(SynchronizedMinidumpManagerTest, HasDumpsWithoutDumps) { | 457 TEST_F(SynchronizedMinidumpManagerTest, HasDumpsWithoutDumps) { |
| 512 FakeSynchronizedMinidumpUploader uploader; | 458 FakeSynchronizedMinidumpUploader uploader; |
| 513 ASSERT_FALSE(uploader.HasDumps()); | 459 ASSERT_FALSE(uploader.HasDumps()); |
| 514 } | 460 } |
| 515 | 461 |
| 516 TEST_F(SynchronizedMinidumpManagerTest, HasDumpsWithDumps) { | 462 TEST_F(SynchronizedMinidumpManagerTest, HasDumpsWithDumps) { |
| 517 // Sample parameters. | 463 // Sample parameters. |
| 518 time_t now = time(0); | 464 base::Time now = base::Time::Now(); |
| 519 MinidumpParams params; | 465 MinidumpParams params; |
| 520 params.process_name = "process"; | 466 params.process_name = "process"; |
| 521 | 467 |
| 522 SynchronizedMinidumpManagerSimple producer; | 468 SynchronizedMinidumpManagerSimple producer; |
| 523 FakeSynchronizedMinidumpUploader uploader; | 469 FakeSynchronizedMinidumpUploader uploader; |
| 524 | 470 |
| 525 producer.SetDumpInfoToWrite( | 471 producer.SetDumpInfoToWrite( |
| 526 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); | 472 base::WrapUnique(new DumpInfo("dump1", "log1", now, params))); |
| 527 | 473 |
| 528 const int kNumDumps = 3; | 474 const int kNumDumps = 3; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 547 const base::FilePath path = | 493 const base::FilePath path = |
| 548 base::FilePath(manager.dump_path()).Append("hello123"); | 494 base::FilePath(manager.dump_path()).Append("hello123"); |
| 549 const char kFileContents[] = "foobar"; | 495 const char kFileContents[] = "foobar"; |
| 550 ASSERT_EQ(static_cast<int>(sizeof(kFileContents)), | 496 ASSERT_EQ(static_cast<int>(sizeof(kFileContents)), |
| 551 WriteFile(path, kFileContents, sizeof(kFileContents))); | 497 WriteFile(path, kFileContents, sizeof(kFileContents))); |
| 552 | 498 |
| 553 ASSERT_TRUE(manager.HasDumps()); | 499 ASSERT_TRUE(manager.HasDumps()); |
| 554 } | 500 } |
| 555 | 501 |
| 556 } // namespace chromecast | 502 } // namespace chromecast |
| OLD | NEW |