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