blob: b9a48a080712ca2077c6e703a188220c27445859 [file] [log] [blame]
Mike Frysinger57b261c2012-04-11 14:47:09 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ken Mixter03403162010-08-18 15:23:16 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Mike Frysingerf19b5182013-05-17 19:36:47 -04005#include "crash-reporter/crash_collector_test.h"
6
Ken Mixter03403162010-08-18 15:23:16 -07007#include <unistd.h>
8
Mike Frysingerf19b5182013-05-17 19:36:47 -04009#include <dbus/dbus-glib-lowlevel.h>
10#include <glib.h>
11
Ken Mixter03403162010-08-18 15:23:16 -070012#include "base/file_util.h"
Ken Mixter04ec10f2010-08-26 16:02:02 -070013#include "base/string_util.h"
Mike Frysinger57b261c2012-04-11 14:47:09 -040014#include "base/stringprintf.h"
Ken Mixtera3249322011-03-03 08:47:38 -080015#include "chromeos/syslog_logging.h"
16#include "chromeos/test_helpers.h"
Ken Mixter03403162010-08-18 15:23:16 -070017#include "crash-reporter/crash_collector.h"
Ken Mixter03403162010-08-18 15:23:16 -070018#include "gflags/gflags.h"
19#include "gtest/gtest.h"
20
Ken Mixter9b346472010-11-07 13:45:45 -080021// This test assumes the following standard binaries are installed.
22static const char kBinBash[] = "/bin/bash";
23static const char kBinCp[] = "/bin/cp";
24static const char kBinEcho[] = "/bin/echo";
25static const char kBinFalse[] = "/bin/false";
26
Simon Que9f90aca2013-02-19 17:19:52 -080027using base::FilePath;
Ken Mixtera3249322011-03-03 08:47:38 -080028using chromeos::FindLog;
Mike Frysingerf19b5182013-05-17 19:36:47 -040029using ::testing::Return;
Ken Mixtera3249322011-03-03 08:47:38 -080030
Ken Mixter03403162010-08-18 15:23:16 -070031void CountCrash() {
32 ADD_FAILURE();
33}
34
35bool IsMetrics() {
36 ADD_FAILURE();
37 return false;
38}
39
40class CrashCollectorTest : public ::testing::Test {
Ken Mixter04ec10f2010-08-26 16:02:02 -070041 public:
Ken Mixter03403162010-08-18 15:23:16 -070042 void SetUp() {
43 collector_.Initialize(CountCrash,
Ken Mixtera3249322011-03-03 08:47:38 -080044 IsMetrics);
Ken Mixter04ec10f2010-08-26 16:02:02 -070045 test_dir_ = FilePath("test");
46 file_util::CreateDirectory(test_dir_);
Ken Mixtera3249322011-03-03 08:47:38 -080047 chromeos::ClearLog();
Ken Mixter03403162010-08-18 15:23:16 -070048 }
Ken Mixter04ec10f2010-08-26 16:02:02 -070049
50 void TearDown() {
51 file_util::Delete(test_dir_, true);
52 }
53
54 bool CheckHasCapacity();
55
Ken Mixter03403162010-08-18 15:23:16 -070056 protected:
Mike Frysingerf19b5182013-05-17 19:36:47 -040057 CrashCollectorMock collector_;
Ken Mixter04ec10f2010-08-26 16:02:02 -070058 FilePath test_dir_;
Ken Mixter03403162010-08-18 15:23:16 -070059};
60
61TEST_F(CrashCollectorTest, Initialize) {
62 ASSERT_TRUE(CountCrash == collector_.count_crash_function_);
63 ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_);
Ken Mixter03403162010-08-18 15:23:16 -070064}
65
Ken Mixter9b346472010-11-07 13:45:45 -080066TEST_F(CrashCollectorTest, WriteNewFile) {
67 FilePath test_file = test_dir_.Append("test_new");
68 const char kBuffer[] = "buffer";
69 EXPECT_EQ(strlen(kBuffer),
70 collector_.WriteNewFile(test_file,
71 kBuffer,
72 strlen(kBuffer)));
73 EXPECT_LT(collector_.WriteNewFile(test_file,
74 kBuffer,
75 strlen(kBuffer)), 0);
76}
77
Ken Mixteree849c52010-09-30 15:30:10 -070078TEST_F(CrashCollectorTest, Sanitize) {
79 EXPECT_EQ("chrome", collector_.Sanitize("chrome"));
80 EXPECT_EQ("CHROME", collector_.Sanitize("CHROME"));
81 EXPECT_EQ("1chrome2", collector_.Sanitize("1chrome2"));
82 EXPECT_EQ("chrome__deleted_", collector_.Sanitize("chrome (deleted)"));
83 EXPECT_EQ("foo_bar", collector_.Sanitize("foo.bar"));
84 EXPECT_EQ("", collector_.Sanitize(""));
85 EXPECT_EQ("_", collector_.Sanitize(" "));
86}
87
Ken Mixter03403162010-08-18 15:23:16 -070088TEST_F(CrashCollectorTest, GetCrashDirectoryInfo) {
89 FilePath path;
90 const int kRootUid = 0;
91 const int kRootGid = 0;
92 const int kNtpUid = 5;
93 const int kChronosUid = 1000;
94 const int kChronosGid = 1001;
95 const mode_t kExpectedSystemMode = 01755;
96 const mode_t kExpectedUserMode = 0755;
97
98 mode_t directory_mode;
99 uid_t directory_owner;
100 gid_t directory_group;
101
102 path = collector_.GetCrashDirectoryInfo(kRootUid,
103 kChronosUid,
104 kChronosGid,
105 &directory_mode,
106 &directory_owner,
107 &directory_group);
108 EXPECT_EQ("/var/spool/crash", path.value());
109 EXPECT_EQ(kExpectedSystemMode, directory_mode);
110 EXPECT_EQ(kRootUid, directory_owner);
111 EXPECT_EQ(kRootGid, directory_group);
112
113 path = collector_.GetCrashDirectoryInfo(kNtpUid,
114 kChronosUid,
115 kChronosGid,
116 &directory_mode,
117 &directory_owner,
118 &directory_group);
119 EXPECT_EQ("/var/spool/crash", path.value());
120 EXPECT_EQ(kExpectedSystemMode, directory_mode);
121 EXPECT_EQ(kRootUid, directory_owner);
122 EXPECT_EQ(kRootGid, directory_group);
123
Mike Frysingerf19b5182013-05-17 19:36:47 -0400124 // No need to destroy the hash as GetCrashDirectoryInfo() will do it for us.
125 GHashTable *active_sessions = g_hash_table_new (g_str_hash, g_str_equal);
126 char kUser[] = "chicken@butt.com";
127 char kHash[] = "hashcakes";
128 g_hash_table_insert (active_sessions,
129 static_cast<gpointer>(kUser),
130 static_cast<gpointer>(kHash));
131 EXPECT_CALL(collector_, GetActiveUserSessions())
132 .WillOnce(Return(active_sessions));
133
134 EXPECT_EQ(collector_.IsUserSpecificDirectoryEnabled(), true);
135
Ken Mixter03403162010-08-18 15:23:16 -0700136 path = collector_.GetCrashDirectoryInfo(kChronosUid,
137 kChronosUid,
138 kChronosGid,
139 &directory_mode,
140 &directory_owner,
141 &directory_group);
Mike Frysingerf19b5182013-05-17 19:36:47 -0400142 EXPECT_EQ("/home/user/hashcakes", path.value());
Ken Mixter03403162010-08-18 15:23:16 -0700143 EXPECT_EQ(kExpectedUserMode, directory_mode);
144 EXPECT_EQ(kChronosUid, directory_owner);
145 EXPECT_EQ(kChronosGid, directory_group);
146}
147
148TEST_F(CrashCollectorTest, FormatDumpBasename) {
149 struct tm tm = {0};
150 tm.tm_sec = 15;
151 tm.tm_min = 50;
152 tm.tm_hour = 13;
153 tm.tm_mday = 23;
154 tm.tm_mon = 4;
155 tm.tm_year = 110;
156 tm.tm_isdst = -1;
157 std::string basename =
158 collector_.FormatDumpBasename("foo", mktime(&tm), 100);
159 ASSERT_EQ("foo.20100523.135015.100", basename);
160}
161
Ken Mixter207694d2010-10-28 15:42:37 -0700162TEST_F(CrashCollectorTest, GetCrashPath) {
163 EXPECT_EQ("/var/spool/crash/myprog.20100101.1200.1234.core",
164 collector_.GetCrashPath(FilePath("/var/spool/crash"),
165 "myprog.20100101.1200.1234",
166 "core").value());
167 EXPECT_EQ("/home/chronos/user/crash/chrome.20100101.1200.1234.dmp",
168 collector_.GetCrashPath(FilePath("/home/chronos/user/crash"),
169 "chrome.20100101.1200.1234",
170 "dmp").value());
171}
172
173
Ken Mixter04ec10f2010-08-26 16:02:02 -0700174bool CrashCollectorTest::CheckHasCapacity() {
175 static const char kFullMessage[] = "Crash directory test already full";
176 bool has_capacity = collector_.CheckHasCapacity(test_dir_);
Ken Mixtera3249322011-03-03 08:47:38 -0800177 bool has_message = FindLog(kFullMessage);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700178 EXPECT_EQ(has_message, !has_capacity);
179 return has_capacity;
180}
181
Ken Mixteree849c52010-09-30 15:30:10 -0700182TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
183 // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700184 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
Ken Mixter04ec10f2010-08-26 16:02:02 -0700185 file_util::WriteFile(test_dir_.Append(StringPrintf("file%d.core", i)),
186 "", 0);
Ken Mixteree849c52010-09-30 15:30:10 -0700187 EXPECT_TRUE(CheckHasCapacity());
Ken Mixter04ec10f2010-08-26 16:02:02 -0700188 }
189
Ken Mixteree849c52010-09-30 15:30:10 -0700190 // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
191 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
192 file_util::WriteFile(test_dir_.Append(StringPrintf("file%d.meta", i)),
193 "", 0);
194 EXPECT_TRUE(CheckHasCapacity());
195 }
196
197 // Test an additional kMaxCrashDirectorySize meta files don't fit.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700198 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
Ken Mixteree849c52010-09-30 15:30:10 -0700199 file_util::WriteFile(test_dir_.Append(StringPrintf("overage%d.meta", i)),
200 "", 0);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700201 EXPECT_FALSE(CheckHasCapacity());
202 }
203}
204
Ken Mixteree849c52010-09-30 15:30:10 -0700205TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
206 // Test kMaxCrashDirectorySize - 1 files can be added.
Ken Mixter04ec10f2010-08-26 16:02:02 -0700207 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
Ken Mixteree849c52010-09-30 15:30:10 -0700208 file_util::WriteFile(test_dir_.Append(StringPrintf("file.%d.core", i)),
Ken Mixter04ec10f2010-08-26 16:02:02 -0700209 "", 0);
Ken Mixteree849c52010-09-30 15:30:10 -0700210 EXPECT_TRUE(CheckHasCapacity());
Ken Mixter04ec10f2010-08-26 16:02:02 -0700211 }
Ken Mixteree849c52010-09-30 15:30:10 -0700212 file_util::WriteFile(test_dir_.Append("file.last.core"), "", 0);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700213 EXPECT_FALSE(CheckHasCapacity());
214}
215
Ken Mixteree849c52010-09-30 15:30:10 -0700216TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
217 // Test many files with different extensions and same base fit.
218 for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
219 file_util::WriteFile(test_dir_.Append(StringPrintf("a.%d", i)), "", 0);
220 EXPECT_TRUE(CheckHasCapacity());
221 }
222 // Test dot files are treated as individual files.
223 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
224 file_util::WriteFile(test_dir_.Append(StringPrintf(".file%d", i)), "", 0);
225 EXPECT_TRUE(CheckHasCapacity());
226 }
227 file_util::WriteFile(test_dir_.Append("normal.meta"), "", 0);
228 EXPECT_FALSE(CheckHasCapacity());
229}
230
Ken Mixterc49dbd42010-12-14 17:44:11 -0800231TEST_F(CrashCollectorTest, IsCommentLine) {
232 EXPECT_FALSE(CrashCollector::IsCommentLine(""));
233 EXPECT_TRUE(CrashCollector::IsCommentLine("#"));
234 EXPECT_TRUE(CrashCollector::IsCommentLine("#real comment"));
235 EXPECT_TRUE(CrashCollector::IsCommentLine(" # real comment"));
236 EXPECT_FALSE(CrashCollector::IsCommentLine("not comment"));
237 EXPECT_FALSE(CrashCollector::IsCommentLine(" not comment"));
238}
239
Ken Mixteree849c52010-09-30 15:30:10 -0700240TEST_F(CrashCollectorTest, ReadKeyValueFile) {
241 const char *contents = ("a=b\n"
242 "\n"
243 " c=d \n");
244 FilePath path(test_dir_.Append("keyval"));
245 std::map<std::string, std::string> dictionary;
246 std::map<std::string, std::string>::iterator i;
247
248 file_util::WriteFile(path, contents, strlen(contents));
249
250 EXPECT_TRUE(collector_.ReadKeyValueFile(path, '=', &dictionary));
251 i = dictionary.find("a");
252 EXPECT_TRUE(i != dictionary.end() && i->second == "b");
253 i = dictionary.find("c");
254 EXPECT_TRUE(i != dictionary.end() && i->second == "d");
255
256 dictionary.clear();
257
258 contents = ("a=b c d\n"
259 "e\n"
260 " f g = h\n"
261 "i=j\n"
262 "=k\n"
Ken Mixterc49dbd42010-12-14 17:44:11 -0800263 "#comment=0\n"
Ken Mixteree849c52010-09-30 15:30:10 -0700264 "l=\n");
265 file_util::WriteFile(path, contents, strlen(contents));
266
267 EXPECT_FALSE(collector_.ReadKeyValueFile(path, '=', &dictionary));
Ken Mixterc49dbd42010-12-14 17:44:11 -0800268 EXPECT_EQ(5, dictionary.size());
269
Ken Mixteree849c52010-09-30 15:30:10 -0700270 i = dictionary.find("a");
271 EXPECT_TRUE(i != dictionary.end() && i->second == "b c d");
272 i = dictionary.find("e");
273 EXPECT_TRUE(i == dictionary.end());
274 i = dictionary.find("f g");
275 EXPECT_TRUE(i != dictionary.end() && i->second == "h");
276 i = dictionary.find("i");
277 EXPECT_TRUE(i != dictionary.end() && i->second == "j");
278 i = dictionary.find("");
279 EXPECT_TRUE(i != dictionary.end() && i->second == "k");
280 i = dictionary.find("l");
281 EXPECT_TRUE(i != dictionary.end() && i->second == "");
282}
283
Ken Mixterafcf8082010-10-26 14:45:01 -0700284TEST_F(CrashCollectorTest, MetaData) {
Ken Mixter9b346472010-11-07 13:45:45 -0800285 const char kMetaFileBasename[] = "generated.meta";
286 FilePath meta_file = test_dir_.Append(kMetaFileBasename);
Ken Mixterafcf8082010-10-26 14:45:01 -0700287 FilePath lsb_release = test_dir_.Append("lsb-release");
288 FilePath payload_file = test_dir_.Append("payload-file");
289 std::string contents;
290 collector_.lsb_release_ = lsb_release.value().c_str();
291 const char kLsbContents[] = "CHROMEOS_RELEASE_VERSION=version\n";
292 ASSERT_TRUE(
293 file_util::WriteFile(lsb_release,
294 kLsbContents, strlen(kLsbContents)));
295 const char kPayload[] = "foo";
296 ASSERT_TRUE(
297 file_util::WriteFile(payload_file,
298 kPayload, strlen(kPayload)));
299 collector_.AddCrashMetaData("foo", "bar");
300 collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
301 EXPECT_TRUE(file_util::ReadFileToString(meta_file, &contents));
Ken Mixter9b346472010-11-07 13:45:45 -0800302 const char kExpectedMeta[] =
303 "foo=bar\n"
304 "exec_name=kernel\n"
305 "ver=version\n"
306 "payload=test/payload-file\n"
307 "payload_size=3\n"
308 "done=1\n";
309 EXPECT_EQ(kExpectedMeta, contents);
310
311 // Test target of symlink is not overwritten.
312 payload_file = test_dir_.Append("payload2-file");
313 ASSERT_TRUE(
314 file_util::WriteFile(payload_file,
315 kPayload, strlen(kPayload)));
316 FilePath meta_symlink_path = test_dir_.Append("symlink.meta");
317 ASSERT_EQ(0,
318 symlink(kMetaFileBasename,
319 meta_symlink_path.value().c_str()));
320 ASSERT_TRUE(file_util::PathExists(meta_symlink_path));
Ken Mixtera3249322011-03-03 08:47:38 -0800321 chromeos::ClearLog();
Ken Mixter9b346472010-11-07 13:45:45 -0800322 collector_.WriteCrashMetaData(meta_symlink_path,
323 "kernel",
324 payload_file.value());
Ken Mixtera3249322011-03-03 08:47:38 -0800325 // Target metadata contents should have stayed the same.
Ken Mixter9b346472010-11-07 13:45:45 -0800326 contents.clear();
327 EXPECT_TRUE(file_util::ReadFileToString(meta_file, &contents));
328 EXPECT_EQ(kExpectedMeta, contents);
Ken Mixtera3249322011-03-03 08:47:38 -0800329 EXPECT_TRUE(FindLog("Unable to write"));
Ken Mixter9b346472010-11-07 13:45:45 -0800330
331 // Test target of dangling symlink is not created.
332 file_util::Delete(meta_file, false);
333 ASSERT_FALSE(file_util::PathExists(meta_file));
Ken Mixtera3249322011-03-03 08:47:38 -0800334 chromeos::ClearLog();
Ken Mixter9b346472010-11-07 13:45:45 -0800335 collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
336 payload_file.value());
337 EXPECT_FALSE(file_util::PathExists(meta_file));
Ken Mixtera3249322011-03-03 08:47:38 -0800338 EXPECT_TRUE(FindLog("Unable to write"));
Ken Mixterafcf8082010-10-26 14:45:01 -0700339}
340
Ken Mixterc49dbd42010-12-14 17:44:11 -0800341TEST_F(CrashCollectorTest, GetLogContents) {
342 FilePath config_file = test_dir_.Append("crash_config");
343 FilePath output_file = test_dir_.Append("crash_log");
344 const char kConfigContents[] =
345 "foobar:echo hello there | sed -e \"s/there/world/\"";
346 ASSERT_TRUE(
347 file_util::WriteFile(config_file,
348 kConfigContents, strlen(kConfigContents)));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800349 file_util::Delete(FilePath(output_file), false);
Ken Mixterc49dbd42010-12-14 17:44:11 -0800350 EXPECT_FALSE(collector_.GetLogContents(config_file,
351 "barfoo",
352 output_file));
353 EXPECT_FALSE(file_util::PathExists(output_file));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800354 file_util::Delete(FilePath(output_file), false);
Ken Mixterc49dbd42010-12-14 17:44:11 -0800355 EXPECT_TRUE(collector_.GetLogContents(config_file,
356 "foobar",
357 output_file));
358 ASSERT_TRUE(file_util::PathExists(output_file));
359 std::string contents;
360 EXPECT_TRUE(file_util::ReadFileToString(output_file, &contents));
361 EXPECT_EQ("hello world\n", contents);
362}
363
Ken Mixter03403162010-08-18 15:23:16 -0700364int main(int argc, char **argv) {
Mike Frysingerf19b5182013-05-17 19:36:47 -0400365 ::g_type_init();
Ken Mixtera3249322011-03-03 08:47:38 -0800366 SetUpTests(&argc, argv, false);
Ken Mixter03403162010-08-18 15:23:16 -0700367 return RUN_ALL_TESTS();
368}