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/stability_debugging.h" | 5 #include "components/browser_watcher/stability_debugging.h" |
6 | 6 |
7 #include "base/files/file_enumerator.h" | 7 #include <windows.h> |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/debug/activity_tracker.h" | |
8 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
9 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
10 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
11 #include "base/process/process.h" | 14 #include "base/process/process.h" |
12 #include "base/test/multiprocess_test.h" | 15 #include "base/test/multiprocess_test.h" |
13 #include "components/browser_watcher/stability_paths.h" | 16 #include "base/test/test_timeouts.h" |
17 #include "components/browser_watcher/stability_report.pb.h" | |
18 #include "components/browser_watcher/stability_report_extractor.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "testing/multiprocess_func_list.h" | 20 #include "testing/multiprocess_func_list.h" |
16 | 21 |
17 namespace browser_watcher { | 22 namespace browser_watcher { |
18 | 23 |
19 class StabilityDebuggingWinMultiProcTest : public base::MultiProcessTest {}; | 24 using base::debug::GlobalActivityTracker; |
20 | 25 |
21 MULTIPROCESS_TEST_MAIN(DummyProcess) { | 26 const int kMemorySize = 1 << 20; // 1MiB |
27 const char* kDebugFileSwitch = "stability_debugging_test_debug_file_switch"; | |
28 | |
29 class StabilityDebuggingTest : public base::MultiProcessTest { | |
30 public: | |
31 StabilityDebuggingTest() {} | |
32 ~StabilityDebuggingTest() override = default; | |
33 | |
34 void SetUp() override { | |
35 testing::Test::SetUp(); | |
36 | |
37 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
38 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); | |
39 } | |
40 | |
41 const base::FilePath& debug_file_path() { return debug_file_path_; } | |
42 | |
43 protected: | |
44 base::CommandLine MakeCmdLine(const std::string& procname) override { | |
45 base::CommandLine cmd = base::MultiProcessTest::MakeCmdLine(procname); | |
46 cmd.AppendSwitchPath(kDebugFileSwitch, debug_file_path_); | |
47 return cmd; | |
48 } | |
49 | |
50 base::ScopedTempDir temp_dir_; | |
51 base::FilePath debug_file_path_; | |
52 }; | |
53 | |
54 // Creates a global tracker, registers a vectored exception handler, then | |
55 // crashes. | |
56 MULTIPROCESS_TEST_MAIN(CrashingProcess) { | |
57 base::FilePath debug_path = | |
58 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( | |
59 kDebugFileSwitch); | |
60 GlobalActivityTracker::CreateWithFile(debug_path, kMemorySize, 0ULL, "", 3); | |
61 RegisterStabilityVEH(); | |
62 | |
63 // Crash! | |
64 char* invalid = nullptr; | |
Sigurður Ásgeirsson
2017/06/09 13:55:15
I'm not sure the compiler is obliged to honor your
manzagop (departed)
2017/06/09 21:27:35
Switched to a single process test, as that's simpl
| |
65 *invalid = 42; | |
66 | |
22 return 0; | 67 return 0; |
23 } | 68 } |
24 | 69 |
25 TEST_F(StabilityDebuggingWinMultiProcTest, GetStabilityFileForProcessTest) { | 70 TEST_F(StabilityDebuggingTest, CrashingTest) { |
26 const base::FilePath empty_path; | 71 base::SpawnChildResult spawn_result = SpawnChild("CrashingProcess"); |
72 int exit_code; | |
73 EXPECT_TRUE(spawn_result.process.WaitForExitWithTimeout( | |
74 TestTimeouts::action_max_timeout(), &exit_code)); | |
27 | 75 |
28 // Get the path for the current process. | 76 // Collect the report. |
29 base::FilePath stability_path; | 77 StabilityReport report; |
30 ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(), empty_path, | 78 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
31 &stability_path)); | |
32 | 79 |
33 // Ensure requesting a second time produces the same. | 80 // Validate expectations: 1 process with 1 thread that has an exception. |
Sigurður Ásgeirsson
2017/06/09 13:55:15
My bet is that this is going to flake a bit, as yo
manzagop (departed)
2017/06/09 21:27:35
Sgtm! Actually, I'm in the same thread it's easy t
| |
34 base::FilePath stability_path_two; | 81 ASSERT_EQ(1, report.process_states_size()); |
35 ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(), empty_path, | 82 const ProcessState& process_state = report.process_states(0); |
36 &stability_path_two)); | 83 EXPECT_EQ(spawn_result.process.Pid(), process_state.process_id()); |
37 EXPECT_EQ(stability_path, stability_path_two); | 84 ASSERT_EQ(1, process_state.threads_size()); |
38 | 85 const ThreadState& thread_state = process_state.threads(0); |
39 // Ensure a different process has a different stability path. | 86 ASSERT_TRUE(thread_state.has_exception()); |
40 base::SpawnChildResult spawn_result = SpawnChild("DummyProcess"); | 87 const Exception& exception = thread_state.exception(); |
41 base::FilePath stability_path_other; | 88 EXPECT_EQ(EXCEPTION_ACCESS_VIOLATION, exception.code()); |
42 ASSERT_TRUE(GetStabilityFileForProcess(spawn_result.process, empty_path, | |
43 &stability_path_other)); | |
44 EXPECT_NE(stability_path, stability_path_other); | |
45 } | |
46 | |
47 TEST(StabilityDebuggingWinTest, | |
48 GetStabilityFilePatternMatchesGetStabilityFileForProcessResult) { | |
49 // GetStabilityFileForProcess file names must match GetStabilityFilePattern | |
50 // according to | |
51 // FileEnumerator's algorithm. We test this by writing out some files and | |
52 // validating what is matched. | |
53 | |
54 base::ScopedTempDir temp_dir; | |
55 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
56 base::FilePath user_data_dir = temp_dir.GetPath(); | |
57 | |
58 // Create the stability directory. | |
59 base::FilePath stability_dir = GetStabilityDir(user_data_dir); | |
60 ASSERT_TRUE(base::CreateDirectory(stability_dir)); | |
61 | |
62 // Write a stability file. | |
63 base::FilePath stability_file; | |
64 ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(), | |
65 user_data_dir, &stability_file)); | |
66 { | |
67 base::ScopedFILE file(base::OpenFile(stability_file, "w")); | |
68 ASSERT_TRUE(file.get()); | |
69 } | |
70 | |
71 // Write a file that shouldn't match. | |
72 base::FilePath non_matching_file = | |
73 stability_dir.AppendASCII("non_matching.foo"); | |
74 { | |
75 base::ScopedFILE file(base::OpenFile(non_matching_file, "w")); | |
76 ASSERT_TRUE(file.get()); | |
77 } | |
78 | |
79 // Validate only the stability file matches. | |
80 base::FileEnumerator enumerator(stability_dir, false /* recursive */, | |
81 base::FileEnumerator::FILES, | |
82 GetStabilityFilePattern()); | |
83 ASSERT_EQ(stability_file, enumerator.Next()); | |
84 ASSERT_TRUE(enumerator.Next().empty()); | |
85 } | 89 } |
86 | 90 |
87 } // namespace browser_watcher | 91 } // namespace browser_watcher |
OLD | NEW |