blob: 7f1d4c23044dadff383607b8588a32157ec21e47 [file] [log] [blame]
Ken Mixter03403162010-08-18 15:23:16 -07001// 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
3// found in the LICENSE file.
4
5#include <unistd.h>
6
7#include "base/file_util.h"
Ken Mixter04ec10f2010-08-26 16:02:02 -07008#include "base/string_util.h"
Ken Mixter03403162010-08-18 15:23:16 -07009#include "crash-reporter/crash_collector.h"
10#include "crash-reporter/system_logging_mock.h"
Ken Mixter9b346472010-11-07 13:45:45 -080011#include "crash-reporter/test_helpers.h"
Ken Mixter03403162010-08-18 15:23:16 -070012#include "gflags/gflags.h"
13#include "gtest/gtest.h"
14
Ken Mixter9b346472010-11-07 13:45:45 -080015// This test assumes the following standard binaries are installed.
16static const char kBinBash[] = "/bin/bash";
17static const char kBinCp[] = "/bin/cp";
18static const char kBinEcho[] = "/bin/echo";
19static const char kBinFalse[] = "/bin/false";
20
Ken Mixter03403162010-08-18 15:23:16 -070021void CountCrash() {
22 ADD_FAILURE();
23}
24
25bool IsMetrics() {
26 ADD_FAILURE();
27 return false;
28}
29
30class CrashCollectorTest : public ::testing::Test {
Ken Mixter04ec10f2010-08-26 16:02:02 -070031 public:
Ken Mixter03403162010-08-18 15:23:16 -070032 void SetUp() {
33 collector_.Initialize(CountCrash,
34 IsMetrics,
35 &logging_);
Ken Mixter04ec10f2010-08-26 16:02:02 -070036 test_dir_ = FilePath("test");
37 file_util::CreateDirectory(test_dir_);
Ken Mixter03403162010-08-18 15:23:16 -070038 }
Ken Mixter04ec10f2010-08-26 16:02:02 -070039
40 void TearDown() {
41 file_util::Delete(test_dir_, true);
42 }
43
44 bool CheckHasCapacity();
45
Ken Mixter03403162010-08-18 15:23:16 -070046 protected:
47 SystemLoggingMock logging_;
48 CrashCollector collector_;
Ken Mixter04ec10f2010-08-26 16:02:02 -070049 FilePath test_dir_;
Ken Mixter03403162010-08-18 15:23:16 -070050};
51
52TEST_F(CrashCollectorTest, Initialize) {
53 ASSERT_TRUE(CountCrash == collector_.count_crash_function_);
54 ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_);
55 ASSERT_TRUE(&logging_ == collector_.logger_);
56}
57
Ken Mixter9b346472010-11-07 13:45:45 -080058TEST_F(CrashCollectorTest, WriteNewFile) {
59 FilePath test_file = test_dir_.Append("test_new");
60 const char kBuffer[] = "buffer";
61 EXPECT_EQ(strlen(kBuffer),
62 collector_.WriteNewFile(test_file,
63 kBuffer,
64 strlen(kBuffer)));
65 EXPECT_LT(collector_.WriteNewFile(test_file,
66 kBuffer,
67 strlen(kBuffer)), 0);
68}
69
70TEST_F(CrashCollectorTest, ForkExecAndPipe) {
71 std::vector<const char *> args;
72 char output_file[] = "test/fork_out";
73
74 // Test basic call with stdout.
75 args.clear();
76 args.push_back(kBinEcho);
77 args.push_back("hello world");
78 EXPECT_EQ(0, collector_.ForkExecAndPipe(args, output_file));
79 ExpectFileEquals("hello world\n", output_file);
80 EXPECT_EQ("", logging_.log());
81
82 // Test non-zero return value
83 logging_.clear();
84 args.clear();
85 args.push_back(kBinFalse);
86 EXPECT_EQ(1, collector_.ForkExecAndPipe(args, output_file));
87 ExpectFileEquals("", output_file);
88 EXPECT_EQ("", logging_.log());
89
90 // Test bad output_file.
91 EXPECT_EQ(127, collector_.ForkExecAndPipe(args, "/bad/path"));
92
93 // Test bad executable.
94 logging_.clear();
95 args.clear();
96 args.push_back("false");
97 EXPECT_EQ(127, collector_.ForkExecAndPipe(args, output_file));
98
99 // Test stderr captured.
100 std::string contents;
101 logging_.clear();
102 args.clear();
103 args.push_back(kBinCp);
104 EXPECT_EQ(1, collector_.ForkExecAndPipe(args, output_file));
105 EXPECT_TRUE(file_util::ReadFileToString(FilePath(output_file),
106 &contents));
107 EXPECT_NE(std::string::npos, contents.find("missing file operand"));
108 EXPECT_EQ("", logging_.log());
109
110 // NULL parameter.
111 logging_.clear();
112 args.clear();
113 args.push_back(NULL);
114 EXPECT_EQ(-1, collector_.ForkExecAndPipe(args, output_file));
115 EXPECT_NE(std::string::npos,
116 logging_.log().find("Bad parameter"));
117
118 // No parameters.
119 args.clear();
120 EXPECT_EQ(127, collector_.ForkExecAndPipe(args, output_file));
121
122 // Segmentation faulting process.
123 logging_.clear();
124 args.clear();
125 args.push_back(kBinBash);
126 args.push_back("-c");
127 args.push_back("kill -SEGV $$");
128 EXPECT_EQ(-1, collector_.ForkExecAndPipe(args, output_file));
129 EXPECT_NE(std::string::npos,
130 logging_.log().find("Process did not exit normally"));
131}
132
Ken Mixteree849c52010-09-30 15:30:10 -0700133TEST_F(CrashCollectorTest, Sanitize) {
134 EXPECT_EQ("chrome", collector_.Sanitize("chrome"));
135 EXPECT_EQ("CHROME", collector_.Sanitize("CHROME"));
136 EXPECT_EQ("1chrome2", collector_.Sanitize("1chrome2"));
137 EXPECT_EQ("chrome__deleted_", collector_.Sanitize("chrome (deleted)"));
138 EXPECT_EQ("foo_bar", collector_.Sanitize("foo.bar"));
139 EXPECT_EQ("", collector_.Sanitize(""));
140 EXPECT_EQ("_", collector_.Sanitize(" "));
141}
142
Ken Mixter03403162010-08-18 15:23:16 -0700143TEST_F(CrashCollectorTest, GetCrashDirectoryInfo) {
144 FilePath path;
145 const int kRootUid = 0;
146 const int kRootGid = 0;
147 const int kNtpUid = 5;
148 const int kChronosUid = 1000;
149 const int kChronosGid = 1001;
150 const mode_t kExpectedSystemMode = 01755;
151 const mode_t kExpectedUserMode = 0755;
152
153 mode_t directory_mode;
154 uid_t directory_owner;
155 gid_t directory_group;
156
157 path = collector_.GetCrashDirectoryInfo(kRootUid,
158 kChronosUid,
159 kChronosGid,
160 &directory_mode,
161 &directory_owner,
162 &directory_group);
163 EXPECT_EQ("/var/spool/crash", path.value());
164 EXPECT_EQ(kExpectedSystemMode, directory_mode);
165 EXPECT_EQ(kRootUid, directory_owner);
166 EXPECT_EQ(kRootGid, directory_group);
167
168 path = collector_.GetCrashDirectoryInfo(kNtpUid,
169 kChronosUid,
170 kChronosGid,
171 &directory_mode,
172 &directory_owner,
173 &directory_group);
174 EXPECT_EQ("/var/spool/crash", path.value());
175 EXPECT_EQ(kExpectedSystemMode, directory_mode);
176 EXPECT_EQ(kRootUid, directory_owner);
177 EXPECT_EQ(kRootGid, directory_group);
178
179 path = collector_.GetCrashDirectoryInfo(kChronosUid,
180 kChronosUid,
181 kChronosGid,
182 &directory_mode,
183 &directory_owner,
184 &directory_group);
185 EXPECT_EQ("/home/chronos/user/crash", path.value());
186 EXPECT_EQ(kExpectedUserMode, directory_mode);
187 EXPECT_EQ(kChronosUid, directory_owner);
188 EXPECT_EQ(kChronosGid, directory_group);
189}
190
191TEST_F(CrashCollectorTest, FormatDumpBasename) {
192 struct tm tm = {0};
193 tm.tm_sec = 15;
194 tm.tm_min = 50;
195 tm.tm_hour = 13;
196 tm.tm_mday = 23;
197 tm.tm_mon = 4;
198 tm.tm_year = 110;
199 tm.tm_isdst = -1;
200 std::string basename =
201 collector_.FormatDumpBasename("foo", mktime(&tm), 100);
202 ASSERT_EQ("foo.20100523.135015.100", basename);
203}
204
Ken Mixter207694d2010-10-28 15:42:37 -0700205TEST_F(CrashCollectorTest, GetCrashPath) {
206 EXPECT_EQ("/var/spool/crash/myprog.20100101.1200.1234.core",
207 collector_.GetCrashPath(FilePath("/var/spool/crash"),
208 "myprog.20100101.1200.1234",
209 "core").value());
210 EXPECT_EQ("/home/chronos/user/crash/chrome.20100101.1200.1234.dmp",
211 collector_.GetCrashPath(FilePath("/home/chronos/user/crash"),
212 "chrome.20100101.1200.1234",
213 "dmp").value());
214}
215
216
Ken Mixter04ec10f2010-08-26 16:02:02 -0700217bool CrashCollectorTest::CheckHasCapacity() {
218 static const char kFullMessage[] = "Crash directory test already full";
219 bool has_capacity = collector_.CheckHasCapacity(test_dir_);
220 bool has_message = (logging_.log().find(kFullMessage) != std::string::npos);
221 EXPECT_EQ(has_message, !has_capacity);
222 return has_capacity;
223}
224
Ken Mixteree849c52010-09-30 15:30:10 -0700225TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
226 // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700227 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
Ken Mixter04ec10f2010-08-26 16:02:02 -0700228 file_util::WriteFile(test_dir_.Append(StringPrintf("file%d.core", i)),
229 "", 0);
Ken Mixteree849c52010-09-30 15:30:10 -0700230 EXPECT_TRUE(CheckHasCapacity());
Ken Mixter04ec10f2010-08-26 16:02:02 -0700231 }
232
Ken Mixteree849c52010-09-30 15:30:10 -0700233 // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
234 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
235 file_util::WriteFile(test_dir_.Append(StringPrintf("file%d.meta", i)),
236 "", 0);
237 EXPECT_TRUE(CheckHasCapacity());
238 }
239
240 // Test an additional kMaxCrashDirectorySize meta files don't fit.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700241 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
Ken Mixteree849c52010-09-30 15:30:10 -0700242 file_util::WriteFile(test_dir_.Append(StringPrintf("overage%d.meta", i)),
243 "", 0);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700244 EXPECT_FALSE(CheckHasCapacity());
245 }
246}
247
Ken Mixteree849c52010-09-30 15:30:10 -0700248TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
249 // Test kMaxCrashDirectorySize - 1 files can be added.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700250 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
Ken Mixteree849c52010-09-30 15:30:10 -0700251 file_util::WriteFile(test_dir_.Append(StringPrintf("file.%d.core", i)),
Ken Mixter04ec10f2010-08-26 16:02:02 -0700252 "", 0);
Ken Mixteree849c52010-09-30 15:30:10 -0700253 EXPECT_TRUE(CheckHasCapacity());
Ken Mixter04ec10f2010-08-26 16:02:02 -0700254 }
Ken Mixteree849c52010-09-30 15:30:10 -0700255 file_util::WriteFile(test_dir_.Append("file.last.core"), "", 0);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700256 EXPECT_FALSE(CheckHasCapacity());
257}
258
Ken Mixteree849c52010-09-30 15:30:10 -0700259TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
260 // Test many files with different extensions and same base fit.
261 for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
262 file_util::WriteFile(test_dir_.Append(StringPrintf("a.%d", i)), "", 0);
263 EXPECT_TRUE(CheckHasCapacity());
264 }
265 // Test dot files are treated as individual files.
266 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
267 file_util::WriteFile(test_dir_.Append(StringPrintf(".file%d", i)), "", 0);
268 EXPECT_TRUE(CheckHasCapacity());
269 }
270 file_util::WriteFile(test_dir_.Append("normal.meta"), "", 0);
271 EXPECT_FALSE(CheckHasCapacity());
272}
273
Ken Mixterc49dbd42010-12-14 17:44:11 -0800274TEST_F(CrashCollectorTest, IsCommentLine) {
275 EXPECT_FALSE(CrashCollector::IsCommentLine(""));
276 EXPECT_TRUE(CrashCollector::IsCommentLine("#"));
277 EXPECT_TRUE(CrashCollector::IsCommentLine("#real comment"));
278 EXPECT_TRUE(CrashCollector::IsCommentLine(" # real comment"));
279 EXPECT_FALSE(CrashCollector::IsCommentLine("not comment"));
280 EXPECT_FALSE(CrashCollector::IsCommentLine(" not comment"));
281}
282
Ken Mixteree849c52010-09-30 15:30:10 -0700283TEST_F(CrashCollectorTest, ReadKeyValueFile) {
284 const char *contents = ("a=b\n"
285 "\n"
286 " c=d \n");
287 FilePath path(test_dir_.Append("keyval"));
288 std::map<std::string, std::string> dictionary;
289 std::map<std::string, std::string>::iterator i;
290
291 file_util::WriteFile(path, contents, strlen(contents));
292
293 EXPECT_TRUE(collector_.ReadKeyValueFile(path, '=', &dictionary));
294 i = dictionary.find("a");
295 EXPECT_TRUE(i != dictionary.end() && i->second == "b");
296 i = dictionary.find("c");
297 EXPECT_TRUE(i != dictionary.end() && i->second == "d");
298
299 dictionary.clear();
300
301 contents = ("a=b c d\n"
302 "e\n"
303 " f g = h\n"
304 "i=j\n"
305 "=k\n"
Ken Mixterc49dbd42010-12-14 17:44:11 -0800306 "#comment=0\n"
Ken Mixteree849c52010-09-30 15:30:10 -0700307 "l=\n");
308 file_util::WriteFile(path, contents, strlen(contents));
309
310 EXPECT_FALSE(collector_.ReadKeyValueFile(path, '=', &dictionary));
Ken Mixterc49dbd42010-12-14 17:44:11 -0800311 EXPECT_EQ(5, dictionary.size());
312
Ken Mixteree849c52010-09-30 15:30:10 -0700313 i = dictionary.find("a");
314 EXPECT_TRUE(i != dictionary.end() && i->second == "b c d");
315 i = dictionary.find("e");
316 EXPECT_TRUE(i == dictionary.end());
317 i = dictionary.find("f g");
318 EXPECT_TRUE(i != dictionary.end() && i->second == "h");
319 i = dictionary.find("i");
320 EXPECT_TRUE(i != dictionary.end() && i->second == "j");
321 i = dictionary.find("");
322 EXPECT_TRUE(i != dictionary.end() && i->second == "k");
323 i = dictionary.find("l");
324 EXPECT_TRUE(i != dictionary.end() && i->second == "");
325}
326
Ken Mixterafcf8082010-10-26 14:45:01 -0700327TEST_F(CrashCollectorTest, MetaData) {
Ken Mixter9b346472010-11-07 13:45:45 -0800328 const char kMetaFileBasename[] = "generated.meta";
329 FilePath meta_file = test_dir_.Append(kMetaFileBasename);
Ken Mixterafcf8082010-10-26 14:45:01 -0700330 FilePath lsb_release = test_dir_.Append("lsb-release");
331 FilePath payload_file = test_dir_.Append("payload-file");
332 std::string contents;
333 collector_.lsb_release_ = lsb_release.value().c_str();
334 const char kLsbContents[] = "CHROMEOS_RELEASE_VERSION=version\n";
335 ASSERT_TRUE(
336 file_util::WriteFile(lsb_release,
337 kLsbContents, strlen(kLsbContents)));
338 const char kPayload[] = "foo";
339 ASSERT_TRUE(
340 file_util::WriteFile(payload_file,
341 kPayload, strlen(kPayload)));
342 collector_.AddCrashMetaData("foo", "bar");
343 collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
344 EXPECT_TRUE(file_util::ReadFileToString(meta_file, &contents));
Ken Mixter9b346472010-11-07 13:45:45 -0800345 const char kExpectedMeta[] =
346 "foo=bar\n"
347 "exec_name=kernel\n"
348 "ver=version\n"
349 "payload=test/payload-file\n"
350 "payload_size=3\n"
351 "done=1\n";
352 EXPECT_EQ(kExpectedMeta, contents);
353
354 // Test target of symlink is not overwritten.
355 payload_file = test_dir_.Append("payload2-file");
356 ASSERT_TRUE(
357 file_util::WriteFile(payload_file,
358 kPayload, strlen(kPayload)));
359 FilePath meta_symlink_path = test_dir_.Append("symlink.meta");
360 ASSERT_EQ(0,
361 symlink(kMetaFileBasename,
362 meta_symlink_path.value().c_str()));
363 ASSERT_TRUE(file_util::PathExists(meta_symlink_path));
364 logging_.clear();
365 collector_.WriteCrashMetaData(meta_symlink_path,
366 "kernel",
367 payload_file.value());
368 // Target metadata contents sould have stayed the same.
369 contents.clear();
370 EXPECT_TRUE(file_util::ReadFileToString(meta_file, &contents));
371 EXPECT_EQ(kExpectedMeta, contents);
372 EXPECT_NE(std::string::npos, logging_.log().find("Unable to write"));
373
374 // Test target of dangling symlink is not created.
375 file_util::Delete(meta_file, false);
376 ASSERT_FALSE(file_util::PathExists(meta_file));
377 logging_.clear();
378 collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
379 payload_file.value());
380 EXPECT_FALSE(file_util::PathExists(meta_file));
381 EXPECT_NE(std::string::npos, logging_.log().find("Unable to write"));
Ken Mixterafcf8082010-10-26 14:45:01 -0700382}
383
Ken Mixterc49dbd42010-12-14 17:44:11 -0800384TEST_F(CrashCollectorTest, GetLogContents) {
385 FilePath config_file = test_dir_.Append("crash_config");
386 FilePath output_file = test_dir_.Append("crash_log");
387 const char kConfigContents[] =
388 "foobar:echo hello there | sed -e \"s/there/world/\"";
389 ASSERT_TRUE(
390 file_util::WriteFile(config_file,
391 kConfigContents, strlen(kConfigContents)));
392 EXPECT_FALSE(collector_.GetLogContents(config_file,
393 "barfoo",
394 output_file));
395 EXPECT_FALSE(file_util::PathExists(output_file));
396 EXPECT_TRUE(collector_.GetLogContents(config_file,
397 "foobar",
398 output_file));
399 ASSERT_TRUE(file_util::PathExists(output_file));
400 std::string contents;
401 EXPECT_TRUE(file_util::ReadFileToString(output_file, &contents));
402 EXPECT_EQ("hello world\n", contents);
403}
404
Ken Mixter03403162010-08-18 15:23:16 -0700405int main(int argc, char **argv) {
406 ::testing::InitGoogleTest(&argc, argv);
407 return RUN_ALL_TESTS();
408}