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 <gflags/gflags.h> | 5 #include <unistd.h> |
6 #include <gtest/gtest.h> | |
7 | 6 |
8 #include "base/file_util.h" | 7 #include "base/file_util.h" |
9 #include "crash-reporter/system_logging_mock.h" | 8 #include "crash-reporter/system_logging_mock.h" |
10 #include "crash-reporter/user_collector.h" | 9 #include "crash-reporter/user_collector.h" |
| 10 #include "gflags/gflags.h" |
| 11 #include "gtest/gtest.h" |
11 | 12 |
12 int s_crashes = 0; | 13 int s_crashes = 0; |
13 bool s_metrics = false; | 14 bool s_metrics = false; |
14 | 15 |
15 static const char kFilePath[] = "/my/path"; | 16 static const char kFilePath[] = "/my/path"; |
16 | 17 |
17 void CountCrash() { | 18 void CountCrash() { |
18 ++s_crashes; | 19 ++s_crashes; |
19 } | 20 } |
20 | 21 |
21 bool IsMetrics() { | 22 bool IsMetrics() { |
22 return s_metrics; | 23 return s_metrics; |
23 } | 24 } |
24 | 25 |
25 class UserCollectorTest : public ::testing::Test { | 26 class UserCollectorTest : public ::testing::Test { |
26 void SetUp() { | 27 void SetUp() { |
27 s_crashes = 0; | 28 s_crashes = 0; |
28 collector_.Initialize(CountCrash, | 29 collector_.Initialize(CountCrash, |
29 kFilePath, | 30 kFilePath, |
30 IsMetrics, | 31 IsMetrics, |
31 &logging_); | 32 &logging_, |
| 33 false); |
32 mkdir("test", 0777); | 34 mkdir("test", 0777); |
33 collector_.set_core_pattern_file("test/core_pattern"); | 35 collector_.set_core_pattern_file("test/core_pattern"); |
| 36 pid_ = getpid(); |
34 } | 37 } |
35 protected: | 38 protected: |
| 39 void TestEnableOK(bool generate_diagnostics); |
| 40 |
36 SystemLoggingMock logging_; | 41 SystemLoggingMock logging_; |
37 UserCollector collector_; | 42 UserCollector collector_; |
| 43 pid_t pid_; |
38 }; | 44 }; |
39 | 45 |
40 TEST_F(UserCollectorTest, EnableOK) { | 46 TEST_F(UserCollectorTest, EnableOK) { |
41 std::string contents; | 47 std::string contents; |
42 ASSERT_TRUE(collector_.Enable()); | 48 ASSERT_TRUE(collector_.Enable()); |
43 ASSERT_TRUE(file_util::ReadFileToString(FilePath("test/core_pattern"), | 49 ASSERT_TRUE(file_util::ReadFileToString(FilePath("test/core_pattern"), |
44 &contents)); | 50 &contents)); |
45 ASSERT_STREQ(contents.c_str(), | 51 ASSERT_EQ("|/my/path --signal=%s --pid=%p", contents); |
46 "|/my/path --signal=%s --pid=%p --exec=%e"); | |
47 ASSERT_EQ(s_crashes, 0); | 52 ASSERT_EQ(s_crashes, 0); |
48 ASSERT_NE(logging_.log().find("Enabling crash handling"), std::string::npos); | 53 ASSERT_NE(logging_.log().find("Enabling crash handling"), std::string::npos); |
49 } | 54 } |
50 | 55 |
51 TEST_F(UserCollectorTest, EnableNoFileAccess) { | 56 TEST_F(UserCollectorTest, EnableNoFileAccess) { |
52 collector_.set_core_pattern_file("/does_not_exist"); | 57 collector_.set_core_pattern_file("/does_not_exist"); |
53 ASSERT_FALSE(collector_.Enable()); | 58 ASSERT_FALSE(collector_.Enable()); |
54 ASSERT_EQ(s_crashes, 0); | 59 ASSERT_EQ(s_crashes, 0); |
55 ASSERT_NE(logging_.log().find("Enabling crash handling"), std::string::npos); | 60 ASSERT_NE(logging_.log().find("Enabling crash handling"), std::string::npos); |
56 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), | 61 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), |
57 std::string::npos); | 62 std::string::npos); |
58 } | 63 } |
59 | 64 |
60 TEST_F(UserCollectorTest, DisableOK) { | 65 TEST_F(UserCollectorTest, DisableOK) { |
61 std::string contents; | 66 std::string contents; |
62 ASSERT_TRUE(collector_.Disable()); | 67 ASSERT_TRUE(collector_.Disable()); |
63 ASSERT_TRUE(file_util::ReadFileToString(FilePath("test/core_pattern"), | 68 ASSERT_TRUE(file_util::ReadFileToString(FilePath("test/core_pattern"), |
64 &contents)); | 69 &contents)); |
65 ASSERT_STREQ(contents.c_str(), "core"); | 70 ASSERT_EQ("core", contents); |
66 ASSERT_EQ(s_crashes, 0); | 71 ASSERT_EQ(s_crashes, 0); |
67 ASSERT_NE(logging_.log().find("Disabling crash handling"), | 72 ASSERT_NE(logging_.log().find("Disabling crash handling"), |
68 std::string::npos); | 73 std::string::npos); |
69 } | 74 } |
70 | 75 |
71 TEST_F(UserCollectorTest, DisableNoFileAccess) { | 76 TEST_F(UserCollectorTest, DisableNoFileAccess) { |
72 collector_.set_core_pattern_file("/does_not_exist"); | 77 collector_.set_core_pattern_file("/does_not_exist"); |
73 ASSERT_FALSE(collector_.Disable()); | 78 ASSERT_FALSE(collector_.Disable()); |
74 ASSERT_EQ(s_crashes, 0); | 79 ASSERT_EQ(s_crashes, 0); |
75 ASSERT_NE(logging_.log().find("Disabling crash handling"), std::string::npos); | 80 ASSERT_NE(logging_.log().find("Disabling crash handling"), std::string::npos); |
76 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), | 81 ASSERT_NE(logging_.log().find("Unable to write /does_not_exist"), |
77 std::string::npos); | 82 std::string::npos); |
78 } | 83 } |
79 | 84 |
80 | |
81 TEST_F(UserCollectorTest, HandleCrashWithoutMetrics) { | 85 TEST_F(UserCollectorTest, HandleCrashWithoutMetrics) { |
82 s_metrics = false; | 86 s_metrics = false; |
83 collector_.HandleCrash(10, 20, "foobar"); | 87 collector_.HandleCrash(10, 20, "foobar"); |
84 ASSERT_NE(logging_.log().find( | 88 ASSERT_NE(logging_.log().find( |
85 "Received crash notification for foobar[20] sig 10"), | 89 "Received crash notification for foobar[20] sig 10"), |
86 std::string::npos); | 90 std::string::npos); |
87 ASSERT_EQ(s_crashes, 0); | 91 ASSERT_EQ(s_crashes, 0); |
88 } | 92 } |
89 | 93 |
90 TEST_F(UserCollectorTest, HandleCrashWithMetrics) { | 94 TEST_F(UserCollectorTest, HandleCrashWithMetrics) { |
91 s_metrics = true; | 95 s_metrics = true; |
92 collector_.HandleCrash(2, 5, "chrome"); | 96 collector_.HandleCrash(2, 5, "chrome"); |
93 ASSERT_NE(logging_.log().find( | 97 ASSERT_NE(logging_.log().find( |
94 "Received crash notification for chrome[5] sig 2"), | 98 "Received crash notification for chrome[5] sig 2"), |
95 std::string::npos); | 99 std::string::npos); |
96 ASSERT_EQ(s_crashes, 1); | 100 ASSERT_EQ(s_crashes, 1); |
97 } | 101 } |
98 | 102 |
| 103 TEST_F(UserCollectorTest, GetProcessPath) { |
| 104 FilePath path = collector_.GetProcessPath(100); |
| 105 ASSERT_EQ("/proc/100", path.value()); |
| 106 } |
| 107 |
| 108 TEST_F(UserCollectorTest, GetSymlinkTarget) { |
| 109 FilePath result; |
| 110 ASSERT_FALSE(collector_.GetSymlinkTarget(FilePath("/does_not_exist"), |
| 111 &result)); |
| 112 |
| 113 std::string long_link; |
| 114 for (int i = 0; i < 50; ++i) |
| 115 long_link += "0123456789"; |
| 116 long_link += "/gold"; |
| 117 |
| 118 for (size_t len = 1; len <= long_link.size(); ++len) { |
| 119 std::string this_link; |
| 120 static const char kLink[] = "test/this_link"; |
| 121 this_link.assign(long_link.c_str(), len); |
| 122 ASSERT_EQ(len, this_link.size()); |
| 123 unlink(kLink); |
| 124 ASSERT_EQ(0, symlink(this_link.c_str(), kLink)); |
| 125 ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result)); |
| 126 ASSERT_EQ(this_link, result.value()); |
| 127 } |
| 128 } |
| 129 |
| 130 TEST_F(UserCollectorTest, GetIdFromStatus) { |
| 131 int id = 1; |
| 132 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 133 UserCollector::kIdEffective, |
| 134 "nothing here", |
| 135 &id)); |
| 136 EXPECT_EQ(id, 1); |
| 137 |
| 138 // Not enough parameters. |
| 139 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 140 UserCollector::kIdReal, |
| 141 "line 1\nUid:\t1\n", &id)); |
| 142 |
| 143 const char valid_contents[] = "\nUid:\t1\t2\t3\t4\nGid:\t5\t6\t7\t8\n"; |
| 144 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 145 UserCollector::kIdReal, |
| 146 valid_contents, |
| 147 &id)); |
| 148 EXPECT_EQ(1, id); |
| 149 |
| 150 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 151 UserCollector::kIdEffective, |
| 152 valid_contents, |
| 153 &id)); |
| 154 EXPECT_EQ(2, id); |
| 155 |
| 156 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 157 UserCollector::kIdFileSystem, |
| 158 valid_contents, |
| 159 &id)); |
| 160 EXPECT_EQ(4, id); |
| 161 |
| 162 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId, |
| 163 UserCollector::kIdEffective, |
| 164 valid_contents, |
| 165 &id)); |
| 166 EXPECT_EQ(6, id); |
| 167 |
| 168 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId, |
| 169 UserCollector::kIdSet, |
| 170 valid_contents, |
| 171 &id)); |
| 172 EXPECT_EQ(7, id); |
| 173 |
| 174 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId, |
| 175 UserCollector::IdKind(5), |
| 176 valid_contents, |
| 177 &id)); |
| 178 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId, |
| 179 UserCollector::IdKind(-1), |
| 180 valid_contents, |
| 181 &id)); |
| 182 |
| 183 // Fail if junk after number |
| 184 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 185 UserCollector::kIdReal, |
| 186 "Uid:\t1f\t2\t3\t4\n", |
| 187 &id)); |
| 188 EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 189 UserCollector::kIdReal, |
| 190 "Uid:\t1\t2\t3\t4\n", |
| 191 &id)); |
| 192 EXPECT_EQ(1, id); |
| 193 |
| 194 // Fail if more than 4 numbers. |
| 195 EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId, |
| 196 UserCollector::kIdReal, |
| 197 "Uid:\t1\t2\t3\t4\t5\n", |
| 198 &id)); |
| 199 } |
| 200 |
| 201 TEST_F(UserCollectorTest, GetUserInfoFromName) { |
| 202 gid_t gid = 100; |
| 203 uid_t uid = 100; |
| 204 EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid)); |
| 205 EXPECT_EQ(0, uid); |
| 206 EXPECT_EQ(0, gid); |
| 207 } |
| 208 |
| 209 TEST_F(UserCollectorTest, GetCrashDirectoryInfo) { |
| 210 FilePath path; |
| 211 const int kRootUid = 0; |
| 212 const int kRootGid = 0; |
| 213 const int kNtpUid = 5; |
| 214 const int kChronosUid = 1000; |
| 215 const int kChronosGid = 1001; |
| 216 const mode_t kExpectedSystemMode = 01755; |
| 217 const mode_t kExpectedUserMode = 0755; |
| 218 |
| 219 mode_t directory_mode; |
| 220 uid_t directory_owner; |
| 221 gid_t directory_group; |
| 222 |
| 223 path = collector_.GetCrashDirectoryInfo(kRootUid, |
| 224 kChronosUid, |
| 225 kChronosGid, |
| 226 &directory_mode, |
| 227 &directory_owner, |
| 228 &directory_group); |
| 229 EXPECT_EQ("/var/spool/crash", path.value()); |
| 230 EXPECT_EQ(kExpectedSystemMode, directory_mode); |
| 231 EXPECT_EQ(kRootUid, directory_owner); |
| 232 EXPECT_EQ(kRootGid, directory_group); |
| 233 |
| 234 path = collector_.GetCrashDirectoryInfo(kNtpUid, |
| 235 kChronosUid, |
| 236 kChronosGid, |
| 237 &directory_mode, |
| 238 &directory_owner, |
| 239 &directory_group); |
| 240 EXPECT_EQ("/var/spool/crash", path.value()); |
| 241 EXPECT_EQ(kExpectedSystemMode, directory_mode); |
| 242 EXPECT_EQ(kRootUid, directory_owner); |
| 243 EXPECT_EQ(kRootGid, directory_group); |
| 244 |
| 245 path = collector_.GetCrashDirectoryInfo(kChronosUid, |
| 246 kChronosUid, |
| 247 kChronosGid, |
| 248 &directory_mode, |
| 249 &directory_owner, |
| 250 &directory_group); |
| 251 EXPECT_EQ("/home/chronos/user/crash", path.value()); |
| 252 EXPECT_EQ(kExpectedUserMode, directory_mode); |
| 253 EXPECT_EQ(kChronosUid, directory_owner); |
| 254 EXPECT_EQ(kChronosGid, directory_group); |
| 255 } |
| 256 |
| 257 TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) { |
| 258 // Try a path that is not writable. |
| 259 ASSERT_FALSE(collector_.CopyOffProcFiles(pid_, FilePath("/bad/path"))); |
| 260 ASSERT_NE(logging_.log().find( |
| 261 "Could not create /bad/path"), |
| 262 std::string::npos); |
| 263 } |
| 264 |
| 265 TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) { |
| 266 FilePath container_path("test/container"); |
| 267 ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path)); |
| 268 ASSERT_NE(logging_.log().find( |
| 269 "Path /proc/0 does not exist"), |
| 270 std::string::npos); |
| 271 } |
| 272 |
| 273 TEST_F(UserCollectorTest, CopyOffProcFilesOK) { |
| 274 FilePath container_path("test/container"); |
| 275 ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path)); |
| 276 ASSERT_EQ(logging_.log().find( |
| 277 "Could not copy"), std::string::npos); |
| 278 static struct { |
| 279 const char *name; |
| 280 bool exists; |
| 281 } expectations[] = { |
| 282 { "auxv", true }, |
| 283 { "cmdline", true }, |
| 284 { "environ", true }, |
| 285 { "maps", true }, |
| 286 { "mem", false }, |
| 287 { "mounts", false }, |
| 288 { "sched", false }, |
| 289 { "status", true } |
| 290 }; |
| 291 for (unsigned i = 0; i < sizeof(expectations)/sizeof(expectations[0]); ++i) { |
| 292 EXPECT_EQ(expectations[i].exists, |
| 293 file_util::PathExists( |
| 294 container_path.Append(expectations[i].name))); |
| 295 } |
| 296 } |
| 297 |
| 298 TEST_F(UserCollectorTest, FormatDumpBasename) { |
| 299 struct tm tm = {0}; |
| 300 tm.tm_sec = 15; |
| 301 tm.tm_min = 50; |
| 302 tm.tm_hour = 13; |
| 303 tm.tm_mday = 23; |
| 304 tm.tm_mon = 4; |
| 305 tm.tm_year = 110; |
| 306 tm.tm_isdst = -1; |
| 307 std::string basename = |
| 308 collector_.FormatDumpBasename("foo", mktime(&tm), 100); |
| 309 ASSERT_EQ("foo.20100523.135015.100", basename); |
| 310 } |
| 311 |
99 int main(int argc, char **argv) { | 312 int main(int argc, char **argv) { |
100 ::testing::InitGoogleTest(&argc, argv); | 313 ::testing::InitGoogleTest(&argc, argv); |
101 return RUN_ALL_TESTS(); | 314 return RUN_ALL_TESTS(); |
102 } | 315 } |
OLD | NEW |