Home | History | Annotate | Download | only in crash_reporter
      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