Chromium Code Reviews| 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); | |
|
Sigurður Ásgeirsson
2017/06/05 15:39:39
nice. Stupid question, though - wouldn't the Postm
manzagop (departed)
2017/06/05 18:02:16
Done.
| |
| 94 } | |
| 95 | |
| 57 const char kProductName[] = "TestProduct"; | 96 const char kProductName[] = "TestProduct"; |
| 58 const char kVersionNumber[] = "TestVersionNumber"; | 97 const char kVersionNumber[] = "TestVersionNumber"; |
| 59 const char kChannelName[] = "TestChannel"; | 98 const char kChannelName[] = "TestChannel"; |
| 60 | 99 |
| 61 // The tracker creates some data entries internally. | 100 // The tracker creates some data entries internally. |
| 62 const size_t kInternalProcessDatums = 1; | 101 const size_t kInternalProcessDatums = 1; |
| 63 | 102 |
| 64 void ContainsKeyValue( | 103 void ContainsKeyValue( |
| 65 const google::protobuf::Map<std::string, TypedValue>& data, | 104 const google::protobuf::Map<std::string, TypedValue>& data, |
| 66 const std::string& key, | 105 const std::string& key, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 MOCK_METHOD2(SkipReportUpload, | 145 MOCK_METHOD2(SkipReportUpload, |
| 107 CrashReportDatabase::OperationStatus( | 146 CrashReportDatabase::OperationStatus( |
| 108 const UUID& uuid, | 147 const UUID& uuid, |
| 109 crashpad::Metrics::CrashSkippedReason reason)); | 148 crashpad::Metrics::CrashSkippedReason reason)); |
| 110 MOCK_METHOD1(DeleteReport, | 149 MOCK_METHOD1(DeleteReport, |
| 111 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 150 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 112 MOCK_METHOD1(RequestUpload, | 151 MOCK_METHOD1(RequestUpload, |
| 113 CrashReportDatabase::OperationStatus(const UUID& uuid)); | 152 CrashReportDatabase::OperationStatus(const UUID& uuid)); |
| 114 }; | 153 }; |
| 115 | 154 |
| 116 // Used for testing CollectAndSubmitAllPendingReports. | |
| 117 class MockPostmortemReportCollector : public PostmortemReportCollector { | 155 class MockPostmortemReportCollector : public PostmortemReportCollector { |
| 118 public: | 156 public: |
| 119 MockPostmortemReportCollector() | 157 explicit MockPostmortemReportCollector(CrashReportDatabase* crash_database) |
| 120 : PostmortemReportCollector(kProductName, | 158 : PostmortemReportCollector(kProductName, |
| 121 kVersionNumber, | 159 kVersionNumber, |
| 122 kChannelName, | 160 kChannelName, |
| 161 crash_database, | |
| 123 nullptr) {} | 162 nullptr) {} |
| 124 | 163 |
| 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, | 164 MOCK_METHOD2(CollectOneReport, |
| 131 CollectionStatus(const base::FilePath&, | 165 CollectionStatus(const FilePath&, StabilityReport* report)); |
| 132 StabilityReport* report)); | |
| 133 MOCK_METHOD4(WriteReportToMinidump, | 166 MOCK_METHOD4(WriteReportToMinidump, |
| 134 bool(StabilityReport* report, | 167 bool(StabilityReport* report, |
| 135 const crashpad::UUID& client_id, | 168 const crashpad::UUID& client_id, |
| 136 const crashpad::UUID& report_id, | 169 const crashpad::UUID& report_id, |
| 137 base::PlatformFile minidump_file)); | 170 base::PlatformFile minidump_file)); |
| 138 }; | 171 }; |
| 139 | 172 |
| 140 class MockSystemSessionAnalyzer : public SystemSessionAnalyzer { | 173 class MockSystemSessionAnalyzer : public SystemSessionAnalyzer { |
| 141 public: | 174 public: |
| 142 MockSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {} | 175 MockSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {} |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 157 MATCHER_P(EqualsProto, message, "") { | 190 MATCHER_P(EqualsProto, message, "") { |
| 158 std::string expected_serialized; | 191 std::string expected_serialized; |
| 159 std::string actual_serialized; | 192 std::string actual_serialized; |
| 160 message.SerializeToString(&expected_serialized); | 193 message.SerializeToString(&expected_serialized); |
| 161 arg.SerializeToString(&actual_serialized); | 194 arg.SerializeToString(&actual_serialized); |
| 162 return expected_serialized == actual_serialized; | 195 return expected_serialized == actual_serialized; |
| 163 } | 196 } |
| 164 | 197 |
| 165 } // namespace | 198 } // namespace |
| 166 | 199 |
| 167 class PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest | 200 class PostmortemReportCollectorProcessTest : public testing::Test { |
| 168 : public testing::Test { | |
| 169 public: | 201 public: |
| 170 void SetUpTest(bool system_session_clean) { | 202 void SetUpTest(bool system_session_clean, bool expect_write_dump) { |
| 203 collector_.reset(new MockPostmortemReportCollector(&database_)); | |
| 204 | |
| 171 // Create a dummy debug file. | 205 // Create a dummy debug file. |
| 172 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 206 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 173 debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma"); | 207 debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma"); |
| 174 { | 208 { |
| 175 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); | 209 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); |
| 176 ASSERT_NE(file.get(), nullptr); | 210 ASSERT_NE(file.get(), nullptr); |
| 177 } | 211 } |
| 178 ASSERT_TRUE(base::PathExists(debug_file_)); | 212 ASSERT_TRUE(base::PathExists(debug_file_)); |
| 179 | 213 |
| 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)); | 214 EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr)); |
| 190 | 215 |
| 191 // Expect a single collection call. | 216 // Expect a single collection call. |
| 192 StabilityReport report; | 217 StabilityReport report; |
| 193 report.mutable_system_state()->set_session_state( | 218 report.mutable_system_state()->set_session_state( |
| 194 system_session_clean ? SystemState::CLEAN : SystemState::UNCLEAN); | 219 system_session_clean ? SystemState::CLEAN : SystemState::UNCLEAN); |
| 195 EXPECT_CALL(collector_, CollectOneReport(debug_file_, _)) | 220 EXPECT_CALL(*collector_, CollectOneReport(debug_file_, _)) |
| 196 .Times(1) | 221 .Times(1) |
| 197 .WillOnce(DoAll(SetArgPointee<1>(report), Return(SUCCESS))); | 222 .WillOnce(DoAll(SetArgPointee<1>(report), Return(SUCCESS))); |
| 198 | 223 |
| 224 if (!expect_write_dump) | |
| 225 return; | |
| 226 | |
| 199 // Expect the call to write the proto to a minidump. This involves | 227 // Expect the call to write the proto to a minidump. This involves |
| 200 // requesting a report from the crashpad database, writing the report, then | 228 // requesting a report from the crashpad database, writing the report, then |
| 201 // finalizing it with the database. | 229 // finalizing it with the database. |
| 202 base::FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); | 230 FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); |
| 203 base::File minidump_file( | 231 base::File minidump_file( |
| 204 minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE); | 232 minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE); |
| 205 crashpad::UUID new_report_uuid; | 233 crashpad::UUID new_report_uuid; |
| 206 new_report_uuid.InitializeWithNew(); | 234 new_report_uuid.InitializeWithNew(); |
| 207 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, | 235 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, |
| 208 minidump_path}; | 236 minidump_path}; |
| 209 EXPECT_CALL(database_, PrepareNewCrashReport(_)) | 237 EXPECT_CALL(database_, PrepareNewCrashReport(_)) |
| 210 .Times(1) | 238 .Times(1) |
| 211 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), | 239 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), |
| 212 Return(CrashReportDatabase::kNoError))); | 240 Return(CrashReportDatabase::kNoError))); |
| 213 | 241 |
| 214 EXPECT_CALL(collector_, | 242 EXPECT_CALL(*collector_, |
| 215 WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile())) | 243 WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile())) |
| 216 .Times(1) | 244 .Times(1) |
| 217 .WillOnce(Return(true)); | 245 .WillOnce(Return(true)); |
| 218 } | 246 } |
| 219 void ValidateHistograms(int unclean_cnt, int unclean_system_cnt) { | 247 void ValidateHistograms(int unclean_cnt, int unclean_system_cnt) { |
| 220 histogram_tester_.ExpectTotalCount( | 248 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 221 "ActivityTracker.Collect.StabilityFileCount", 1); | 249 UNCLEAN_SHUTDOWN, unclean_cnt); |
| 222 histogram_tester_.ExpectBucketCount( | 250 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", |
| 223 "ActivityTracker.Collect.StabilityFileCount", 1, 1); | 251 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 } | 252 } |
| 233 void CollectReports(bool is_session_clean) { | 253 void CollectReports(bool is_session_clean) { |
| 234 SetUpTest(is_session_clean); | 254 SetUpTest(is_session_clean, true); |
| 235 | 255 |
| 236 EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _)) | 256 EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _)) |
| 237 .Times(1) | 257 .Times(1) |
| 238 .WillOnce(Return(CrashReportDatabase::kNoError)); | 258 .WillOnce(Return(CrashReportDatabase::kNoError)); |
| 239 | 259 |
| 240 // Run the test. | 260 // Run the test. |
| 241 int success_cnt = collector_.CollectAndSubmitAllPendingReports( | 261 std::vector<FilePath> debug_files{debug_file_}; |
| 242 debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, | 262 collector_->Process(debug_files); |
| 243 &database_); | |
| 244 ASSERT_EQ(1, success_cnt); | |
| 245 ASSERT_FALSE(base::PathExists(debug_file_)); | 263 ASSERT_FALSE(base::PathExists(debug_file_)); |
| 246 } | 264 } |
| 247 | 265 |
| 248 protected: | 266 protected: |
| 249 base::HistogramTester histogram_tester_; | 267 base::HistogramTester histogram_tester_; |
| 250 base::ScopedTempDir temp_dir_; | 268 base::ScopedTempDir temp_dir_; |
| 251 base::FilePath debug_file_; | 269 FilePath debug_file_; |
| 252 MockCrashReportDatabase database_; | 270 MockCrashReportDatabase database_; |
| 253 MockPostmortemReportCollector collector_; | 271 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_; | 272 CrashReportDatabase::NewReport crashpad_report_; |
| 257 }; | 273 }; |
| 258 | 274 |
| 259 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 275 TEST_F(PostmortemReportCollectorProcessTest, ProcessCleanSession) { |
| 260 CollectAndSubmitAllPendingReportsCleanSession) { | |
| 261 CollectReports(true); | 276 CollectReports(true); |
| 262 int expected_unclean = 1; | 277 int expected_unclean = 1; |
| 263 int expected_system_unclean = 0; | 278 int expected_system_unclean = 0; |
| 264 ValidateHistograms(expected_unclean, expected_system_unclean); | 279 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 265 } | 280 } |
| 266 | 281 |
| 267 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 282 TEST_F(PostmortemReportCollectorProcessTest, ProcessUncleanSession) { |
| 268 CollectAndSubmitAllPendingReportsUncleanSession) { | |
| 269 CollectReports(false); | 283 CollectReports(false); |
| 270 int expected_unclean = 1; | 284 int expected_unclean = 1; |
| 271 int expected_system_unclean = 1; | 285 int expected_system_unclean = 1; |
| 272 ValidateHistograms(expected_unclean, expected_system_unclean); | 286 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 273 } | 287 } |
| 274 | 288 |
| 275 TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, | 289 TEST_F(PostmortemReportCollectorProcessTest, ProcessStuckFile) { |
| 276 CollectAndSubmitAllPendingReportsStuckFile) { | 290 bool system_session_clean = true; |
| 277 SetUpTest(true); | 291 bool expect_write_dump = false; |
| 292 SetUpTest(system_session_clean, expect_write_dump); | |
| 278 | 293 |
| 279 // Open the stability debug file to prevent its deletion. | 294 // Open the stability debug file to prevent its deletion. |
| 280 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); | 295 base::ScopedFILE file(base::OpenFile(debug_file_, "w")); |
| 281 ASSERT_NE(file.get(), nullptr); | 296 ASSERT_NE(file.get(), nullptr); |
| 282 | 297 |
| 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. | 298 // Run the test. |
| 289 int success_cnt = collector_.CollectAndSubmitAllPendingReports( | 299 std::vector<FilePath> debug_files{debug_file_}; |
| 290 debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, | 300 collector_->Process(debug_files); |
| 291 &database_); | |
| 292 ASSERT_EQ(0, success_cnt); | |
| 293 ASSERT_TRUE(base::PathExists(debug_file_)); | 301 ASSERT_TRUE(base::PathExists(debug_file_)); |
| 294 | 302 |
| 303 histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", | |
| 304 DEBUG_FILE_DELETION_FAILED, 1); | |
| 295 int expected_unclean = 0; | 305 int expected_unclean = 0; |
| 296 int expected_system_unclean = 0; | 306 int expected_system_unclean = 0; |
| 297 ValidateHistograms(expected_unclean, expected_system_unclean); | 307 ValidateHistograms(expected_unclean, expected_system_unclean); |
| 298 } | 308 } |
| 299 | 309 |
| 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) { | 310 TEST(PostmortemReportCollectorTest, CollectEmptyFile) { |
| 341 // Create an empty file. | 311 // Create an empty file. |
| 342 base::ScopedTempDir temp_dir; | 312 base::ScopedTempDir temp_dir; |
| 343 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 313 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 344 base::FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); | 314 FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); |
| 345 { | 315 { |
| 346 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 316 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 347 ASSERT_NE(file.get(), nullptr); | 317 ASSERT_NE(file.get(), nullptr); |
| 348 } | 318 } |
| 349 ASSERT_TRUE(PathExists(file_path)); | 319 ASSERT_TRUE(PathExists(file_path)); |
| 350 | 320 |
| 351 // Validate collection: an empty file cannot suppport an analyzer. | 321 // Validate collection: an empty file cannot suppport an analyzer. |
| 322 MockCrashReportDatabase crash_db; | |
| 352 PostmortemReportCollector collector(kProductName, kVersionNumber, | 323 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 353 kChannelName, nullptr); | 324 kChannelName, &crash_db, nullptr); |
| 354 StabilityReport report; | 325 StabilityReport report; |
| 355 ASSERT_EQ(ANALYZER_CREATION_FAILED, | 326 ASSERT_EQ(ANALYZER_CREATION_FAILED, |
| 356 collector.CollectOneReport(file_path, &report)); | 327 collector.CollectOneReport(file_path, &report)); |
| 357 } | 328 } |
| 358 | 329 |
| 359 TEST(PostmortemReportCollectorTest, CollectRandomFile) { | 330 TEST(PostmortemReportCollectorTest, CollectRandomFile) { |
| 360 // Create a file with content we don't expect to be valid for a debug file. | 331 // Create a file with content we don't expect to be valid for a debug file. |
| 361 base::ScopedTempDir temp_dir; | 332 base::ScopedTempDir temp_dir; |
| 362 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 333 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 363 base::FilePath file_path = | 334 FilePath file_path = temp_dir.GetPath().AppendASCII("invalid_content.pma"); |
| 364 temp_dir.GetPath().AppendASCII("invalid_content.pma"); | |
| 365 { | 335 { |
| 366 base::ScopedFILE file(base::OpenFile(file_path, "w")); | 336 base::ScopedFILE file(base::OpenFile(file_path, "w")); |
| 367 ASSERT_NE(file.get(), nullptr); | 337 ASSERT_NE(file.get(), nullptr); |
| 368 // Assuming this size is greater than the minimum size of a debug file. | 338 // Assuming this size is greater than the minimum size of a debug file. |
| 369 std::vector<uint8_t> data(1024); | 339 std::vector<uint8_t> data(1024); |
| 370 for (size_t i = 0; i < data.size(); ++i) | 340 for (size_t i = 0; i < data.size(); ++i) |
| 371 data[i] = i % UINT8_MAX; | 341 data[i] = i % UINT8_MAX; |
| 372 ASSERT_EQ(data.size(), | 342 ASSERT_EQ(data.size(), |
| 373 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); | 343 fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get())); |
| 374 } | 344 } |
| 375 ASSERT_TRUE(PathExists(file_path)); | 345 ASSERT_TRUE(PathExists(file_path)); |
| 376 | 346 |
| 377 // Validate collection: random content appears as though there is not | 347 // Validate collection: random content appears as though there is not |
| 378 // stability data. | 348 // stability data. |
| 349 MockCrashReportDatabase crash_db; | |
| 379 PostmortemReportCollector collector(kProductName, kVersionNumber, | 350 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 380 kChannelName, nullptr); | 351 kChannelName, &crash_db, nullptr); |
| 381 StabilityReport report; | 352 StabilityReport report; |
| 382 ASSERT_NE(SUCCESS, collector.CollectOneReport(file_path, &report)); | 353 ASSERT_NE(SUCCESS, collector.CollectOneReport(file_path, &report)); |
| 383 } | 354 } |
| 384 | 355 |
| 385 namespace { | 356 namespace { |
| 386 | 357 |
| 387 // Parameters for the activity tracking. | 358 // Parameters for the activity tracking. |
| 388 const size_t kFileSize = 64 << 10; // 64 KiB | 359 const size_t kFileSize = 64 << 10; // 64 KiB |
| 389 const int kStackDepth = 6; | 360 const int kStackDepth = 6; |
| 390 const uint64_t kAllocatorId = 0; | 361 const uint64_t kAllocatorId = 0; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 PersistentMemoryAllocator::kSizeAny); | 430 PersistentMemoryAllocator::kSizeAny); |
| 460 if (mem_base == nullptr) | 431 if (mem_base == nullptr) |
| 461 return nullptr; | 432 return nullptr; |
| 462 | 433 |
| 463 // Make the allocation iterable so it can be found by other processes. | 434 // Make the allocation iterable so it can be found by other processes. |
| 464 allocator->MakeIterable(mem_reference); | 435 allocator->MakeIterable(mem_reference); |
| 465 | 436 |
| 466 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); | 437 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); |
| 467 } | 438 } |
| 468 | 439 |
| 469 const base::FilePath& debug_file_path() const { return debug_file_path_; } | 440 const FilePath& debug_file_path() const { return debug_file_path_; } |
| 470 | 441 |
| 471 protected: | 442 protected: |
| 472 base::ScopedTempDir temp_dir_; | 443 base::ScopedTempDir temp_dir_; |
| 473 base::FilePath debug_file_path_; | 444 FilePath debug_file_path_; |
| 474 | 445 |
| 475 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 446 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 476 std::unique_ptr<ThreadActivityTracker> tracker_; | 447 std::unique_ptr<ThreadActivityTracker> tracker_; |
| 477 }; | 448 }; |
| 478 | 449 |
| 479 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 450 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
| 480 // Create some activity data. | 451 // Create some activity data. |
| 481 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), | 452 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), |
| 482 base::debug::Activity::ACT_TASK_RUN, | 453 base::debug::Activity::ACT_TASK_RUN, |
| 483 ActivityData::ForTask(kTaskSequenceNum)); | 454 ActivityData::ForTask(kTaskSequenceNum)); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 499 | 470 |
| 500 // Add some user data. | 471 // Add some user data. |
| 501 ActivityTrackerMemoryAllocator user_data_allocator( | 472 ActivityTrackerMemoryAllocator user_data_allocator( |
| 502 allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord, | 473 allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord, |
| 503 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); | 474 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
| 504 std::unique_ptr<ActivityUserData> user_data = | 475 std::unique_ptr<ActivityUserData> user_data = |
| 505 tracker_->GetUserData(activity_id, &user_data_allocator); | 476 tracker_->GetUserData(activity_id, &user_data_allocator); |
| 506 user_data->SetInt("some_int", 42); | 477 user_data->SetInt("some_int", 42); |
| 507 | 478 |
| 508 // Validate collection returns the expected report. | 479 // Validate collection returns the expected report. |
| 480 MockCrashReportDatabase crash_db; | |
| 509 PostmortemReportCollector collector(kProductName, kVersionNumber, | 481 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 510 kChannelName, nullptr); | 482 kChannelName, &crash_db, nullptr); |
| 511 StabilityReport report; | 483 StabilityReport report; |
| 512 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 484 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 513 | 485 |
| 514 // Validate the report. | 486 // Validate the report. |
| 515 ASSERT_EQ(1, report.process_states_size()); | 487 ASSERT_EQ(1, report.process_states_size()); |
| 516 const ProcessState& process_state = report.process_states(0); | 488 const ProcessState& process_state = report.process_states(0); |
| 517 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | 489 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); |
| 518 ASSERT_EQ(1, process_state.threads_size()); | 490 ASSERT_EQ(1, process_state.threads_size()); |
| 519 | 491 |
| 520 const ThreadState& thread_state = process_state.threads(0); | 492 const ThreadState& thread_state = process_state.threads(0); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 587 } | 559 } |
| 588 | 560 |
| 589 void SetUp() override { | 561 void SetUp() override { |
| 590 testing::Test::SetUp(); | 562 testing::Test::SetUp(); |
| 591 | 563 |
| 592 // Set up a debug file path. | 564 // Set up a debug file path. |
| 593 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 565 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 594 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); | 566 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); |
| 595 } | 567 } |
| 596 | 568 |
| 597 const base::FilePath& debug_file_path() { return debug_file_path_; } | 569 const FilePath& debug_file_path() { return debug_file_path_; } |
| 598 | 570 |
| 599 protected: | 571 protected: |
| 600 base::ScopedTempDir temp_dir_; | 572 base::ScopedTempDir temp_dir_; |
| 601 base::FilePath debug_file_path_; | 573 FilePath debug_file_path_; |
| 602 }; | 574 }; |
| 603 | 575 |
| 604 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, | 576 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| 605 LogCollection) { | 577 LogCollection) { |
| 606 // Record some log messages. | 578 // Record some log messages. |
| 607 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, | 579 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 608 "", 3); | 580 "", 3); |
| 609 GlobalActivityTracker::Get()->RecordLogMessage("hello world"); | 581 GlobalActivityTracker::Get()->RecordLogMessage("hello world"); |
| 610 GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); | 582 GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); |
| 611 | 583 |
| 612 // Collect the stability report. | 584 // Collect the stability report. |
| 585 MockCrashReportDatabase crash_db; | |
| 613 PostmortemReportCollector collector(kProductName, kVersionNumber, | 586 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 614 kChannelName, nullptr); | 587 kChannelName, &crash_db, nullptr); |
| 615 StabilityReport report; | 588 StabilityReport report; |
| 616 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 589 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 617 | 590 |
| 618 // Validate the report's log content. | 591 // Validate the report's log content. |
| 619 ASSERT_EQ(2, report.log_messages_size()); | 592 ASSERT_EQ(2, report.log_messages_size()); |
| 620 ASSERT_EQ("hello world", report.log_messages(0)); | 593 ASSERT_EQ("hello world", report.log_messages(0)); |
| 621 ASSERT_EQ("foo bar", report.log_messages(1)); | 594 ASSERT_EQ("foo bar", report.log_messages(1)); |
| 622 } | 595 } |
| 623 | 596 |
| 624 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, | 597 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 636 process_data.Set("raw", "foo", 3); | 609 process_data.Set("raw", "foo", 3); |
| 637 process_data.SetString("string", "bar"); | 610 process_data.SetString("string", "bar"); |
| 638 process_data.SetChar("char", '9'); | 611 process_data.SetChar("char", '9'); |
| 639 process_data.SetInt("int", -9999); | 612 process_data.SetInt("int", -9999); |
| 640 process_data.SetUint("uint", 9999); | 613 process_data.SetUint("uint", 9999); |
| 641 process_data.SetBool("bool", true); | 614 process_data.SetBool("bool", true); |
| 642 process_data.SetReference("ref", string1, strlen(string1)); | 615 process_data.SetReference("ref", string1, strlen(string1)); |
| 643 process_data.SetStringReference("sref", string2); | 616 process_data.SetStringReference("sref", string2); |
| 644 | 617 |
| 645 // Collect the stability report. | 618 // Collect the stability report. |
| 619 MockCrashReportDatabase crash_db; | |
| 646 PostmortemReportCollector collector(kProductName, kVersionNumber, | 620 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 647 kChannelName, nullptr); | 621 kChannelName, &crash_db, nullptr); |
| 648 StabilityReport report; | 622 StabilityReport report; |
| 649 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 623 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 650 | 624 |
| 651 // Validate the report's user data. | 625 // Validate the report's user data. |
| 652 const auto& collected_data = report.global_data(); | 626 const auto& collected_data = report.global_data(); |
| 653 ASSERT_EQ(kInternalProcessDatums + 12U, collected_data.size()); | 627 ASSERT_EQ(kInternalProcessDatums + 12U, collected_data.size()); |
| 654 | 628 |
| 655 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); | 629 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); |
| 656 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); | 630 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); |
| 657 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); | 631 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 705 FieldTrialCollection) { | 679 FieldTrialCollection) { |
| 706 // Record some data. | 680 // Record some data. |
| 707 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, | 681 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 708 "", 3); | 682 "", 3); |
| 709 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); | 683 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); |
| 710 process_data.SetString("string", "bar"); | 684 process_data.SetString("string", "bar"); |
| 711 process_data.SetString("FieldTrial.string", "bar"); | 685 process_data.SetString("FieldTrial.string", "bar"); |
| 712 process_data.SetString("FieldTrial.foo", "bar"); | 686 process_data.SetString("FieldTrial.foo", "bar"); |
| 713 | 687 |
| 714 // Collect the stability report. | 688 // Collect the stability report. |
| 689 MockCrashReportDatabase crash_db; | |
| 715 PostmortemReportCollector collector(kProductName, kVersionNumber, | 690 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 716 kChannelName, nullptr); | 691 kChannelName, &crash_db, nullptr); |
| 717 StabilityReport report; | 692 StabilityReport report; |
| 718 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 693 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 719 | 694 |
| 720 // Validate the report's experiment and global data. | 695 // Validate the report's experiment and global data. |
| 721 ASSERT_EQ(2, report.field_trials_size()); | 696 ASSERT_EQ(2, report.field_trials_size()); |
| 722 EXPECT_NE(0U, report.field_trials(0).name_id()); | 697 EXPECT_NE(0U, report.field_trials(0).name_id()); |
| 723 EXPECT_NE(0U, report.field_trials(0).group_id()); | 698 EXPECT_NE(0U, report.field_trials(0).group_id()); |
| 724 EXPECT_NE(0U, report.field_trials(1).name_id()); | 699 EXPECT_NE(0U, report.field_trials(1).name_id()); |
| 725 EXPECT_EQ(report.field_trials(0).group_id(), | 700 EXPECT_EQ(report.field_trials(0).group_id(), |
| 726 report.field_trials(1).group_id()); | 701 report.field_trials(1).group_id()); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 746 module_info.age = 1; | 721 module_info.age = 1; |
| 747 crashpad::UUID debug_uuid; | 722 crashpad::UUID debug_uuid; |
| 748 debug_uuid.InitializeFromString("11223344-5566-7788-abcd-0123456789ab"); | 723 debug_uuid.InitializeFromString("11223344-5566-7788-abcd-0123456789ab"); |
| 749 memcpy(module_info.identifier, &debug_uuid, sizeof(module_info.identifier)); | 724 memcpy(module_info.identifier, &debug_uuid, sizeof(module_info.identifier)); |
| 750 module_info.file = "foo"; | 725 module_info.file = "foo"; |
| 751 module_info.debug_file = "bar"; | 726 module_info.debug_file = "bar"; |
| 752 | 727 |
| 753 GlobalActivityTracker::Get()->RecordModuleInfo(module_info); | 728 GlobalActivityTracker::Get()->RecordModuleInfo(module_info); |
| 754 | 729 |
| 755 // Collect the stability report. | 730 // Collect the stability report. |
| 731 MockCrashReportDatabase crash_db; | |
| 756 PostmortemReportCollector collector(kProductName, kVersionNumber, | 732 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 757 kChannelName, nullptr); | 733 kChannelName, &crash_db, nullptr); |
| 758 StabilityReport report; | 734 StabilityReport report; |
| 759 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 735 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 760 | 736 |
| 761 // Validate the report's modules content. | 737 // Validate the report's modules content. |
| 762 ASSERT_EQ(1, report.process_states_size()); | 738 ASSERT_EQ(1, report.process_states_size()); |
| 763 const ProcessState& process_state = report.process_states(0); | 739 const ProcessState& process_state = report.process_states(0); |
| 764 ASSERT_EQ(1, process_state.modules_size()); | 740 ASSERT_EQ(1, process_state.modules_size()); |
| 765 | 741 |
| 766 const CodeModule collected_module = process_state.modules(0); | 742 const CodeModule collected_module = process_state.modules(0); |
| 767 EXPECT_EQ(module_info.address, | 743 EXPECT_EQ(module_info.address, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 784 "", 3); | 760 "", 3); |
| 785 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); | 761 ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data(); |
| 786 process_data.SetInt(kStabilityStartTimestamp, 12345LL); | 762 process_data.SetInt(kStabilityStartTimestamp, 12345LL); |
| 787 | 763 |
| 788 // Collect. | 764 // Collect. |
| 789 MockSystemSessionAnalyzer analyzer; | 765 MockSystemSessionAnalyzer analyzer; |
| 790 EXPECT_CALL(analyzer, | 766 EXPECT_CALL(analyzer, |
| 791 IsSessionUnclean(base::Time::FromInternalValue(12345LL))) | 767 IsSessionUnclean(base::Time::FromInternalValue(12345LL))) |
| 792 .Times(1) | 768 .Times(1) |
| 793 .WillOnce(Return(SystemSessionAnalyzer::CLEAN)); | 769 .WillOnce(Return(SystemSessionAnalyzer::CLEAN)); |
| 770 MockCrashReportDatabase crash_db; | |
| 794 PostmortemReportCollector collector(kProductName, kVersionNumber, | 771 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 795 kChannelName, &analyzer); | 772 kChannelName, &crash_db, &analyzer); |
| 796 StabilityReport report; | 773 StabilityReport report; |
| 797 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); | 774 ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); |
| 798 | 775 |
| 799 // Validate the report. | 776 // Validate the report. |
| 800 ASSERT_EQ(SystemState::CLEAN, report.system_state().session_state()); | 777 ASSERT_EQ(SystemState::CLEAN, report.system_state().session_state()); |
| 801 } | 778 } |
| 802 | 779 |
| 803 } // namespace browser_watcher | 780 } // namespace browser_watcher |
| OLD | NEW |