crash_collector_test.cc revision c8b741428caeb01f7aca3c4c199e5f6894d335f8
1// Copyright (c) 2012 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 "crash_collector_test.h"
6
7#include <unistd.h>
8#include <utility>
9
10#include <base/files/file_util.h>
11#include <base/strings/string_util.h>
12#include <base/strings/stringprintf.h>
13#include <chromeos/syslog_logging.h>
14#include <gtest/gtest.h>
15
16#include "crash_collector.h"
17
18using base::FilePath;
19using base::StringPrintf;
20using chromeos::FindLog;
21using ::testing::Invoke;
22using ::testing::Return;
23
24namespace {
25
26void CountCrash() {
27  ADD_FAILURE();
28}
29
30bool IsMetrics() {
31  ADD_FAILURE();
32  return false;
33}
34
35}  // namespace
36
37class CrashCollectorTest : public ::testing::Test {
38 public:
39  void SetUp() {
40    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(Return());
41
42    collector_.Initialize(CountCrash, IsMetrics);
43    test_dir_ = FilePath("test");
44    base::CreateDirectory(test_dir_);
45    chromeos::ClearLog();
46  }
47
48  void TearDown() {
49    base::DeleteFile(test_dir_, true);
50  }
51
52  bool CheckHasCapacity();
53
54 protected:
55  CrashCollectorMock collector_;
56  FilePath test_dir_;
57};
58
59TEST_F(CrashCollectorTest, Initialize) {
60  ASSERT_TRUE(CountCrash == collector_.count_crash_function_);
61  ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_);
62}
63
64TEST_F(CrashCollectorTest, WriteNewFile) {
65  FilePath test_file = test_dir_.Append("test_new");
66  const char kBuffer[] = "buffer";
67  EXPECT_EQ(strlen(kBuffer),
68            collector_.WriteNewFile(test_file,
69                                    kBuffer,
70                                    strlen(kBuffer)));
71  EXPECT_LT(collector_.WriteNewFile(test_file,
72                                    kBuffer,
73                                    strlen(kBuffer)), 0);
74}
75
76TEST_F(CrashCollectorTest, Sanitize) {
77  EXPECT_EQ("chrome", collector_.Sanitize("chrome"));
78  EXPECT_EQ("CHROME", collector_.Sanitize("CHROME"));
79  EXPECT_EQ("1chrome2", collector_.Sanitize("1chrome2"));
80  EXPECT_EQ("chrome__deleted_", collector_.Sanitize("chrome (deleted)"));
81  EXPECT_EQ("foo_bar", collector_.Sanitize("foo.bar"));
82  EXPECT_EQ("", collector_.Sanitize(""));
83  EXPECT_EQ("_", collector_.Sanitize(" "));
84}
85
86TEST_F(CrashCollectorTest, GetCrashDirectoryInfo) {
87  FilePath path;
88  const int kRootUid = 0;
89  const int kRootGid = 0;
90  const int kNtpUid = 5;
91  const int kChronosUid = 1000;
92  const int kChronosGid = 1001;
93  const mode_t kExpectedSystemMode = 01755;
94  const mode_t kExpectedUserMode = 0755;
95
96  mode_t directory_mode;
97  uid_t directory_owner;
98  gid_t directory_group;
99
100  path = collector_.GetCrashDirectoryInfo(kRootUid,
101                                          kChronosUid,
102                                          kChronosGid,
103                                          &directory_mode,
104                                          &directory_owner,
105                                          &directory_group);
106  EXPECT_EQ("/var/spool/crash", path.value());
107  EXPECT_EQ(kExpectedSystemMode, directory_mode);
108  EXPECT_EQ(kRootUid, directory_owner);
109  EXPECT_EQ(kRootGid, directory_group);
110
111  path = collector_.GetCrashDirectoryInfo(kNtpUid,
112                                          kChronosUid,
113                                          kChronosGid,
114                                          &directory_mode,
115                                          &directory_owner,
116                                          &directory_group);
117  EXPECT_EQ("/var/spool/crash", path.value());
118  EXPECT_EQ(kExpectedSystemMode, directory_mode);
119  EXPECT_EQ(kRootUid, directory_owner);
120  EXPECT_EQ(kRootGid, directory_group);
121
122  path = collector_.GetCrashDirectoryInfo(kChronosUid,
123                                          kChronosUid,
124                                          kChronosGid,
125                                          &directory_mode,
126                                          &directory_owner,
127                                          &directory_group);
128  EXPECT_EQ("/var/spool/crash", path.value());
129  EXPECT_EQ(kExpectedUserMode, directory_mode);
130  EXPECT_EQ(kChronosUid, directory_owner);
131  EXPECT_EQ(kChronosGid, directory_group);
132}
133
134TEST_F(CrashCollectorTest, FormatDumpBasename) {
135  struct tm tm = {0};
136  tm.tm_sec = 15;
137  tm.tm_min = 50;
138  tm.tm_hour = 13;
139  tm.tm_mday = 23;
140  tm.tm_mon = 4;
141  tm.tm_year = 110;
142  tm.tm_isdst = -1;
143  std::string basename =
144      collector_.FormatDumpBasename("foo", mktime(&tm), 100);
145  ASSERT_EQ("foo.20100523.135015.100", basename);
146}
147
148TEST_F(CrashCollectorTest, GetCrashPath) {
149  EXPECT_EQ("/var/spool/crash/myprog.20100101.1200.1234.core",
150            collector_.GetCrashPath(FilePath("/var/spool/crash"),
151                                    "myprog.20100101.1200.1234",
152                                    "core").value());
153  EXPECT_EQ("/home/chronos/user/crash/chrome.20100101.1200.1234.dmp",
154            collector_.GetCrashPath(FilePath("/home/chronos/user/crash"),
155                                    "chrome.20100101.1200.1234",
156                                    "dmp").value());
157}
158
159
160bool CrashCollectorTest::CheckHasCapacity() {
161  static const char kFullMessage[] = "Crash directory test already full";
162  bool has_capacity = collector_.CheckHasCapacity(test_dir_);
163  bool has_message = FindLog(kFullMessage);
164  EXPECT_EQ(has_message, !has_capacity);
165  return has_capacity;
166}
167
168TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
169  // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
170  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
171    base::WriteFile(test_dir_.Append(StringPrintf("file%d.core", i)), "", 0);
172    EXPECT_TRUE(CheckHasCapacity());
173  }
174
175  // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
176  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
177    base::WriteFile(test_dir_.Append(StringPrintf("file%d.meta", i)), "", 0);
178    EXPECT_TRUE(CheckHasCapacity());
179  }
180
181  // Test an additional kMaxCrashDirectorySize meta files don't fit.
182  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
183    base::WriteFile(test_dir_.Append(StringPrintf("overage%d.meta", i)), "", 0);
184    EXPECT_FALSE(CheckHasCapacity());
185  }
186}
187
188TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
189  // Test kMaxCrashDirectorySize - 1 files can be added.
190  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
191    base::WriteFile(test_dir_.Append(StringPrintf("file.%d.core", i)), "", 0);
192    EXPECT_TRUE(CheckHasCapacity());
193  }
194  base::WriteFile(test_dir_.Append("file.last.core"), "", 0);
195  EXPECT_FALSE(CheckHasCapacity());
196}
197
198TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
199  // Test many files with different extensions and same base fit.
200  for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
201    base::WriteFile(test_dir_.Append(StringPrintf("a.%d", i)), "", 0);
202    EXPECT_TRUE(CheckHasCapacity());
203  }
204  // Test dot files are treated as individual files.
205  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
206    base::WriteFile(test_dir_.Append(StringPrintf(".file%d", i)), "", 0);
207    EXPECT_TRUE(CheckHasCapacity());
208  }
209  base::WriteFile(test_dir_.Append("normal.meta"), "", 0);
210  EXPECT_FALSE(CheckHasCapacity());
211}
212
213TEST_F(CrashCollectorTest, MetaData) {
214  const char kMetaFileBasename[] = "generated.meta";
215  FilePath meta_file = test_dir_.Append(kMetaFileBasename);
216  FilePath lsb_release = test_dir_.Append("lsb-release");
217  FilePath payload_file = test_dir_.Append("payload-file");
218  std::string contents;
219  collector_.lsb_release_ = lsb_release.value();
220  const char kLsbContents[] =
221      "CHROMEOS_RELEASE_BOARD=lumpy\n"
222      "CHROMEOS_RELEASE_VERSION=6727.0.2015_01_26_0853\n"
223      "CHROMEOS_RELEASE_NAME=Chromium OS\n";
224  ASSERT_TRUE(base::WriteFile(lsb_release, kLsbContents, strlen(kLsbContents)));
225  const char kPayload[] = "foo";
226  ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
227  collector_.AddCrashMetaData("foo", "bar");
228  collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
229  EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
230  const char kExpectedMeta[] =
231      "foo=bar\n"
232      "exec_name=kernel\n"
233      "ver=6727.0.2015_01_26_0853\n"
234      "payload=test/payload-file\n"
235      "payload_size=3\n"
236      "done=1\n";
237  EXPECT_EQ(kExpectedMeta, contents);
238
239  // Test target of symlink is not overwritten.
240  payload_file = test_dir_.Append("payload2-file");
241  ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
242  FilePath meta_symlink_path = test_dir_.Append("symlink.meta");
243  ASSERT_EQ(0,
244            symlink(kMetaFileBasename,
245                    meta_symlink_path.value().c_str()));
246  ASSERT_TRUE(base::PathExists(meta_symlink_path));
247  chromeos::ClearLog();
248  collector_.WriteCrashMetaData(meta_symlink_path,
249                                "kernel",
250                                payload_file.value());
251  // Target metadata contents should have stayed the same.
252  contents.clear();
253  EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
254  EXPECT_EQ(kExpectedMeta, contents);
255  EXPECT_TRUE(FindLog("Unable to write"));
256
257  // Test target of dangling symlink is not created.
258  base::DeleteFile(meta_file, false);
259  ASSERT_FALSE(base::PathExists(meta_file));
260  chromeos::ClearLog();
261  collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
262                                payload_file.value());
263  EXPECT_FALSE(base::PathExists(meta_file));
264  EXPECT_TRUE(FindLog("Unable to write"));
265}
266
267TEST_F(CrashCollectorTest, GetLogContents) {
268  FilePath config_file = test_dir_.Append("crash_config");
269  FilePath output_file = test_dir_.Append("crash_log");
270  const char kConfigContents[] =
271      "foobar=echo hello there | \\\n  sed -e \"s/there/world/\"";
272  ASSERT_TRUE(
273      base::WriteFile(config_file, kConfigContents, strlen(kConfigContents)));
274  base::DeleteFile(FilePath(output_file), false);
275  EXPECT_FALSE(collector_.GetLogContents(config_file,
276                                         "barfoo",
277                                         output_file));
278  EXPECT_FALSE(base::PathExists(output_file));
279  base::DeleteFile(FilePath(output_file), false);
280  EXPECT_TRUE(collector_.GetLogContents(config_file,
281                                        "foobar",
282                                        output_file));
283  ASSERT_TRUE(base::PathExists(output_file));
284  std::string contents;
285  EXPECT_TRUE(base::ReadFileToString(output_file, &contents));
286  EXPECT_EQ("hello world\n", contents);
287}
288