OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 <unistd.h> | 5 #include <unistd.h> |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "crash-reporter/system_logging_mock.h" | 8 #include "chromeos/syslog_logging.h" |
| 9 #include "chromeos/test_helpers.h" |
9 #include "crash-reporter/user_collector.h" | 10 #include "crash-reporter/user_collector.h" |
10 #include "crash-reporter/test_helpers.h" | |
11 #include "gflags/gflags.h" | 11 #include "gflags/gflags.h" |
12 #include "gtest/gtest.h" | 12 #include "gtest/gtest.h" |
13 | 13 |
14 static int s_crashes = 0; | 14 static int s_crashes = 0; |
15 static bool s_metrics = false; | 15 static bool s_metrics = false; |
16 | 16 |
17 static const char kFilePath[] = "/my/path"; | 17 static const char kFilePath[] = "/my/path"; |
18 | 18 |
| 19 using chromeos::FindLog; |
| 20 |
19 void CountCrash() { | 21 void CountCrash() { |
20 ++s_crashes; | 22 ++s_crashes; |
21 } | 23 } |
22 | 24 |
23 bool IsMetrics() { | 25 bool IsMetrics() { |
24 return s_metrics; | 26 return s_metrics; |
25 } | 27 } |
26 | 28 |
27 class UserCollectorTest : public ::testing::Test { | 29 class UserCollectorTest : public ::testing::Test { |
28 void SetUp() { | 30 void SetUp() { |
29 s_crashes = 0; | 31 s_crashes = 0; |
30 collector_.Initialize(CountCrash, | 32 collector_.Initialize(CountCrash, |
31 kFilePath, | 33 kFilePath, |
32 IsMetrics, | 34 IsMetrics, |
33 &logging_, | |
34 false); | 35 false); |
35 file_util::Delete(FilePath("test"), true); | 36 file_util::Delete(FilePath("test"), true); |
36 mkdir("test", 0777); | 37 mkdir("test", 0777); |
37 collector_.set_core_pattern_file("test/core_pattern"); | 38 collector_.set_core_pattern_file("test/core_pattern"); |
38 collector_.set_core_pipe_limit_file("test/core_pipe_limit"); | 39 collector_.set_core_pipe_limit_file("test/core_pipe_limit"); |
39 pid_ = getpid(); | 40 pid_ = getpid(); |
| 41 chromeos::ClearLog(); |
40 } | 42 } |
41 protected: | 43 protected: |
42 void ExpectFileEquals(const char *golden, | 44 void ExpectFileEquals(const char *golden, |
43 const char *file_path) { | 45 const char *file_path) { |
44 std::string contents; | 46 std::string contents; |
45 EXPECT_TRUE(file_util::ReadFileToString(FilePath(file_path), | 47 EXPECT_TRUE(file_util::ReadFileToString(FilePath(file_path), |
46 &contents)); | 48 &contents)); |
47 EXPECT_EQ(golden, contents); | 49 EXPECT_EQ(golden, contents); |
48 } | 50 } |
49 | 51 |
50 SystemLoggingMock logging_; | |
51 UserCollector collector_; | 52 UserCollector collector_; |
52 pid_t pid_; | 53 pid_t pid_; |
53 }; | 54 }; |
54 | 55 |
55 TEST_F(UserCollectorTest, EnableOK) { | 56 TEST_F(UserCollectorTest, EnableOK) { |
56 ASSERT_TRUE(collector_.Enable()); | 57 ASSERT_TRUE(collector_.Enable()); |
57 ExpectFileEquals("|/my/path --user=%p:%s:%e", "test/core_pattern"); | 58 ExpectFileEquals("|/my/path --user=%p:%s:%e", "test/core_pattern"); |
58 ExpectFileEquals("4", "test/core_pipe_limit"); | 59 ExpectFileEquals("4", "test/core_pipe_limit"); |
59 ASSERT_EQ(s_crashes, 0); | 60 ASSERT_EQ(s_crashes, 0); |
60 ASSERT_NE(logging_.log().find("Enabling user crash handling"), | 61 EXPECT_TRUE(FindLog("Enabling user crash handling")); |
61 std::string::npos); | |
62 } | 62 } |
63 | 63 |
64 TEST_F(UserCollectorTest, EnableNoPatternFileAccess) { | 64 TEST_F(UserCollectorTest, EnableNoPatternFileAccess) { |
65 collector_.set_core_pattern_file("/does_not_exist"); | 65 collector_.set_core_pattern_file("/does_not_exist"); |
66 ASSERT_FALSE(collector_.Enable()); | 66 ASSERT_FALSE(collector_.Enable()); |
67 ASSERT_EQ(s_crashes, 0); | 67 ASSERT_EQ(s_crashes, 0); |
68 ASSERT_NE(logging_.log().find("Enabling user crash handling"), | 68 EXPECT_TRUE(FindLog("Enabling user crash handling")); |
69 std::string::npos); | 69 EXPECT_TRUE(FindLog("Unable to write /does_not_exist")); |
70 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), | |
71 std::string::npos); | |
72 } | 70 } |
73 | 71 |
74 TEST_F(UserCollectorTest, EnableNoPipeLimitFileAccess) { | 72 TEST_F(UserCollectorTest, EnableNoPipeLimitFileAccess) { |
75 collector_.set_core_pipe_limit_file("/does_not_exist"); | 73 collector_.set_core_pipe_limit_file("/does_not_exist"); |
76 ASSERT_FALSE(collector_.Enable()); | 74 ASSERT_FALSE(collector_.Enable()); |
77 ASSERT_EQ(s_crashes, 0); | 75 ASSERT_EQ(s_crashes, 0); |
78 // Core pattern should not be written if we cannot access the pipe limit | 76 // Core pattern should not be written if we cannot access the pipe limit |
79 // or otherwise we may set a pattern that results in infinite recursion. | 77 // or otherwise we may set a pattern that results in infinite recursion. |
80 ASSERT_FALSE(file_util::PathExists(FilePath("test/core_pattern"))); | 78 ASSERT_FALSE(file_util::PathExists(FilePath("test/core_pattern"))); |
81 ASSERT_NE(logging_.log().find("Enabling user crash handling"), | 79 EXPECT_TRUE(FindLog("Enabling user crash handling")); |
82 std::string::npos); | 80 EXPECT_TRUE(FindLog("Unable to write /does_not_exist")); |
83 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), | |
84 std::string::npos); | |
85 } | 81 } |
86 | 82 |
87 TEST_F(UserCollectorTest, DisableOK) { | 83 TEST_F(UserCollectorTest, DisableOK) { |
88 ASSERT_TRUE(collector_.Disable()); | 84 ASSERT_TRUE(collector_.Disable()); |
89 ExpectFileEquals("core", "test/core_pattern"); | 85 ExpectFileEquals("core", "test/core_pattern"); |
90 ASSERT_EQ(s_crashes, 0); | 86 ASSERT_EQ(s_crashes, 0); |
91 ASSERT_NE(logging_.log().find("Disabling user crash handling"), | 87 EXPECT_TRUE(FindLog("Disabling user crash handling")); |
92 std::string::npos); | |
93 } | 88 } |
94 | 89 |
95 TEST_F(UserCollectorTest, DisableNoFileAccess) { | 90 TEST_F(UserCollectorTest, DisableNoFileAccess) { |
96 collector_.set_core_pattern_file("/does_not_exist"); | 91 collector_.set_core_pattern_file("/does_not_exist"); |
97 ASSERT_FALSE(collector_.Disable()); | 92 ASSERT_FALSE(collector_.Disable()); |
98 ASSERT_EQ(s_crashes, 0); | 93 ASSERT_EQ(s_crashes, 0); |
99 ASSERT_NE(logging_.log().find("Disabling user crash handling"), | 94 EXPECT_TRUE(FindLog("Disabling user crash handling")); |
100 std::string::npos); | 95 EXPECT_TRUE(FindLog("Unable to write /does_not_exist")); |
101 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), | |
102 std::string::npos); | |
103 } | 96 } |
104 | 97 |
105 TEST_F(UserCollectorTest, ParseCrashAttributes) { | 98 TEST_F(UserCollectorTest, ParseCrashAttributes) { |
106 pid_t pid; | 99 pid_t pid; |
107 int signal; | 100 int signal; |
108 std::string exec_name; | 101 std::string exec_name; |
109 EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:foobar", | 102 EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:foobar", |
110 &pid, &signal, &exec_name)); | 103 &pid, &signal, &exec_name)); |
111 EXPECT_EQ(123456, pid); | 104 EXPECT_EQ(123456, pid); |
112 EXPECT_EQ(11, signal); | 105 EXPECT_EQ(11, signal); |
(...skipping 12 matching lines...) Loading... |
125 EXPECT_FALSE(collector_.ParseCrashAttributes("123456:1 :foobar", | 118 EXPECT_FALSE(collector_.ParseCrashAttributes("123456:1 :foobar", |
126 &pid, &signal, &exec_name)); | 119 &pid, &signal, &exec_name)); |
127 | 120 |
128 EXPECT_FALSE(collector_.ParseCrashAttributes("123456::foobar", | 121 EXPECT_FALSE(collector_.ParseCrashAttributes("123456::foobar", |
129 &pid, &signal, &exec_name)); | 122 &pid, &signal, &exec_name)); |
130 } | 123 } |
131 | 124 |
132 TEST_F(UserCollectorTest, HandleCrashWithoutMetrics) { | 125 TEST_F(UserCollectorTest, HandleCrashWithoutMetrics) { |
133 s_metrics = false; | 126 s_metrics = false; |
134 collector_.HandleCrash("20:10:ignored", "foobar"); | 127 collector_.HandleCrash("20:10:ignored", "foobar"); |
135 ASSERT_NE(std::string::npos, | 128 EXPECT_TRUE(FindLog( |
136 logging_.log().find( | 129 "Received crash notification for foobar[20] sig 10")); |
137 "Received crash notification for foobar[20] sig 10")); | |
138 ASSERT_EQ(s_crashes, 0); | 130 ASSERT_EQ(s_crashes, 0); |
139 } | 131 } |
140 | 132 |
141 TEST_F(UserCollectorTest, HandleNonChromeCrashWithMetrics) { | 133 TEST_F(UserCollectorTest, HandleNonChromeCrashWithMetrics) { |
142 s_metrics = true; | 134 s_metrics = true; |
143 collector_.HandleCrash("5:2:ignored", "chromeos-wm"); | 135 collector_.HandleCrash("5:2:ignored", "chromeos-wm"); |
144 ASSERT_NE(std::string::npos, | 136 EXPECT_TRUE(FindLog( |
145 logging_.log().find( | 137 "Received crash notification for chromeos-wm[5] sig 2")); |
146 "Received crash notification for chromeos-wm[5] sig 2")); | |
147 ASSERT_EQ(s_crashes, 1); | 138 ASSERT_EQ(s_crashes, 1); |
148 } | 139 } |
149 | 140 |
150 TEST_F(UserCollectorTest, HandleChromeCrashWithMetrics) { | 141 TEST_F(UserCollectorTest, HandleChromeCrashWithMetrics) { |
151 s_metrics = true; | 142 s_metrics = true; |
152 collector_.HandleCrash("5:2:ignored", "chrome"); | 143 collector_.HandleCrash("5:2:ignored", "chrome"); |
153 ASSERT_NE(std::string::npos, | 144 EXPECT_TRUE(FindLog( |
154 logging_.log().find( | 145 "Received crash notification for chrome[5] sig 2")); |
155 "Received crash notification for chrome[5] sig 2")); | 146 EXPECT_TRUE(FindLog("(ignoring - chrome crash)")); |
156 ASSERT_NE(std::string::npos, | |
157 logging_.log().find("(ignoring - chrome crash)")); | |
158 ASSERT_EQ(s_crashes, 0); | 147 ASSERT_EQ(s_crashes, 0); |
159 } | 148 } |
160 | 149 |
161 TEST_F(UserCollectorTest, HandleSuppliedChromeCrashWithMetrics) { | 150 TEST_F(UserCollectorTest, HandleSuppliedChromeCrashWithMetrics) { |
162 s_metrics = true; | 151 s_metrics = true; |
163 collector_.HandleCrash("0:2:chrome", NULL); | 152 collector_.HandleCrash("0:2:chrome", NULL); |
164 ASSERT_NE(std::string::npos, | 153 EXPECT_TRUE(FindLog( |
165 logging_.log().find( | 154 "Received crash notification for supplied_chrome[0] sig 2")); |
166 "Received crash notification for supplied_chrome[0] sig 2")); | 155 EXPECT_TRUE(FindLog("(ignoring - chrome crash)")); |
167 ASSERT_NE(std::string::npos, | |
168 logging_.log().find("(ignoring - chrome crash)")); | |
169 ASSERT_EQ(s_crashes, 0); | 156 ASSERT_EQ(s_crashes, 0); |
170 } | 157 } |
171 | 158 |
172 TEST_F(UserCollectorTest, GetProcessPath) { | 159 TEST_F(UserCollectorTest, GetProcessPath) { |
173 FilePath path = collector_.GetProcessPath(100); | 160 FilePath path = collector_.GetProcessPath(100); |
174 ASSERT_EQ("/proc/100", path.value()); | 161 ASSERT_EQ("/proc/100", path.value()); |
175 } | 162 } |
176 | 163 |
177 TEST_F(UserCollectorTest, GetSymlinkTarget) { | 164 TEST_F(UserCollectorTest, GetSymlinkTarget) { |
178 FilePath result; | 165 FilePath result; |
179 ASSERT_FALSE(collector_.GetSymlinkTarget(FilePath("/does_not_exist"), | 166 ASSERT_FALSE(collector_.GetSymlinkTarget(FilePath("/does_not_exist"), |
180 &result)); | 167 &result)); |
181 ASSERT_NE(std::string::npos, | 168 ASSERT_TRUE(FindLog( |
182 logging_.log().find( | 169 "Readlink failed on /does_not_exist with 2")); |
183 "Readlink failed on /does_not_exist with 2")); | |
184 std::string long_link; | 170 std::string long_link; |
185 for (int i = 0; i < 50; ++i) | 171 for (int i = 0; i < 50; ++i) |
186 long_link += "0123456789"; | 172 long_link += "0123456789"; |
187 long_link += "/gold"; | 173 long_link += "/gold"; |
188 | 174 |
189 for (size_t len = 1; len <= long_link.size(); ++len) { | 175 for (size_t len = 1; len <= long_link.size(); ++len) { |
190 std::string this_link; | 176 std::string this_link; |
191 static const char kLink[] = "test/this_link"; | 177 static const char kLink[] = "test/this_link"; |
192 this_link.assign(long_link.c_str(), len); | 178 this_link.assign(long_link.c_str(), len); |
193 ASSERT_EQ(len, this_link.size()); | 179 ASSERT_EQ(len, this_link.size()); |
194 unlink(kLink); | 180 unlink(kLink); |
195 ASSERT_EQ(0, symlink(this_link.c_str(), kLink)); | 181 ASSERT_EQ(0, symlink(this_link.c_str(), kLink)); |
196 ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result)); | 182 ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result)); |
197 ASSERT_EQ(this_link, result.value()); | 183 ASSERT_EQ(this_link, result.value()); |
198 } | 184 } |
199 } | 185 } |
200 | 186 |
201 TEST_F(UserCollectorTest, GetExecutableBaseNameFromPid) { | 187 TEST_F(UserCollectorTest, GetExecutableBaseNameFromPid) { |
202 std::string base_name; | 188 std::string base_name; |
203 EXPECT_FALSE(collector_.GetExecutableBaseNameFromPid(0, &base_name)); | 189 EXPECT_FALSE(collector_.GetExecutableBaseNameFromPid(0, &base_name)); |
204 EXPECT_NE(std::string::npos, | 190 EXPECT_TRUE(FindLog( |
205 logging_.log().find( | 191 "Readlink failed on /proc/0/exe with 2")); |
206 "Readlink failed on /proc/0/exe with 2")); | 192 EXPECT_TRUE(FindLog( |
207 EXPECT_NE(std::string::npos, | 193 "GetSymlinkTarget failed - Path /proc/0 DirectoryExists: 0")); |
208 logging_.log().find( | 194 EXPECT_TRUE(FindLog("stat /proc/0/exe failed: -1 2")); |
209 "GetSymlinkTarget failed - Path " | |
210 "/proc/0 DirectoryExists: 0")); | |
211 EXPECT_NE(std::string::npos, | |
212 logging_.log().find( | |
213 "stat /proc/0/exe failed: -1 2")); | |
214 | 195 |
215 logging_.clear(); | 196 chromeos::ClearLog(); |
216 pid_t my_pid = getpid(); | 197 pid_t my_pid = getpid(); |
217 EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name)); | 198 EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name)); |
218 EXPECT_EQ(std::string::npos, | 199 EXPECT_FALSE(FindLog("Readlink failed")); |
219 logging_.log().find( | |
220 "Readlink failed")); | |
221 EXPECT_EQ("user_collector_test", base_name); | 200 EXPECT_EQ("user_collector_test", base_name); |
222 } | 201 } |
223 | 202 |
224 TEST_F(UserCollectorTest, GetIdFromStatus) { | 203 TEST_F(UserCollectorTest, GetIdFromStatus) { |
225 int id = 1; | 204 int id = 1; |
226 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, | 205 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, |
227 UserCollector::kIdEffective, | 206 UserCollector::kIdEffective, |
228 "nothing here", | 207 "nothing here", |
229 &id)); | 208 &id)); |
230 EXPECT_EQ(id, 1); | 209 EXPECT_EQ(id, 1); |
(...skipping 65 matching lines...) Loading... |
296 gid_t gid = 100; | 275 gid_t gid = 100; |
297 uid_t uid = 100; | 276 uid_t uid = 100; |
298 EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid)); | 277 EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid)); |
299 EXPECT_EQ(0, uid); | 278 EXPECT_EQ(0, uid); |
300 EXPECT_EQ(0, gid); | 279 EXPECT_EQ(0, gid); |
301 } | 280 } |
302 | 281 |
303 TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) { | 282 TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) { |
304 // Try a path that is not writable. | 283 // Try a path that is not writable. |
305 ASSERT_FALSE(collector_.CopyOffProcFiles(pid_, FilePath("/bad/path"))); | 284 ASSERT_FALSE(collector_.CopyOffProcFiles(pid_, FilePath("/bad/path"))); |
306 ASSERT_NE(logging_.log().find( | 285 EXPECT_TRUE(FindLog("Could not create /bad/path")); |
307 "Could not create /bad/path"), | |
308 std::string::npos); | |
309 } | 286 } |
310 | 287 |
311 TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) { | 288 TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) { |
312 FilePath container_path("test/container"); | 289 FilePath container_path("test/container"); |
313 ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path)); | 290 ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path)); |
314 ASSERT_NE(logging_.log().find( | 291 EXPECT_TRUE(FindLog("Path /proc/0 does not exist")); |
315 "Path /proc/0 does not exist"), | |
316 std::string::npos); | |
317 } | 292 } |
318 | 293 |
319 TEST_F(UserCollectorTest, CopyOffProcFilesOK) { | 294 TEST_F(UserCollectorTest, CopyOffProcFilesOK) { |
320 FilePath container_path("test/container"); | 295 FilePath container_path("test/container"); |
321 ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path)); | 296 ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path)); |
322 ASSERT_EQ(logging_.log().find( | 297 EXPECT_FALSE(FindLog("Could not copy")); |
323 "Could not copy"), std::string::npos); | |
324 static struct { | 298 static struct { |
325 const char *name; | 299 const char *name; |
326 bool exists; | 300 bool exists; |
327 } expectations[] = { | 301 } expectations[] = { |
328 { "auxv", true }, | 302 { "auxv", true }, |
329 { "cmdline", true }, | 303 { "cmdline", true }, |
330 { "environ", true }, | 304 { "environ", true }, |
331 { "maps", true }, | 305 { "maps", true }, |
332 { "mem", false }, | 306 { "mem", false }, |
333 { "mounts", false }, | 307 { "mounts", false }, |
334 { "sched", false }, | 308 { "sched", false }, |
335 { "status", true } | 309 { "status", true } |
336 }; | 310 }; |
337 for (unsigned i = 0; i < sizeof(expectations)/sizeof(expectations[0]); ++i) { | 311 for (unsigned i = 0; i < sizeof(expectations)/sizeof(expectations[0]); ++i) { |
338 EXPECT_EQ(expectations[i].exists, | 312 EXPECT_EQ(expectations[i].exists, |
339 file_util::PathExists( | 313 file_util::PathExists( |
340 container_path.Append(expectations[i].name))); | 314 container_path.Append(expectations[i].name))); |
341 } | 315 } |
342 } | 316 } |
343 | 317 |
344 int main(int argc, char **argv) { | 318 int main(int argc, char **argv) { |
345 ::testing::InitGoogleTest(&argc, argv); | 319 SetUpTests(&argc, argv, false); |
346 return RUN_ALL_TESTS(); | 320 return RUN_ALL_TESTS(); |
347 } | 321 } |
OLD | NEW |