1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "crash_collector_test.h"
18
19 #include <unistd.h>
20 #include <utility>
21
22 #include <base/files/file_util.h>
23 #include <base/files/scoped_temp_dir.h>
24 #include <base/strings/string_util.h>
25 #include <base/strings/stringprintf.h>
26 #include <brillo/syslog_logging.h>
27 #include <gtest/gtest.h>
28
29 #include "crash_collector.h"
30
31 using base::FilePath;
32 using base::StringPrintf;
33 using brillo::FindLog;
34 using ::testing::Invoke;
35 using ::testing::Return;
36
37 namespace {
38
CountCrash()39 void CountCrash() {
40 ADD_FAILURE();
41 }
42
IsMetrics()43 bool IsMetrics() {
44 ADD_FAILURE();
45 return false;
46 }
47
48 } // namespace
49
50 class CrashCollectorTest : public ::testing::Test {
51 public:
SetUp()52 void SetUp() {
53 EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(Return());
54
55 collector_.Initialize(CountCrash, IsMetrics);
56 EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
57 brillo::ClearLog();
58 }
59
60 bool CheckHasCapacity();
61
62 protected:
63 CrashCollectorMock collector_;
64
65 // Temporary directory used for tests.
66 base::ScopedTempDir test_dir_;
67 };
68
TEST_F(CrashCollectorTest,Initialize)69 TEST_F(CrashCollectorTest, Initialize) {
70 ASSERT_TRUE(CountCrash == collector_.count_crash_function_);
71 ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_);
72 }
73
TEST_F(CrashCollectorTest,WriteNewFile)74 TEST_F(CrashCollectorTest, WriteNewFile) {
75 FilePath test_file = test_dir_.path().Append("test_new");
76 const char kBuffer[] = "buffer";
77 EXPECT_EQ(strlen(kBuffer),
78 collector_.WriteNewFile(test_file,
79 kBuffer,
80 strlen(kBuffer)));
81 EXPECT_LT(collector_.WriteNewFile(test_file,
82 kBuffer,
83 strlen(kBuffer)), 0);
84 }
85
TEST_F(CrashCollectorTest,Sanitize)86 TEST_F(CrashCollectorTest, Sanitize) {
87 EXPECT_EQ("chrome", collector_.Sanitize("chrome"));
88 EXPECT_EQ("CHROME", collector_.Sanitize("CHROME"));
89 EXPECT_EQ("1chrome2", collector_.Sanitize("1chrome2"));
90 EXPECT_EQ("chrome__deleted_", collector_.Sanitize("chrome (deleted)"));
91 EXPECT_EQ("foo_bar", collector_.Sanitize("foo.bar"));
92 EXPECT_EQ("", collector_.Sanitize(""));
93 EXPECT_EQ("_", collector_.Sanitize(" "));
94 }
95
TEST_F(CrashCollectorTest,FormatDumpBasename)96 TEST_F(CrashCollectorTest, FormatDumpBasename) {
97 struct tm tm = {0};
98 tm.tm_sec = 15;
99 tm.tm_min = 50;
100 tm.tm_hour = 13;
101 tm.tm_mday = 23;
102 tm.tm_mon = 4;
103 tm.tm_year = 110;
104 tm.tm_isdst = -1;
105 std::string basename =
106 collector_.FormatDumpBasename("foo", mktime(&tm), 100);
107 ASSERT_EQ("foo.20100523.135015.100", basename);
108 }
109
TEST_F(CrashCollectorTest,GetCrashPath)110 TEST_F(CrashCollectorTest, GetCrashPath) {
111 EXPECT_EQ("/var/spool/crash/myprog.20100101.1200.1234.core",
112 collector_.GetCrashPath(FilePath("/var/spool/crash"),
113 "myprog.20100101.1200.1234",
114 "core").value());
115 EXPECT_EQ("/home/chronos/user/crash/chrome.20100101.1200.1234.dmp",
116 collector_.GetCrashPath(FilePath("/home/chronos/user/crash"),
117 "chrome.20100101.1200.1234",
118 "dmp").value());
119 }
120
121
CheckHasCapacity()122 bool CrashCollectorTest::CheckHasCapacity() {
123 const char* kFullMessage =
124 StringPrintf("Crash directory %s already full",
125 test_dir_.path().value().c_str()).c_str();
126 bool has_capacity = collector_.CheckHasCapacity(test_dir_.path());
127 bool has_message = FindLog(kFullMessage);
128 EXPECT_EQ(has_message, !has_capacity);
129 return has_capacity;
130 }
131
TEST_F(CrashCollectorTest,CheckHasCapacityUsual)132 TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
133 // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
134 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
135 base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.core", i)),
136 "", 0);
137 EXPECT_TRUE(CheckHasCapacity());
138 }
139
140 // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
141 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
142 base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.meta", i)),
143 "", 0);
144 EXPECT_TRUE(CheckHasCapacity());
145 }
146
147 // Test an additional kMaxCrashDirectorySize meta files don't fit.
148 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
149 base::WriteFile(test_dir_.path().Append(StringPrintf("overage%d.meta", i)),
150 "", 0);
151 EXPECT_FALSE(CheckHasCapacity());
152 }
153 }
154
TEST_F(CrashCollectorTest,CheckHasCapacityCorrectBasename)155 TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
156 // Test kMaxCrashDirectorySize - 1 files can be added.
157 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
158 base::WriteFile(test_dir_.path().Append(StringPrintf("file.%d.core", i)),
159 "", 0);
160 EXPECT_TRUE(CheckHasCapacity());
161 }
162 base::WriteFile(test_dir_.path().Append("file.last.core"), "", 0);
163 EXPECT_FALSE(CheckHasCapacity());
164 }
165
TEST_F(CrashCollectorTest,CheckHasCapacityStrangeNames)166 TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
167 // Test many files with different extensions and same base fit.
168 for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
169 base::WriteFile(test_dir_.path().Append(StringPrintf("a.%d", i)), "", 0);
170 EXPECT_TRUE(CheckHasCapacity());
171 }
172 // Test dot files are treated as individual files.
173 for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
174 base::WriteFile(test_dir_.path().Append(StringPrintf(".file%d", i)), "", 0);
175 EXPECT_TRUE(CheckHasCapacity());
176 }
177 base::WriteFile(test_dir_.path().Append("normal.meta"), "", 0);
178 EXPECT_FALSE(CheckHasCapacity());
179 }
180
TEST_F(CrashCollectorTest,MetaData)181 TEST_F(CrashCollectorTest, MetaData) {
182 const char kMetaFileBasename[] = "generated.meta";
183 FilePath meta_file = test_dir_.path().Append(kMetaFileBasename);
184 FilePath payload_file = test_dir_.path().Append("payload-file");
185 std::string contents;
186 const char kPayload[] = "foo";
187 ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
188 collector_.AddCrashMetaData("foo", "bar");
189 collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
190 EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
191 const std::string kExpectedMeta =
192 StringPrintf("foo=bar\n"
193 "exec_name=kernel\n"
194 "payload=%s\n"
195 "payload_size=3\n"
196 "done=1\n",
197 test_dir_.path().Append("payload-file").value().c_str());
198 EXPECT_EQ(kExpectedMeta, contents);
199
200 // Test target of symlink is not overwritten.
201 payload_file = test_dir_.path().Append("payload2-file");
202 ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
203 FilePath meta_symlink_path = test_dir_.path().Append("symlink.meta");
204 ASSERT_EQ(0,
205 symlink(kMetaFileBasename,
206 meta_symlink_path.value().c_str()));
207 ASSERT_TRUE(base::PathExists(meta_symlink_path));
208 brillo::ClearLog();
209 collector_.WriteCrashMetaData(meta_symlink_path,
210 "kernel",
211 payload_file.value());
212 // Target metadata contents should have stayed the same.
213 contents.clear();
214 EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
215 EXPECT_EQ(kExpectedMeta, contents);
216 EXPECT_TRUE(FindLog("Unable to write"));
217
218 // Test target of dangling symlink is not created.
219 base::DeleteFile(meta_file, false);
220 ASSERT_FALSE(base::PathExists(meta_file));
221 brillo::ClearLog();
222 collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
223 payload_file.value());
224 EXPECT_FALSE(base::PathExists(meta_file));
225 EXPECT_TRUE(FindLog("Unable to write"));
226 }
227
TEST_F(CrashCollectorTest,GetLogContents)228 TEST_F(CrashCollectorTest, GetLogContents) {
229 FilePath config_file = test_dir_.path().Append("crash_config");
230 FilePath output_file = test_dir_.path().Append("crash_log");
231 const char kConfigContents[] =
232 "foobar=echo hello there | \\\n sed -e \"s/there/world/\"";
233 ASSERT_TRUE(
234 base::WriteFile(config_file, kConfigContents, strlen(kConfigContents)));
235 base::DeleteFile(FilePath(output_file), false);
236 EXPECT_FALSE(collector_.GetLogContents(config_file,
237 "barfoo",
238 output_file));
239 EXPECT_FALSE(base::PathExists(output_file));
240 base::DeleteFile(FilePath(output_file), false);
241 EXPECT_TRUE(collector_.GetLogContents(config_file,
242 "foobar",
243 output_file));
244 ASSERT_TRUE(base::PathExists(output_file));
245 std::string contents;
246 EXPECT_TRUE(base::ReadFileToString(output_file, &contents));
247 EXPECT_EQ("hello world\n", contents);
248 }
249