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 39 void CountCrash() { 40 ADD_FAILURE(); 41 } 42 43 bool IsMetrics() { 44 ADD_FAILURE(); 45 return false; 46 } 47 48 } // namespace 49 50 class CrashCollectorTest : public ::testing::Test { 51 public: 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 69 TEST_F(CrashCollectorTest, Initialize) { 70 ASSERT_TRUE(CountCrash == collector_.count_crash_function_); 71 ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_); 72 } 73 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 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 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 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 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 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 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 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 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 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