| 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> |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 using base::WrapUnique; | 39 using base::WrapUnique; |
| 40 using crashpad::CrashReportDatabase; | 40 using crashpad::CrashReportDatabase; |
| 41 using crashpad::Settings; | 41 using crashpad::Settings; |
| 42 using crashpad::UUID; | 42 using crashpad::UUID; |
| 43 using testing::_; | 43 using testing::_; |
| 44 using testing::Return; | 44 using testing::Return; |
| 45 using testing::SetArgPointee; | 45 using testing::SetArgPointee; |
| 46 | 46 |
| 47 namespace { | 47 namespace { |
| 48 | 48 |
| 49 const char kProductName[] = "TestProduct"; |
| 50 const char kVersionNumber[] = "TestVersionNumber"; |
| 51 const char kChannelName[] = "TestChannel"; |
| 52 |
| 49 // Exposes a public constructor in order to create a dummy database. | 53 // Exposes a public constructor in order to create a dummy database. |
| 50 class MockCrashReportDatabase : public CrashReportDatabase { | 54 class MockCrashReportDatabase : public CrashReportDatabase { |
| 51 public: | 55 public: |
| 52 MockCrashReportDatabase() {} | 56 MockCrashReportDatabase() {} |
| 53 MOCK_METHOD0(GetSettings, Settings*()); | 57 MOCK_METHOD0(GetSettings, Settings*()); |
| 54 MOCK_METHOD1(PrepareNewCrashReport, | 58 MOCK_METHOD1(PrepareNewCrashReport, |
| 55 CrashReportDatabase::CrashReportDatabase::OperationStatus( | 59 CrashReportDatabase::CrashReportDatabase::OperationStatus( |
| 56 NewReport** report)); | 60 NewReport** report)); |
| 57 MOCK_METHOD2(FinishedWritingCrashReport, | 61 MOCK_METHOD2(FinishedWritingCrashReport, |
| 58 CrashReportDatabase::CrashReportDatabase::OperationStatus( | 62 CrashReportDatabase::CrashReportDatabase::OperationStatus( |
| (...skipping 25 matching lines...) Expand all Loading... |
| 84 crashpad::Metrics::CrashSkippedReason reason)); | 88 crashpad::Metrics::CrashSkippedReason reason)); |
| 85 MOCK_METHOD1(DeleteReport, | 89 MOCK_METHOD1(DeleteReport, |
| 86 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 90 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 87 MOCK_METHOD1(RequestUpload, | 91 MOCK_METHOD1(RequestUpload, |
| 88 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 92 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 89 }; | 93 }; |
| 90 | 94 |
| 91 // Used for testing CollectAndSubmitForUpload. | 95 // Used for testing CollectAndSubmitForUpload. |
| 92 class MockPostmortemReportCollector : public PostmortemReportCollector { | 96 class MockPostmortemReportCollector : public PostmortemReportCollector { |
| 93 public: | 97 public: |
| 94 MockPostmortemReportCollector() {} | 98 MockPostmortemReportCollector() |
| 99 : PostmortemReportCollector(kProductName, kVersionNumber, kChannelName) {} |
| 95 | 100 |
| 96 // A function that returns a unique_ptr cannot be mocked, so mock a function | 101 // A function that returns a unique_ptr cannot be mocked, so mock a function |
| 97 // that returns a raw pointer instead. | 102 // that returns a raw pointer instead. |
| 98 CollectionStatus Collect(const base::FilePath& debug_state_file, | 103 CollectionStatus Collect(const base::FilePath& debug_state_file, |
| 99 std::unique_ptr<StabilityReport>* report) override { | 104 std::unique_ptr<StabilityReport>* report) override { |
| 100 DCHECK_NE(nullptr, report); | 105 DCHECK_NE(nullptr, report); |
| 101 report->reset(CollectRaw(debug_state_file)); | 106 report->reset(CollectRaw(debug_state_file)); |
| 102 return SUCCESS; | 107 return SUCCESS; |
| 103 } | 108 } |
| 104 | 109 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 file.reset(base::OpenFile(path, "w")); | 261 file.reset(base::OpenFile(path, "w")); |
| 257 ASSERT_NE(file.get(), nullptr); | 262 ASSERT_NE(file.get(), nullptr); |
| 258 expected_paths.push_back(path); | 263 expected_paths.push_back(path); |
| 259 | 264 |
| 260 // Does not match the pattern. | 265 // Does not match the pattern. |
| 261 path = temp_dir.path().AppendASCII("bar.baz"); | 266 path = temp_dir.path().AppendASCII("bar.baz"); |
| 262 file.reset(base::OpenFile(path, "w")); | 267 file.reset(base::OpenFile(path, "w")); |
| 263 ASSERT_NE(file.get(), nullptr); | 268 ASSERT_NE(file.get(), nullptr); |
| 264 } | 269 } |
| 265 | 270 |
| 266 PostmortemReportCollector collector; | 271 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 272 kChannelName); |
| 267 EXPECT_THAT( | 273 EXPECT_THAT( |
| 268 collector.GetDebugStateFilePaths( | 274 collector.GetDebugStateFilePaths( |
| 269 temp_dir.path(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), | 275 temp_dir.path(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), |
| 270 testing::UnorderedElementsAreArray(expected_paths)); | 276 testing::UnorderedElementsAreArray(expected_paths)); |
| 271 } | 277 } |
| 272 | 278 |
| 273 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { | 279 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { |
| 274 // Create an empty file. | 280 // Create an empty file. |
| 275 base::ScopedTempDir temp_dir; | 281 base::ScopedTempDir temp_dir; |
| 276 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 282 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 277 base::FilePath file_path = temp_dir.path().AppendASCII("empty.pma"); | 283 base::FilePath file_path = temp_dir.path().AppendASCII("empty.pma"); |
| 278 { | 284 { |
| 279 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 285 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 280 ASSERT_NE(file.get(), nullptr); | 286 ASSERT_NE(file.get(), nullptr); |
| 281 } | 287 } |
| 282 ASSERT_TRUE(PathExists(file_path)); | 288 ASSERT_TRUE(PathExists(file_path)); |
| 283 | 289 |
| 284 // Validate collection: an empty file cannot suppport an analyzer. | 290 // Validate collection: an empty file cannot suppport an analyzer. |
| 285 PostmortemReportCollector collector; | 291 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 292 kChannelName); |
| 286 std::unique_ptr<StabilityReport> report; | 293 std::unique_ptr<StabilityReport> report; |
| 287 ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED, | 294 ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED, |
| 288 collector.Collect(file_path, &report)); | 295 collector.Collect(file_path, &report)); |
| 289 } | 296 } |
| 290 | 297 |
| 291 TEST(PostmortemReportCollectorTest, CollectRandomFile) { | 298 TEST(PostmortemReportCollectorTest, CollectRandomFile) { |
| 292 // Create a file with content we don't expect to be valid for a debug file. | 299 // Create a file with content we don't expect to be valid for a debug file. |
| 293 base::ScopedTempDir temp_dir; | 300 base::ScopedTempDir temp_dir; |
| 294 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 301 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 295 base::FilePath file_path = temp_dir.path().AppendASCII("invalid_content.pma"); | 302 base::FilePath file_path = temp_dir.path().AppendASCII("invalid_content.pma"); |
| 296 { | 303 { |
| 297 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 304 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 298 ASSERT_NE(file.get(), nullptr); | 305 ASSERT_NE(file.get(), nullptr); |
| 299 // Assuming this size is greater than the minimum size of a debug file. | 306 // Assuming this size is greater than the minimum size of a debug file. |
| 300 std::vector<uint8_t> data(1024); | 307 std::vector<uint8_t> data(1024); |
| 301 for (size_t i = 0; i < data.size(); ++i) | 308 for (size_t i = 0; i < data.size(); ++i) |
| 302 data[i] = i % UINT8_MAX; | 309 data[i] = i % UINT8_MAX; |
| 303 ASSERT_EQ(data.size(), | 310 ASSERT_EQ(data.size(), |
| 304 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); | 311 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); |
| 305 } | 312 } |
| 306 ASSERT_TRUE(PathExists(file_path)); | 313 ASSERT_TRUE(PathExists(file_path)); |
| 307 | 314 |
| 308 // Validate collection: random content appears as though there is not | 315 // Validate collection: random content appears as though there is not |
| 309 // stability data. | 316 // stability data. |
| 310 PostmortemReportCollector collector; | 317 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 318 kChannelName); |
| 311 std::unique_ptr<StabilityReport> report; | 319 std::unique_ptr<StabilityReport> report; |
| 312 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, | 320 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, |
| 313 collector.Collect(file_path, &report)); | 321 collector.Collect(file_path, &report)); |
| 314 } | 322 } |
| 315 | 323 |
| 316 namespace { | 324 namespace { |
| 317 | 325 |
| 318 // Parameters for the activity tracking. | 326 // Parameters for the activity tracking. |
| 319 const size_t kFileSize = 2 * 1024; | 327 const size_t kFileSize = 2 * 1024; |
| 320 const int kStackDepth = 4; | 328 const int kStackDepth = 4; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 | 402 |
| 395 const base::FilePath& debug_file_path() const { return debug_file_path_; } | 403 const base::FilePath& debug_file_path() const { return debug_file_path_; } |
| 396 | 404 |
| 397 private: | 405 private: |
| 398 base::ScopedTempDir temp_dir_; | 406 base::ScopedTempDir temp_dir_; |
| 399 base::FilePath debug_file_path_; | 407 base::FilePath debug_file_path_; |
| 400 }; | 408 }; |
| 401 | 409 |
| 402 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 410 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
| 403 // Validate collection returns the expected report. | 411 // Validate collection returns the expected report. |
| 404 PostmortemReportCollector collector; | 412 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 413 kChannelName); |
| 405 std::unique_ptr<StabilityReport> report; | 414 std::unique_ptr<StabilityReport> report; |
| 406 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 415 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
| 407 collector.Collect(debug_file_path(), &report)); | 416 collector.Collect(debug_file_path(), &report)); |
| 408 ASSERT_NE(nullptr, report); | 417 ASSERT_NE(nullptr, report); |
| 409 | 418 |
| 410 // Build the expected report. | 419 // Build the expected report. |
| 411 StabilityReport expected_report; | 420 StabilityReport expected_report; |
| 412 ProcessState* process_state = expected_report.add_process_states(); | 421 ProcessState* process_state = expected_report.add_process_states(); |
| 413 ThreadState* thread_state = process_state->add_threads(); | 422 ThreadState* thread_state = process_state->add_threads(); |
| 414 thread_state->set_thread_name(base::PlatformThread::GetName()); | 423 thread_state->set_thread_name(base::PlatformThread::GetName()); |
| 415 | 424 |
| 416 ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString()); | 425 ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString()); |
| 417 } | 426 } |
| 418 | 427 |
| 419 } // namespace browser_watcher | 428 } // namespace browser_watcher |
| OLD | NEW |