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