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 |