OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/stability_report_extractor.h" | 5 #include "components/browser_watcher/stability_report_extractor.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/debug/activity_tracker.h" | 10 #include "base/debug/activity_tracker.h" |
11 #include "base/files/file.h" | 11 #include "base/files/file.h" |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/files/memory_mapped_file.h" | 13 #include "base/files/memory_mapped_file.h" |
14 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/metrics/persistent_memory_allocator.h" | 16 #include "base/metrics/persistent_memory_allocator.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/time/time.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
19 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 20 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
20 | 21 |
21 namespace browser_watcher { | 22 namespace browser_watcher { |
22 | 23 |
23 using base::debug::ActivityData; | 24 using base::debug::ActivityData; |
24 using base::debug::ActivityTrackerMemoryAllocator; | 25 using base::debug::ActivityTrackerMemoryAllocator; |
25 using base::debug::ActivityUserData; | 26 using base::debug::ActivityUserData; |
26 using base::debug::GlobalActivityTracker; | 27 using base::debug::GlobalActivityTracker; |
27 using base::debug::ThreadActivityTracker; | 28 using base::debug::ThreadActivityTracker; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 mem_reference, GlobalActivityTracker::kTypeIdActivityTracker, | 112 mem_reference, GlobalActivityTracker::kTypeIdActivityTracker, |
112 PersistentMemoryAllocator::kSizeAny); | 113 PersistentMemoryAllocator::kSizeAny); |
113 if (mem_base == nullptr) | 114 if (mem_base == nullptr) |
114 return nullptr; | 115 return nullptr; |
115 | 116 |
116 // Make the allocation iterable so it can be found by other processes. | 117 // Make the allocation iterable so it can be found by other processes. |
117 allocator->MakeIterable(mem_reference); | 118 allocator->MakeIterable(mem_reference); |
118 | 119 |
119 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); | 120 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); |
120 } | 121 } |
122 void PerformBasicReportValidation(const StabilityReport& report) { | |
123 // One report with one thread that has the expected name and id. | |
124 ASSERT_EQ(1, report.process_states_size()); | |
125 const ProcessState& process_state = report.process_states(0); | |
126 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | |
127 ASSERT_EQ(1, process_state.threads_size()); | |
128 const ThreadState& thread_state = process_state.threads(0); | |
129 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); | |
130 #if defined(OS_WIN) | |
131 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); | |
132 #elif defined(OS_POSIX) | |
133 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), | |
134 thread_state.thread_id()); | |
135 #endif | |
136 } | |
121 | 137 |
122 const FilePath& debug_file_path() const { return debug_file_path_; } | 138 const FilePath& debug_file_path() const { return debug_file_path_; } |
123 | 139 |
124 protected: | 140 protected: |
125 base::ScopedTempDir temp_dir_; | 141 base::ScopedTempDir temp_dir_; |
126 FilePath debug_file_path_; | 142 FilePath debug_file_path_; |
127 | 143 |
128 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 144 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
129 std::unique_ptr<ThreadActivityTracker> tracker_; | 145 std::unique_ptr<ThreadActivityTracker> tracker_; |
130 }; | 146 }; |
(...skipping 25 matching lines...) Expand all Loading... | |
156 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); | 172 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
157 std::unique_ptr<ActivityUserData> user_data = | 173 std::unique_ptr<ActivityUserData> user_data = |
158 tracker_->GetUserData(activity_id, &user_data_allocator); | 174 tracker_->GetUserData(activity_id, &user_data_allocator); |
159 user_data->SetInt("some_int", 42); | 175 user_data->SetInt("some_int", 42); |
160 | 176 |
161 // Validate collection returns the expected report. | 177 // Validate collection returns the expected report. |
162 StabilityReport report; | 178 StabilityReport report; |
163 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | 179 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
164 | 180 |
165 // Validate the report. | 181 // Validate the report. |
166 ASSERT_EQ(1, report.process_states_size()); | 182 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); |
167 const ProcessState& process_state = report.process_states(0); | 183 const ThreadState& thread_state = report.process_states(0).threads(0); |
168 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | |
169 ASSERT_EQ(1, process_state.threads_size()); | |
170 | |
171 const ThreadState& thread_state = process_state.threads(0); | |
172 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); | |
173 #if defined(OS_WIN) | |
174 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); | |
175 #elif defined(OS_POSIX) | |
176 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), | |
177 thread_state.thread_id()); | |
178 #endif | |
179 | 184 |
180 EXPECT_EQ(7, thread_state.activity_count()); | 185 EXPECT_EQ(7, thread_state.activity_count()); |
181 ASSERT_EQ(6, thread_state.activities_size()); | 186 ASSERT_EQ(6, thread_state.activities_size()); |
182 { | 187 { |
183 const Activity& activity = thread_state.activities(0); | 188 const Activity& activity = thread_state.activities(0); |
184 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); | 189 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); |
185 EXPECT_EQ(kTaskOrigin, activity.origin_address()); | 190 EXPECT_EQ(kTaskOrigin, activity.origin_address()); |
186 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); | 191 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); |
187 EXPECT_EQ(0U, activity.user_data().size()); | 192 EXPECT_EQ(0U, activity.user_data().size()); |
188 } | 193 } |
(...skipping 27 matching lines...) Expand all Loading... | |
216 } | 221 } |
217 { | 222 { |
218 const Activity& activity = thread_state.activities(5); | 223 const Activity& activity = thread_state.activities(5); |
219 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); | 224 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); |
220 EXPECT_EQ(kGenericId, activity.generic_id()); | 225 EXPECT_EQ(kGenericId, activity.generic_id()); |
221 EXPECT_EQ(kGenericData, activity.generic_data()); | 226 EXPECT_EQ(kGenericData, activity.generic_data()); |
222 EXPECT_EQ(0U, activity.user_data().size()); | 227 EXPECT_EQ(0U, activity.user_data().size()); |
223 } | 228 } |
224 } | 229 } |
225 | 230 |
231 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectException) { | |
232 const void* expected_pc = reinterpret_cast<void*>(0xCAFE); | |
233 const void* expected_address = nullptr; | |
234 const uint32_t expected_code = 42U; | |
235 | |
236 // Record an exception. | |
237 const int64_t timestamp = base::Time::Now().ToInternalValue(); | |
238 tracker_->RecordExceptionActivity(expected_pc, expected_address, | |
239 base::debug::Activity::ACT_EXCEPTION, | |
240 ActivityData::ForException(expected_code)); | |
241 | |
242 // Collect report and validate. | |
243 StabilityReport report; | |
244 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | |
245 | |
246 // Validate the presence of the exception. | |
247 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); | |
248 const ThreadState& thread_state = report.process_states(0).threads(0); | |
249 ASSERT_TRUE(thread_state.has_exception()); | |
250 const Exception& exception = thread_state.exception(); | |
251 EXPECT_EQ(expected_code, exception.code()); | |
252 EXPECT_EQ(expected_pc, reinterpret_cast<void*>(exception.program_counter())); | |
253 EXPECT_EQ(expected_address, | |
254 reinterpret_cast<void*>(exception.exception_address())); | |
255 const int64_t tolerance_us = 1000ULL; | |
256 EXPECT_LE(std::abs(timestamp - exception.time()), tolerance_us); | |
257 } | |
258 | |
259 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectNoException) { | |
Sigurður Ásgeirsson
2017/06/09 13:55:15
nice testing, I like it!
manzagop (departed)
2017/06/09 21:27:35
Thanks you sir! Ack.
| |
260 // Record something. | |
261 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), | |
262 base::debug::Activity::ACT_TASK_RUN, | |
263 ActivityData::ForTask(kTaskSequenceNum)); | |
264 | |
265 // Collect report and validate there is no exception. | |
266 StabilityReport report; | |
267 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | |
268 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); | |
269 const ThreadState& thread_state = report.process_states(0).threads(0); | |
270 ASSERT_FALSE(thread_state.has_exception()); | |
271 } | |
272 | |
226 // Tests stability report extraction. | 273 // Tests stability report extraction. |
227 class StabilityReportExtractorTest : public testing::Test { | 274 class StabilityReportExtractorTest : public testing::Test { |
228 public: | 275 public: |
229 const int kMemorySize = 1 << 20; // 1MiB | 276 const int kMemorySize = 1 << 20; // 1MiB |
230 | 277 |
231 StabilityReportExtractorTest() {} | 278 StabilityReportExtractorTest() {} |
232 ~StabilityReportExtractorTest() override { | 279 ~StabilityReportExtractorTest() override { |
233 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); | 280 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
234 if (global_tracker) { | 281 if (global_tracker) { |
235 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); | 282 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
400 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); | 447 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); |
401 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); | 448 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); |
402 EXPECT_EQ("1122334455667788ABCD0123456789AB1", | 449 EXPECT_EQ("1122334455667788ABCD0123456789AB1", |
403 collected_module.debug_identifier()); | 450 collected_module.debug_identifier()); |
404 EXPECT_EQ("", collected_module.version()); | 451 EXPECT_EQ("", collected_module.version()); |
405 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); | 452 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); |
406 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); | 453 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); |
407 } | 454 } |
408 | 455 |
409 } // namespace browser_watcher | 456 } // namespace browser_watcher |
OLD | NEW |