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 |