| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/browser_watcher/postmortem_report_collector.h" | 5 #include "components/browser_watcher/postmortem_report_collector.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <set> | 10 #include <set> |
| 11 #include <string> | 11 #include <string> |
| 12 #include <utility> | 12 #include <utility> |
| 13 #include <vector> | 13 #include <vector> |
| 14 | 14 |
| 15 #include "base/bind.h" |
| 15 #include "base/debug/activity_tracker.h" | 16 #include "base/debug/activity_tracker.h" |
| 16 #include "base/files/file.h" | 17 #include "base/files/file.h" |
| 17 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
| 18 #include "base/files/file_util.h" | 19 #include "base/files/file_util.h" |
| 19 #include "base/files/memory_mapped_file.h" | 20 #include "base/files/memory_mapped_file.h" |
| 20 #include "base/files/scoped_file.h" | 21 #include "base/files/scoped_file.h" |
| 21 #include "base/files/scoped_temp_dir.h" | 22 #include "base/files/scoped_temp_dir.h" |
| 22 #include "base/memory/ptr_util.h" | 23 #include "base/memory/ptr_util.h" |
| 23 #include "base/metrics/persistent_memory_allocator.h" | 24 #include "base/metrics/persistent_memory_allocator.h" |
| 24 #include "base/threading/platform_thread.h" | 25 #include "base/threading/platform_thread.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 MOCK_METHOD2(SkipReportUpload, | 82 MOCK_METHOD2(SkipReportUpload, |
| 82 CrashReportDatabase::OperationStatus( | 83 CrashReportDatabase::OperationStatus( |
| 83 const UUID& uuid, | 84 const UUID& uuid, |
| 84 crashpad::Metrics::CrashSkippedReason reason)); | 85 crashpad::Metrics::CrashSkippedReason reason)); |
| 85 MOCK_METHOD1(DeleteReport, | 86 MOCK_METHOD1(DeleteReport, |
| 86 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 87 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 87 MOCK_METHOD1(RequestUpload, | 88 MOCK_METHOD1(RequestUpload, |
| 88 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 89 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 89 }; | 90 }; |
| 90 | 91 |
| 92 void GetExecutableDetails(base::string16* product_name, |
| 93 base::string16* version_number, |
| 94 base::string16* channel_name) { |
| 95 DCHECK_NE(nullptr, product_name); |
| 96 DCHECK_NE(nullptr, version_number); |
| 97 DCHECK_NE(nullptr, channel_name); |
| 98 |
| 99 *product_name = L"TestProduct"; |
| 100 *version_number = L"TestVersionNumber"; |
| 101 *channel_name = L"TestChannel"; |
| 102 } |
| 103 |
| 91 // Used for testing CollectAndSubmitForUpload. | 104 // Used for testing CollectAndSubmitForUpload. |
| 92 class MockPostmortemReportCollector : public PostmortemReportCollector { | 105 class MockPostmortemReportCollector : public PostmortemReportCollector { |
| 93 public: | 106 public: |
| 94 MockPostmortemReportCollector() {} | 107 MockPostmortemReportCollector() |
| 108 : PostmortemReportCollector(base::Bind(&GetExecutableDetails)) {} |
| 95 | 109 |
| 96 // A function that returns a unique_ptr cannot be mocked, so mock a function | 110 // A function that returns a unique_ptr cannot be mocked, so mock a function |
| 97 // that returns a raw pointer instead. | 111 // that returns a raw pointer instead. |
| 98 CollectionStatus Collect(const base::FilePath& debug_state_file, | 112 CollectionStatus Collect(const base::FilePath& debug_state_file, |
| 99 std::unique_ptr<StabilityReport>* report) override { | 113 std::unique_ptr<StabilityReport>* report) override { |
| 100 DCHECK_NE(nullptr, report); | 114 DCHECK_NE(nullptr, report); |
| 101 report->reset(CollectRaw(debug_state_file)); | 115 report->reset(CollectRaw(debug_state_file)); |
| 102 return SUCCESS; | 116 return SUCCESS; |
| 103 } | 117 } |
| 104 | 118 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 file.reset(base::OpenFile(path, "w")); | 270 file.reset(base::OpenFile(path, "w")); |
| 257 ASSERT_NE(file.get(), nullptr); | 271 ASSERT_NE(file.get(), nullptr); |
| 258 expected_paths.push_back(path); | 272 expected_paths.push_back(path); |
| 259 | 273 |
| 260 // Does not match the pattern. | 274 // Does not match the pattern. |
| 261 path = temp_dir.path().AppendASCII("bar.baz"); | 275 path = temp_dir.path().AppendASCII("bar.baz"); |
| 262 file.reset(base::OpenFile(path, "w")); | 276 file.reset(base::OpenFile(path, "w")); |
| 263 ASSERT_NE(file.get(), nullptr); | 277 ASSERT_NE(file.get(), nullptr); |
| 264 } | 278 } |
| 265 | 279 |
| 266 PostmortemReportCollector collector; | 280 PostmortemReportCollector collector(base::Bind(&GetExecutableDetails)); |
| 267 EXPECT_THAT( | 281 EXPECT_THAT( |
| 268 collector.GetDebugStateFilePaths( | 282 collector.GetDebugStateFilePaths( |
| 269 temp_dir.path(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), | 283 temp_dir.path(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), |
| 270 testing::UnorderedElementsAreArray(expected_paths)); | 284 testing::UnorderedElementsAreArray(expected_paths)); |
| 271 } | 285 } |
| 272 | 286 |
| 273 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { | 287 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { |
| 274 // Create an empty file. | 288 // Create an empty file. |
| 275 base::ScopedTempDir temp_dir; | 289 base::ScopedTempDir temp_dir; |
| 276 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 290 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 277 base::FilePath file_path = temp_dir.path().AppendASCII("empty.pma"); | 291 base::FilePath file_path = temp_dir.path().AppendASCII("empty.pma"); |
| 278 { | 292 { |
| 279 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 293 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 280 ASSERT_NE(file.get(), nullptr); | 294 ASSERT_NE(file.get(), nullptr); |
| 281 } | 295 } |
| 282 ASSERT_TRUE(PathExists(file_path)); | 296 ASSERT_TRUE(PathExists(file_path)); |
| 283 | 297 |
| 284 // Validate collection: an empty file cannot suppport an analyzer. | 298 // Validate collection: an empty file cannot suppport an analyzer. |
| 285 PostmortemReportCollector collector; | 299 PostmortemReportCollector collector(base::Bind(&GetExecutableDetails)); |
| 286 std::unique_ptr<StabilityReport> report; | 300 std::unique_ptr<StabilityReport> report; |
| 287 ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED, | 301 ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED, |
| 288 collector.Collect(file_path, &report)); | 302 collector.Collect(file_path, &report)); |
| 289 } | 303 } |
| 290 | 304 |
| 291 TEST(PostmortemReportCollectorTest, CollectRandomFile) { | 305 TEST(PostmortemReportCollectorTest, CollectRandomFile) { |
| 292 // Create a file with content we don't expect to be valid for a debug file. | 306 // Create a file with content we don't expect to be valid for a debug file. |
| 293 base::ScopedTempDir temp_dir; | 307 base::ScopedTempDir temp_dir; |
| 294 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 308 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 295 base::FilePath file_path = temp_dir.path().AppendASCII("invalid_content.pma"); | 309 base::FilePath file_path = temp_dir.path().AppendASCII("invalid_content.pma"); |
| 296 { | 310 { |
| 297 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 311 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 298 ASSERT_NE(file.get(), nullptr); | 312 ASSERT_NE(file.get(), nullptr); |
| 299 // Assuming this size is greater than the minimum size of a debug file. | 313 // Assuming this size is greater than the minimum size of a debug file. |
| 300 std::vector<uint8_t> data(1024); | 314 std::vector<uint8_t> data(1024); |
| 301 for (size_t i = 0; i < data.size(); ++i) | 315 for (size_t i = 0; i < data.size(); ++i) |
| 302 data[i] = i % UINT8_MAX; | 316 data[i] = i % UINT8_MAX; |
| 303 ASSERT_EQ(data.size(), | 317 ASSERT_EQ(data.size(), |
| 304 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); | 318 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); |
| 305 } | 319 } |
| 306 ASSERT_TRUE(PathExists(file_path)); | 320 ASSERT_TRUE(PathExists(file_path)); |
| 307 | 321 |
| 308 // Validate collection: random content appears as though there is not | 322 // Validate collection: random content appears as though there is not |
| 309 // stability data. | 323 // stability data. |
| 310 PostmortemReportCollector collector; | 324 PostmortemReportCollector collector(base::Bind(&GetExecutableDetails)); |
| 311 std::unique_ptr<StabilityReport> report; | 325 std::unique_ptr<StabilityReport> report; |
| 312 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, | 326 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, |
| 313 collector.Collect(file_path, &report)); | 327 collector.Collect(file_path, &report)); |
| 314 } | 328 } |
| 315 | 329 |
| 316 namespace { | 330 namespace { |
| 317 | 331 |
| 318 // Parameters for the activity tracking. | 332 // Parameters for the activity tracking. |
| 319 const size_t kFileSize = 2 * 1024; | 333 const size_t kFileSize = 2 * 1024; |
| 320 const int kStackDepth = 4; | 334 const int kStackDepth = 4; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 | 408 |
| 395 const base::FilePath& debug_file_path() const { return debug_file_path_; } | 409 const base::FilePath& debug_file_path() const { return debug_file_path_; } |
| 396 | 410 |
| 397 private: | 411 private: |
| 398 base::ScopedTempDir temp_dir_; | 412 base::ScopedTempDir temp_dir_; |
| 399 base::FilePath debug_file_path_; | 413 base::FilePath debug_file_path_; |
| 400 }; | 414 }; |
| 401 | 415 |
| 402 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 416 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
| 403 // Validate collection returns the expected report. | 417 // Validate collection returns the expected report. |
| 404 PostmortemReportCollector collector; | 418 PostmortemReportCollector collector(base::Bind(&GetExecutableDetails)); |
| 405 std::unique_ptr<StabilityReport> report; | 419 std::unique_ptr<StabilityReport> report; |
| 406 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 420 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
| 407 collector.Collect(debug_file_path(), &report)); | 421 collector.Collect(debug_file_path(), &report)); |
| 408 ASSERT_NE(nullptr, report); | 422 ASSERT_NE(nullptr, report); |
| 409 | 423 |
| 410 // Build the expected report. | 424 // Build the expected report. |
| 411 StabilityReport expected_report; | 425 StabilityReport expected_report; |
| 412 ProcessState* process_state = expected_report.add_process_states(); | 426 ProcessState* process_state = expected_report.add_process_states(); |
| 413 ThreadState* thread_state = process_state->add_threads(); | 427 ThreadState* thread_state = process_state->add_threads(); |
| 414 thread_state->set_thread_name(base::PlatformThread::GetName()); | 428 thread_state->set_thread_name(base::PlatformThread::GetName()); |
| 415 | 429 |
| 416 ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString()); | 430 ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString()); |
| 417 } | 431 } |
| 418 | 432 |
| 419 } // namespace browser_watcher | 433 } // namespace browser_watcher |
| OLD | NEW |