| 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 22 matching lines...) Expand all Loading... |
| 33 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 33 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
| 34 | 34 |
| 35 namespace browser_watcher { | 35 namespace browser_watcher { |
| 36 | 36 |
| 37 using base::debug::ActivityData; | 37 using base::debug::ActivityData; |
| 38 using base::debug::ActivityTrackerMemoryAllocator; | 38 using base::debug::ActivityTrackerMemoryAllocator; |
| 39 using base::debug::ActivityUserData; | 39 using base::debug::ActivityUserData; |
| 40 using base::debug::GlobalActivityTracker; | 40 using base::debug::GlobalActivityTracker; |
| 41 using base::debug::ThreadActivityTracker; | 41 using base::debug::ThreadActivityTracker; |
| 42 using base::File; | 42 using base::File; |
| 43 using base::FilePath; |
| 43 using base::FilePersistentMemoryAllocator; | 44 using base::FilePersistentMemoryAllocator; |
| 44 using base::MemoryMappedFile; | 45 using base::MemoryMappedFile; |
| 45 using base::PersistentMemoryAllocator; | 46 using base::PersistentMemoryAllocator; |
| 46 using base::WrapUnique; | 47 using base::WrapUnique; |
| 47 using crashpad::CrashReportDatabase; | 48 using crashpad::CrashReportDatabase; |
| 48 using crashpad::Settings; | 49 using crashpad::Settings; |
| 49 using crashpad::UUID; | 50 using crashpad::UUID; |
| 50 using testing::_; | 51 using testing::_; |
| 51 using testing::DoAll; | 52 using testing::DoAll; |
| 52 using testing::Return; | 53 using testing::Return; |
| 53 using testing::SetArgPointee; | 54 using testing::SetArgPointee; |
| 54 | 55 |
| 55 namespace { | 56 namespace { |
| 56 | 57 |
| 58 TEST(PostmortemDeleterTest, BasicTest) { |
| 59 base::HistogramTester histogram_tester; |
| 60 base::ScopedTempDir temp_dir; |
| 61 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 62 |
| 63 // Create three files. |
| 64 FilePath path_one = temp_dir.GetPath().AppendASCII("a.pma"); |
| 65 FilePath path_two = temp_dir.GetPath().AppendASCII("b.pma"); |
| 66 FilePath path_three = temp_dir.GetPath().AppendASCII("c.pma"); |
| 67 |
| 68 std::vector<FilePath> stability_files = {path_one, path_two, path_three}; |
| 69 |
| 70 for (const FilePath& path : stability_files) { |
| 71 { |
| 72 base::ScopedFILE file(base::OpenFile(path, "w")); |
| 73 ASSERT_NE(file.get(), nullptr); |
| 74 } |
| 75 ASSERT_TRUE(base::PathExists(path)); |
| 76 } |
| 77 |
| 78 // Open one stability file to prevent its deletion. |
| 79 base::ScopedFILE file(base::OpenFile(path_two, "w")); |
| 80 ASSERT_NE(file.get(), nullptr); |
| 81 |
| 82 // Validate deletion and metrics. |
| 83 PostmortemDeleter deleter; |
| 84 deleter.Process(stability_files); |
| 85 |
| 86 ASSERT_FALSE(base::PathExists(path_one)); |
| 87 ASSERT_FALSE(base::PathExists(path_three)); |
| 88 histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 89 UNCLEAN_SHUTDOWN, 2); |
| 90 |
| 91 ASSERT_TRUE(base::PathExists(path_two)); |
| 92 histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 93 DEBUG_FILE_DELETION_FAILED, 1); |
| 94 |
| 95 std::vector<CollectionStatus> unexpected_statuses = { |
| 96 NONE, |
| 97 SUCCESS, |
| 98 ANALYZER_CREATION_FAILED, |
| 99 DEBUG_FILE_NO_DATA, |
| 100 PREPARE_NEW_CRASH_REPORT_FAILED, |
| 101 WRITE_TO_MINIDUMP_FAILED, |
| 102 FINISHED_WRITING_CRASH_REPORT_FAILED, |
| 103 COLLECTION_ATTEMPT}; |
| 104 for (CollectionStatus status : unexpected_statuses) { |
| 105 histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", status, |
| 106 0); |
| 107 } |
| 108 } |
| 109 |
| 57 const char kProductName[] = "TestProduct"; | 110 const char kProductName[] = "TestProduct"; |
| 58 const char kVersionNumber[] = "TestVersionNumber"; | 111 const char kVersionNumber[] = "TestVersionNumber"; |
| 59 const char kChannelName[] = "TestChannel"; | 112 const char kChannelName[] = "TestChannel"; |
| 60 | 113 |
| 61 // The tracker creates some data entries internally. | 114 // The tracker creates some data entries internally. |
| 62 const size_t kInternalProcessDatums = 1; | 115 const size_t kInternalProcessDatums = 1; |
| 63 | 116 |
| 64 void ContainsKeyValue( | 117 void ContainsKeyValue( |
| 65 const google::protobuf::Map<std::string, TypedValue>& data, | 118 const google::protobuf::Map<std::string, TypedValue>& data, |
| 66 const std::string& key, | 119 const std::string& key, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 MOCK_METHOD2(SkipReportUpload, | 159 MOCK_METHOD2(SkipReportUpload, |
| 107 CrashReportDatabase::OperationStatus( | 160 CrashReportDatabase::OperationStatus( |
| 108 const UUID& uuid, | 161 const UUID& uuid, |
| 109 crashpad::Metrics::CrashSkippedReason reason)); | 162 crashpad::Metrics::CrashSkippedReason reason)); |
| 110 MOCK_METHOD1(DeleteReport, | 163 MOCK_METHOD1(DeleteReport, |
| 111 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 164 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 112 MOCK_METHOD1(RequestUpload, | 165 MOCK_METHOD1(RequestUpload, |
| 113 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 166 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 114 }; | 167 }; |
| 115 | 168 |
| 116 // Used for testing CollectAndSubmitAllPendingReports. | |
| 117 class MockPostmortemReportCollector : public PostmortemReportCollector { | 169 class MockPostmortemReportCollector : public PostmortemReportCollector { |
| 118 public: | 170 public: |
| 119 MockPostmortemReportCollector() | 171 explicit MockPostmortemReportCollector(CrashReportDatabase* crash_database) |
| 120 : PostmortemReportCollector(kProductName, | 172 : PostmortemReportCollector(kProductName, |
| 121 kVersionNumber, | 173 kVersionNumber, |
| 122 kChannelName, | 174 kChannelName, |
| 175 crash_database, |
| 123 nullptr) {} | 176 nullptr) {} |
| 124 | 177 |
| 125 MOCK_METHOD3(GetDebugStateFilePaths, | |
| 126 std::vector<base::FilePath>( | |
| 127 const base::FilePath& debug_info_dir, | |
| 128 const base::FilePath::StringType& debug_file_pattern, | |
| 129 const std::set<base::FilePath>&)); | |
| 130 MOCK_METHOD2(CollectOneReport, | 178 MOCK_METHOD2(CollectOneReport, |
| 131 CollectionStatus(const base::FilePath&, | 179 CollectionStatus(const FilePath&, StabilityReport* report)); |
| 132 StabilityReport* report)); | |
| 133 MOCK_METHOD4(WriteReportToMinidump, | 180 MOCK_METHOD4(WriteReportToMinidump, |
| 134 bool(StabilityReport* report, | 181 bool(StabilityReport* report, |
| 135 const crashpad::UUID& client_id, | 182 const crashpad::UUID& client_id, |
| 136 const crashpad::UUID& report_id, | 183 const crashpad::UUID& report_id, |
| 137 base::PlatformFile minidump_file)); | 184 base::PlatformFile minidump_file)); |
| 138 }; | 185 }; |
| 139 | 186 |
| 140 class MockSystemSessionAnalyzer : public SystemSessionAnalyzer { | 187 class MockSystemSessionAnalyzer : public SystemSessionAnalyzer { |
| 141 public: | 188 public: |
| 142 MockSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {} | 189 MockSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {} |
| (...skipping 14 matching lines...) Expand all Loading... |
| 157 MATCHER_P(EqualsProto, message, "") { | 204 MATCHER_P(EqualsProto, message, "") { |
| 158 std::string expected_serialized; | 205 std::string expected_serialized; |
| 159 std::string actual_serialized; | 206 std::string actual_serialized; |
| 160 message.SerializeToString(&expected_serialized); | 207 message.SerializeToString(&expected_serialized); |
| 161 arg.SerializeToString(&actual_serialized); | 208 arg.SerializeToString(&actual_serialized); |
| 162 return expected_serialized == actual_serialized; | 209 return expected_serialized == actual_serialized; |
| 163 } | 210 } |
| 164 | 211 |
| 165 } // namespace | 212 } // namespace |
| 166 | 213 |
| 167 class PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest | 214 class PostmortemReportCollectorProcessTest : public testing::Test { |
| 168 : public testing::Test { | |
| 169 public: | 215 public: |
| 170 void SetUpTest(bool system_session_clean) { | 216 void SetUpTest(bool system_session_clean, bool expect_write_dump) { |
| 217 collector_.reset(new MockPostmortemReportCollector(&database_)); |
| 218 |
| 171 // Create a dummy debug file. | 219 // Create a dummy debug file. |
| 172 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 220 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 173 debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma"); | 221 debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma"); |
| 174 { | 222 { |
| 175 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); | 223 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); |
| 176 ASSERT_NE(file.get(), nullptr); | 224 ASSERT_NE(file.get(), nullptr); |
| 177 } | 225 } |
| 178 ASSERT_TRUE(base::PathExists(debug_file_)); | 226 ASSERT_TRUE(base::PathExists(debug_file_)); |
| 179 | 227 |
| 180 // Expect collection of the debug file paths. | |
| 181 debug_file_pattern_ = FILE_PATH_LITERAL("foo-*.pma"); | |
| 182 std::vector<base::FilePath> debug_files{debug_file_}; | |
| 183 EXPECT_CALL(collector_, | |
| 184 GetDebugStateFilePaths(debug_file_.DirName(), | |
| 185 debug_file_pattern_, no_excluded_files_)) | |
| 186 .Times(1) | |
| 187 .WillOnce(Return(debug_files)); | |
| 188 | |
| 189 EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr)); | 228 EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr)); |
| 190 | 229 |
| 191 // Expect a single collection call. | 230 // Expect a single collection call. |
| 192 StabilityReport report; | 231 StabilityReport report; |
| 193 report.mutable_system_state()->set_session_state( | 232 report.mutable_system_state()->set_session_state( |
| 194 system_session_clean ? SystemState::CLEAN : SystemState::UNCLEAN); | 233 system_session_clean ? SystemState::CLEAN : SystemState::UNCLEAN); |
| 195 EXPECT_CALL(collector_, CollectOneReport(debug_file_, _)) | 234 EXPECT_CALL(*collector_, CollectOneReport(debug_file_, _)) |
| 196 .Times(1) | 235 .Times(1) |
| 197 .WillOnce(DoAll(SetArgPointee<1>(report), Return(SUCCESS))); | 236 .WillOnce(DoAll(SetArgPointee<1>(report), Return(SUCCESS))); |
| 198 | 237 |
| 238 if (!expect_write_dump) |
| 239 return; |
| 240 |
| 199 // Expect the call to write the proto to a minidump. This involves | 241 // Expect the call to write the proto to a minidump. This involves |
| 200 // requesting a report from the crashpad database, writing the report, then | 242 // requesting a report from the crashpad database, writing the report, then |
| 201 // finalizing it with the database. | 243 // finalizing it with the database. |
| 202 base::FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); | 244 FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); |
| 203 base::File minidump_file( | 245 base::File minidump_file( |
| 204 minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE); | 246 minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE); |
| 205 crashpad::UUID new_report_uuid; | 247 crashpad::UUID new_report_uuid; |
| 206 new_report_uuid.InitializeWithNew(); | 248 new_report_uuid.InitializeWithNew(); |
| 207 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, | 249 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, |
| 208 minidump_path}; | 250 minidump_path}; |
| 209 EXPECT_CALL(database_, PrepareNewCrashReport(_)) | 251 EXPECT_CALL(database_, PrepareNewCrashReport(_)) |
| 210 .Times(1) | 252 .Times(1) |
| 211 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), | 253 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), |
| 212 Return(CrashReportDatabase::kNoError))); | 254 Return(CrashReportDatabase::kNoError))); |
| 213 | 255 |
| 214 EXPECT_CALL(collector_, | 256 EXPECT_CALL(*collector_, |
| 215 WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile())) | 257 WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile())) |
| 216 .Times(1) | 258 .Times(1) |
| 217 .WillOnce(Return(true)); | 259 .WillOnce(Return(true)); |
| 218 } | 260 } |
| 219 void ValidateHistograms(int unclean_cnt, int unclean_system_cnt) { | 261 void ValidateHistograms(int unclean_cnt, int unclean_system_cnt) { |
| 220 histogram_tester_.ExpectTotalCount( | 262 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 221 "ActivityTracker.Collect.StabilityFileCount", 1); | 263 UNCLEAN_SHUTDOWN, unclean_cnt); |
| 222 histogram_tester_.ExpectBucketCount( | 264 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 223 "ActivityTracker.Collect.StabilityFileCount", 1, 1); | 265 UNCLEAN_SESSION, unclean_system_cnt); |
| 224 histogram_tester_.ExpectTotalCount( | |
| 225 "ActivityTracker.Collect.UncleanShutdownCount", 1); | |
| 226 histogram_tester_.ExpectBucketCount( | |
| 227 "ActivityTracker.Collect.UncleanShutdownCount", unclean_cnt, 1); | |
| 228 histogram_tester_.ExpectTotalCount( | |
| 229 "ActivityTracker.Collect.UncleanSystemCount", 1); | |
| 230 histogram_tester_.ExpectBucketCount( | |
| 231 "ActivityTracker.Collect.UncleanSystemCount", unclean_system_cnt, 1); | |
| 232 } | 266 } |
| 233 void CollectReports(bool is_session_clean) { | 267 void CollectReports(bool is_session_clean) { |
| 234 SetUpTest(is_session_clean); | 268 SetUpTest(is_session_clean, true); |
| 235 | 269 |
| 236 EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _)) | 270 EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _)) |
| 237 .Times(1) | 271 .Times(1) |
| 238 .WillOnce(Return(CrashReportDatabase::kNoError)); | 272 .WillOnce(Return(CrashReportDatabase::kNoError)); |
| 239 | 273 |
| 240 // Run the test. | 274 // Run the test. |
| 241 int success_cnt = collector_.CollectAndSubmitAllPendingReports( | 275 std::vector<FilePath> debug_files{debug_file_}; |
| 242 debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, | 276 collector_->Process(debug_files); |
| 243 &database_); | |
| 244 ASSERT_EQ(1, success_cnt); | |
| 245 ASSERT_FALSE(base::PathExists(debug_file_)); | 277 ASSERT_FALSE(base::PathExists(debug_file_)); |
| 246 } | 278 } |
| 247 | 279 |
| 248 protected: | 280 protected: |
| 249 base::HistogramTester histogram_tester_; | 281 base::HistogramTester histogram_tester_; |
| 250 base::ScopedTempDir temp_dir_; | 282 base::ScopedTempDir temp_dir_; |
| 251 base::FilePath debug_file_; | 283 FilePath debug_file_; |
| 252 MockCrashReportDatabase database_; | 284 MockCrashReportDatabase database_; |
| 253 MockPostmortemReportCollector collector_; | 285 std::unique_ptr<MockPostmortemReportCollector> collector_; |
| 254 base::FilePath::StringType debug_file_pattern_; | |
| 255 std::set<base::FilePath> no_excluded_files_; | |
| 256 CrashReportDatabase::NewReport crashpad_report_; | 286 CrashReportDatabase::NewReport crashpad_report_; |
| 257 }; | 287 }; |
| 258 | 288 |
| 259 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 289 TEST_F(PostmortemReportCollectorProcessTest, ProcessCleanSession) { |
| 260 CollectAndSubmitAllPendingReportsCleanSession) { | |
| 261 CollectReports(true); | 290 CollectReports(true); |
| 262 int expected_unclean = 1; | 291 int expected_unclean = 1; |
| 263 int expected_system_unclean = 0; | 292 int expected_system_unclean = 0; |
| 264 ValidateHistograms(expected_unclean, expected_system_unclean); | 293 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 265 } | 294 } |
| 266 | 295 |
| 267 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 296 TEST_F(PostmortemReportCollectorProcessTest, ProcessUncleanSession) { |
| 268 CollectAndSubmitAllPendingReportsUncleanSession) { | |
| 269 CollectReports(false); | 297 CollectReports(false); |
| 270 int expected_unclean = 1; | 298 int expected_unclean = 1; |
| 271 int expected_system_unclean = 1; | 299 int expected_system_unclean = 1; |
| 272 ValidateHistograms(expected_unclean, expected_system_unclean); | 300 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 273 } | 301 } |
| 274 | 302 |
| 275 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 303 TEST_F(PostmortemReportCollectorProcessTest, ProcessStuckFile) { |
| 276 CollectAndSubmitAllPendingReportsStuckFile) { | 304 bool system_session_clean = true; |
| 277 SetUpTest(true); | 305 bool expect_write_dump = false; |
| 306 SetUpTest(system_session_clean, expect_write_dump); |
| 278 | 307 |
| 279 // Open the stability debug file to prevent its deletion. | 308 // Open the stability debug file to prevent its deletion. |
| 280 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); | 309 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); |
| 281 ASSERT_NE(file.get(), nullptr); | 310 ASSERT_NE(file.get(), nullptr); |
| 282 | 311 |
| 283 // Expect Crashpad is notified of an error writing the crash report. | |
| 284 EXPECT_CALL(database_, ErrorWritingCrashReport(&crashpad_report_)) | |
| 285 .Times(1) | |
| 286 .WillOnce(Return(CrashReportDatabase::kNoError)); | |
| 287 | |
| 288 // Run the test. | 312 // Run the test. |
| 289 int success_cnt = collector_.CollectAndSubmitAllPendingReports( | 313 std::vector<FilePath> debug_files{debug_file_}; |
| 290 debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, | 314 collector_->Process(debug_files); |
| 291 &database_); | |
| 292 ASSERT_EQ(0, success_cnt); | |
| 293 ASSERT_TRUE(base::PathExists(debug_file_)); | 315 ASSERT_TRUE(base::PathExists(debug_file_)); |
| 294 | 316 |
| 317 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 318 DEBUG_FILE_DELETION_FAILED, 1); |
| 295 int expected_unclean = 0; | 319 int expected_unclean = 0; |
| 296 int expected_system_unclean = 0; | 320 int expected_system_unclean = 0; |
| 297 ValidateHistograms(expected_unclean, expected_system_unclean); | 321 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 298 } | 322 } |
| 299 | 323 |
| 300 TEST(PostmortemReportCollectorTest, GetDebugStateFilePaths) { | |
| 301 base::ScopedTempDir temp_dir; | |
| 302 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 303 | |
| 304 // Create files. | |
| 305 std::vector<base::FilePath> expected_paths; | |
| 306 std::set<base::FilePath> excluded_paths; | |
| 307 { | |
| 308 // Matches the pattern. | |
| 309 base::FilePath path = temp_dir.GetPath().AppendASCII("foo1.pma"); | |
| 310 base::ScopedFILE file(base::OpenFile(path, "w")); | |
| 311 ASSERT_NE(file.get(), nullptr); | |
| 312 expected_paths.push_back(path); | |
| 313 | |
| 314 // Matches the pattern, but is excluded. | |
| 315 path = temp_dir.GetPath().AppendASCII("foo2.pma"); | |
| 316 file.reset(base::OpenFile(path, "w")); | |
| 317 ASSERT_NE(file.get(), nullptr); | |
| 318 ASSERT_TRUE(excluded_paths.insert(path).second); | |
| 319 | |
| 320 // Matches the pattern. | |
| 321 path = temp_dir.GetPath().AppendASCII("foo3.pma"); | |
| 322 file.reset(base::OpenFile(path, "w")); | |
| 323 ASSERT_NE(file.get(), nullptr); | |
| 324 expected_paths.push_back(path); | |
| 325 | |
| 326 // Does not match the pattern. | |
| 327 path = temp_dir.GetPath().AppendASCII("bar.baz"); | |
| 328 file.reset(base::OpenFile(path, "w")); | |
| 329 ASSERT_NE(file.get(), nullptr); | |
| 330 } | |
| 331 | |
| 332 PostmortemReportCollector collector(kProductName, kVersionNumber, | |
| 333 kChannelName, nullptr); | |
| 334 EXPECT_THAT( | |
| 335 collector.GetDebugStateFilePaths( | |
| 336 temp_dir.GetPath(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), | |
| 337 testing::UnorderedElementsAreArray(expected_paths)); | |
| 338 } | |
| 339 | |
| 340 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { | 324 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { |
| 341 // Create an empty file. | 325 // Create an empty file. |
| 342 base::ScopedTempDir temp_dir; | 326 base::ScopedTempDir temp_dir; |
| 343 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 327 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 344 base::FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); | 328 FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); |
| 345 { | 329 { |
| 346 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 330 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 347 ASSERT_NE(file.get(), nullptr); | 331 ASSERT_NE(file.get(), nullptr); |
| 348 } | 332 } |
| 349 ASSERT_TRUE(PathExists(file_path)); | 333 ASSERT_TRUE(PathExists(file_path)); |
| 350 | 334 |
| 351 // Validate collection: an empty file cannot suppport an analyzer. | 335 // Validate collection: an empty file cannot suppport an analyzer. |
| 336 MockCrashReportDatabase crash_db; |
| 352 PostmortemReportCollector collector(kProductName, kVersionNumber, | 337 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 353 kChannelName, nullptr); | 338 kChannelName, &crash_db, nullptr); |
| 354 StabilityReport report; | 339 StabilityReport report; |
| 355 ASSERT_EQ(ANALYZER_CREATION_FAILED, | 340 ASSERT_EQ(ANALYZER_CREATION_FAILED, |
| 356 collector.CollectOneReport(file_path, &report)); | 341 collector.CollectOneReport(file_path, &report)); |
| 357 } | 342 } |
| 358 | 343 |
| 359 TEST(PostmortemReportCollectorTest, CollectRandomFile) { | 344 TEST(PostmortemReportCollectorTest, CollectRandomFile) { |
| 360 // Create a file with content we don't expect to be valid for a debug file. | 345 // Create a file with content we don't expect to be valid for a debug file. |
| 361 base::ScopedTempDir temp_dir; | 346 base::ScopedTempDir temp_dir; |
| 362 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 347 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 363 base::FilePath file_path = | 348 FilePath file_path = temp_dir.GetPath().AppendASCII("invalid_content.pma"); |
| 364 temp_dir.GetPath().AppendASCII("invalid_content.pma"); | |
| 365 { | 349 { |
| 366 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 350 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 367 ASSERT_NE(file.get(), nullptr); | 351 ASSERT_NE(file.get(), nullptr); |
| 368 // Assuming this size is greater than the minimum size of a debug file. | 352 // Assuming this size is greater than the minimum size of a debug file. |
| 369 std::vector<uint8_t> data(1024); | 353 std::vector<uint8_t> data(1024); |
| 370 for (size_t i = 0; i < data.size(); ++i) | 354 for (size_t i = 0; i < data.size(); ++i) |
| 371 data[i] = i % UINT8_MAX; | 355 data[i] = i % UINT8_MAX; |
| 372 ASSERT_EQ(data.size(), | 356 ASSERT_EQ(data.size(), |
| 373 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); | 357 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); |
| 374 } | 358 } |
| 375 ASSERT_TRUE(PathExists(file_path)); | 359 ASSERT_TRUE(PathExists(file_path)); |
| 376 | 360 |
| 377 // Validate collection: random content appears as though there is not | 361 // Validate collection: random content appears as though there is not |
| 378 // stability data. | 362 // stability data. |
| 363 MockCrashReportDatabase crash_db; |
| 379 PostmortemReportCollector collector(kProductName, kVersionNumber, | 364 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 380 kChannelName, nullptr); | 365 kChannelName, &crash_db, nullptr); |
| 381 StabilityReport report; | 366 StabilityReport report; |
| 382 ASSERT_NE(SUCCESS, collector.CollectOneReport(file_path, &report)); | 367 ASSERT_NE(SUCCESS, collector.CollectOneReport(file_path, &report)); |
| 383 } | 368 } |
| 384 | 369 |
| 385 namespace { | 370 namespace { |
| 386 | 371 |
| 387 // Parameters for the activity tracking. | 372 // Parameters for the activity tracking. |
| 388 const size_t kFileSize = 64 << 10; // 64 KiB | 373 const size_t kFileSize = 64 << 10; // 64 KiB |
| 389 const int kStackDepth = 6; | 374 const int kStackDepth = 6; |
| 390 const uint64_t kAllocatorId = 0; | 375 const uint64_t kAllocatorId = 0; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 PersistentMemoryAllocator::kSizeAny); | 444 PersistentMemoryAllocator::kSizeAny); |
| 460 if (mem_base == nullptr) | 445 if (mem_base == nullptr) |
| 461 return nullptr; | 446 return nullptr; |
| 462 | 447 |
| 463 // Make the allocation iterable so it can be found by other processes. | 448 // Make the allocation iterable so it can be found by other processes. |
| 464 allocator->MakeIterable(mem_reference); | 449 allocator->MakeIterable(mem_reference); |
| 465 | 450 |
| 466 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); | 451 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); |
| 467 } | 452 } |
| 468 | 453 |
| 469 const base::FilePath& debug_file_path() const { return debug_file_path_; } | 454 const FilePath& debug_file_path() const { return debug_file_path_; } |
| 470 | 455 |
| 471 protected: | 456 protected: |
| 472 base::ScopedTempDir temp_dir_; | 457 base::ScopedTempDir temp_dir_; |
| 473 base::FilePath debug_file_path_; | 458 FilePath debug_file_path_; |
| 474 | 459 |
| 475 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 460 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 476 std::unique_ptr<ThreadActivityTracker> tracker_; | 461 std::unique_ptr<ThreadActivityTracker> tracker_; |
| 477 }; | 462 }; |
| 478 | 463 |
| 479 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 464 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
| 480 // Create some activity data. | 465 // Create some activity data. |
| 481 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), | 466 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), |
| 482 base::debug::Activity::ACT_TASK_RUN, | 467 base::debug::Activity::ACT_TASK_RUN, |
| 483 ActivityData::ForTask(kTaskSequenceNum)); | 468 ActivityData::ForTask(kTaskSequenceNum)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 499 | 484 |
| 500 // Add some user data. | 485 // Add some user data. |
| 501 ActivityTrackerMemoryAllocator user_data_allocator( | 486 ActivityTrackerMemoryAllocator user_data_allocator( |
| 502 allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord, | 487 allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord, |
| 503 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); | 488 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
| 504 std::unique_ptr<ActivityUserData> user_data = | 489 std::unique_ptr<ActivityUserData> user_data = |
| 505 tracker_->GetUserData(activity_id, &user_data_allocator); | 490 tracker_->GetUserData(activity_id, &user_data_allocator); |
| 506 user_data->SetInt("some_int", 42); | 491 user_data->SetInt("some_int", 42); |
| 507 | 492 |
| 508 // Validate collection returns the expected report. | 493 // Validate collection returns the expected report. |
| 494 MockCrashReportDatabase crash_db; |
| 509 PostmortemReportCollector collector(kProductName, kVersionNumber, | 495 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 510 kChannelName, nullptr); | 496 kChannelName, &crash_db, nullptr); |
| 511 StabilityReport report; | 497 StabilityReport report; |
| 512 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 498 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 513 | 499 |
| 514 // Validate the report. | 500 // Validate the report. |
| 515 ASSERT_EQ(1, report.process_states_size()); | 501 ASSERT_EQ(1, report.process_states_size()); |
| 516 const ProcessState& process_state = report.process_states(0); | 502 const ProcessState& process_state = report.process_states(0); |
| 517 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | 503 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); |
| 518 ASSERT_EQ(1, process_state.threads_size()); | 504 ASSERT_EQ(1, process_state.threads_size()); |
| 519 | 505 |
| 520 const ThreadState& thread_state = process_state.threads(0); | 506 const ThreadState& thread_state = process_state.threads(0); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 } | 573 } |
| 588 | 574 |
| 589 void SetUp() override { | 575 void SetUp() override { |
| 590 testing::Test::SetUp(); | 576 testing::Test::SetUp(); |
| 591 | 577 |
| 592 // Set up a debug file path. | 578 // Set up a debug file path. |
| 593 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 579 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 594 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); | 580 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); |
| 595 } | 581 } |
| 596 | 582 |
| 597 const base::FilePath& debug_file_path() { return debug_file_path_; } | 583 const FilePath& debug_file_path() { return debug_file_path_; } |
| 598 | 584 |
| 599 protected: | 585 protected: |
| 600 base::ScopedTempDir temp_dir_; | 586 base::ScopedTempDir temp_dir_; |
| 601 base::FilePath debug_file_path_; | 587 FilePath debug_file_path_; |
| 602 }; | 588 }; |
| 603 | 589 |
| 604 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, | 590 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| 605 LogCollection) { | 591 LogCollection) { |
| 606 // Record some log messages. | 592 // Record some log messages. |
| 607 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, | 593 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 608 "", 3); | 594 "", 3); |
| 609 GlobalActivityTracker::Get()->RecordLogMessage("hello world"); | 595 GlobalActivityTracker::Get()->RecordLogMessage("hello world"); |
| 610 GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); | 596 GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); |
| 611 | 597 |
| 612 // Collect the stability report. | 598 // Collect the stability report. |
| 599 MockCrashReportDatabase crash_db; |
| 613 PostmortemReportCollector collector(kProductName, kVersionNumber, | 600 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 614 kChannelName, nullptr); | 601 kChannelName, &crash_db, nullptr); |
| 615 StabilityReport report; | 602 StabilityReport report; |
| 616 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 603 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 617 | 604 |
| 618 // Validate the report's log content. | 605 // Validate the report's log content. |
| 619 ASSERT_EQ(2, report.log_messages_size()); | 606 ASSERT_EQ(2, report.log_messages_size()); |
| 620 ASSERT_EQ("hello world", report.log_messages(0)); | 607 ASSERT_EQ("hello world", report.log_messages(0)); |
| 621 ASSERT_EQ("foo bar", report.log_messages(1)); | 608 ASSERT_EQ("foo bar", report.log_messages(1)); |
| 622 } | 609 } |
| 623 | 610 |
| 624 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, | 611 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 636 process_data.Set("raw", "foo", 3); | 623 process_data.Set("raw", "foo", 3); |
| 637 process_data.SetString("string", "bar"); | 624 process_data.SetString("string", "bar"); |
| 638 process_data.SetChar("char", '9'); | 625 process_data.SetChar("char", '9'); |
| 639 process_data.SetInt("int", -9999); | 626 process_data.SetInt("int", -9999); |
| 640 process_data.SetUint("uint", 9999); | 627 process_data.SetUint("uint", 9999); |
| 641 process_data.SetBool("bool", true); | 628 process_data.SetBool("bool", true); |
| 642 process_data.SetReference("ref", string1, strlen(string1)); | 629 process_data.SetReference("ref", string1, strlen(string1)); |
| 643 process_data.SetStringReference("sref", string2); | 630 process_data.SetStringReference("sref", string2); |
| 644 | 631 |
| 645 // Collect the stability report. | 632 // Collect the stability report. |
| 633 MockCrashReportDatabase crash_db; |
| 646 PostmortemReportCollector collector(kProductName, kVersionNumber, | 634 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 647 kChannelName, nullptr); | 635 kChannelName, &crash_db, nullptr); |
| 648 StabilityReport report; | 636 StabilityReport report; |
| 649 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 637 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 650 | 638 |
| 651 // Validate the report's user data. | 639 // Validate the report's user data. |
| 652 const auto& collected_data = report.global_data(); | 640 const auto& collected_data = report.global_data(); |
| 653 ASSERT_EQ(kInternalProcessDatums + 12U, collected_data.size()); | 641 ASSERT_EQ(kInternalProcessDatums + 12U, collected_data.size()); |
| 654 | 642 |
| 655 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); | 643 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); |
| 656 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); | 644 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); |
| 657 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); | 645 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 FieldTrialCollection) { | 693 FieldTrialCollection) { |
| 706 // Record some data. | 694 // Record some data. |
| 707 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, | 695 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 708 "", 3); | 696 "", 3); |
| 709 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); | 697 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); |
| 710 process_data.SetString("string", "bar"); | 698 process_data.SetString("string", "bar"); |
| 711 process_data.SetString("FieldTrial.string", "bar"); | 699 process_data.SetString("FieldTrial.string", "bar"); |
| 712 process_data.SetString("FieldTrial.foo", "bar"); | 700 process_data.SetString("FieldTrial.foo", "bar"); |
| 713 | 701 |
| 714 // Collect the stability report. | 702 // Collect the stability report. |
| 703 MockCrashReportDatabase crash_db; |
| 715 PostmortemReportCollector collector(kProductName, kVersionNumber, | 704 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 716 kChannelName, nullptr); | 705 kChannelName, &crash_db, nullptr); |
| 717 StabilityReport report; | 706 StabilityReport report; |
| 718 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 707 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 719 | 708 |
| 720 // Validate the report's experiment and global data. | 709 // Validate the report's experiment and global data. |
| 721 ASSERT_EQ(2, report.field_trials_size()); | 710 ASSERT_EQ(2, report.field_trials_size()); |
| 722 EXPECT_NE(0U, report.field_trials(0).name_id()); | 711 EXPECT_NE(0U, report.field_trials(0).name_id()); |
| 723 EXPECT_NE(0U, report.field_trials(0).group_id()); | 712 EXPECT_NE(0U, report.field_trials(0).group_id()); |
| 724 EXPECT_NE(0U, report.field_trials(1).name_id()); | 713 EXPECT_NE(0U, report.field_trials(1).name_id()); |
| 725 EXPECT_EQ(report.field_trials(0).group_id(), | 714 EXPECT_EQ(report.field_trials(0).group_id(), |
| 726 report.field_trials(1).group_id()); | 715 report.field_trials(1).group_id()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 746 module_info.age = 1; | 735 module_info.age = 1; |
| 747 crashpad::UUID debug_uuid; | 736 crashpad::UUID debug_uuid; |
| 748 debug_uuid.InitializeFromString("11223344-5566-7788-abcd-0123456789ab"); | 737 debug_uuid.InitializeFromString("11223344-5566-7788-abcd-0123456789ab"); |
| 749 memcpy(module_info.identifier, &debug_uuid, sizeof(module_info.identifier)); | 738 memcpy(module_info.identifier, &debug_uuid, sizeof(module_info.identifier)); |
| 750 module_info.file = "foo"; | 739 module_info.file = "foo"; |
| 751 module_info.debug_file = "bar"; | 740 module_info.debug_file = "bar"; |
| 752 | 741 |
| 753 GlobalActivityTracker::Get()->RecordModuleInfo(module_info); | 742 GlobalActivityTracker::Get()->RecordModuleInfo(module_info); |
| 754 | 743 |
| 755 // Collect the stability report. | 744 // Collect the stability report. |
| 745 MockCrashReportDatabase crash_db; |
| 756 PostmortemReportCollector collector(kProductName, kVersionNumber, | 746 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 757 kChannelName, nullptr); | 747 kChannelName, &crash_db, nullptr); |
| 758 StabilityReport report; | 748 StabilityReport report; |
| 759 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 749 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 760 | 750 |
| 761 // Validate the report's modules content. | 751 // Validate the report's modules content. |
| 762 ASSERT_EQ(1, report.process_states_size()); | 752 ASSERT_EQ(1, report.process_states_size()); |
| 763 const ProcessState& process_state = report.process_states(0); | 753 const ProcessState& process_state = report.process_states(0); |
| 764 ASSERT_EQ(1, process_state.modules_size()); | 754 ASSERT_EQ(1, process_state.modules_size()); |
| 765 | 755 |
| 766 const CodeModule collected_module = process_state.modules(0); | 756 const CodeModule collected_module = process_state.modules(0); |
| 767 EXPECT_EQ(module_info.address, | 757 EXPECT_EQ(module_info.address, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 784 "", 3); | 774 "", 3); |
| 785 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); | 775 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); |
| 786 process_data.SetInt(kStabilityStartTimestamp, 12345LL); | 776 process_data.SetInt(kStabilityStartTimestamp, 12345LL); |
| 787 | 777 |
| 788 // Collect. | 778 // Collect. |
| 789 MockSystemSessionAnalyzer analyzer; | 779 MockSystemSessionAnalyzer analyzer; |
| 790 EXPECT_CALL(analyzer, | 780 EXPECT_CALL(analyzer, |
| 791 IsSessionUnclean(base::Time::FromInternalValue(12345LL))) | 781 IsSessionUnclean(base::Time::FromInternalValue(12345LL))) |
| 792 .Times(1) | 782 .Times(1) |
| 793 .WillOnce(Return(SystemSessionAnalyzer::CLEAN)); | 783 .WillOnce(Return(SystemSessionAnalyzer::CLEAN)); |
| 784 MockCrashReportDatabase crash_db; |
| 794 PostmortemReportCollector collector(kProductName, kVersionNumber, | 785 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 795 kChannelName, &analyzer); | 786 kChannelName, &crash_db, &analyzer); |
| 796 StabilityReport report; | 787 StabilityReport report; |
| 797 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 788 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 798 | 789 |
| 799 // Validate the report. | 790 // Validate the report. |
| 800 ASSERT_EQ(SystemState::CLEAN, report.system_state().session_state()); | 791 ASSERT_EQ(SystemState::CLEAN, report.system_state().session_state()); |
| 801 } | 792 } |
| 802 | 793 |
| 803 } // namespace browser_watcher | 794 } // namespace browser_watcher |
| OLD | NEW |