| 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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 |