| // Copyright 2016 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/memory/ref_counted.h> |
| #include <base/memory/scoped_refptr.h> |
| #include <brillo/syslog_logging.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <metrics/metrics_library.h> |
| #include <metrics/metrics_library_mock.h> |
| |
| #include "crash-reporter/ec_collector.h" |
| #include "crash-reporter/test_util.h" |
| |
| using base::FilePath; |
| using brillo::FindLog; |
| |
| namespace { |
| |
| const char kECPanicInfo[] = "panicinfo"; |
| const char kDevCoredumpDirectory[] = "cros_ec"; |
| const unsigned int kPanicDataArchByte = 0; |
| const unsigned int kPanicDataVersionByte = 1; |
| const unsigned int kPanicDataReservedByte = 3; |
| |
| } // namespace |
| |
| class ECCollectorMock : public ECCollector { |
| public: |
| ECCollectorMock() |
| : ECCollector( |
| base::MakeRefCounted< |
| base::RefCountedData<std::unique_ptr<MetricsLibraryInterface>>>( |
| std::make_unique<MetricsLibraryMock>())) {} |
| MOCK_METHOD(void, SetUpDBus, (), (override)); |
| }; |
| |
| class ECCollectorTest : public ::testing::Test { |
| protected: |
| void PreparePanicInfo(bool present, bool stale, bool valid = true) { |
| FilePath panicinfo_path = collector_.debugfs_path_.Append(kECPanicInfo); |
| |
| if (present) { |
| char data[116]; |
| for (unsigned int i = 0; i < sizeof(data); i++) |
| data[i] = i; |
| |
| if (valid) { |
| // Forge a panic data with valid arch, struct version, flag, and |
| // reserved. |
| data[kPanicDataArchByte] = 1; |
| data[kPanicDataVersionByte] = 2; |
| data[PANIC_DATA_FLAGS_BYTE] = 0; |
| data[kPanicDataReservedByte] = 0; |
| } |
| if (stale) |
| data[PANIC_DATA_FLAGS_BYTE] |= PANIC_DATA_FLAG_OLD_HOSTCMD; |
| else |
| data[PANIC_DATA_FLAGS_BYTE] &= ~PANIC_DATA_FLAG_OLD_HOSTCMD; |
| |
| ASSERT_EQ(base::WriteFile(panicinfo_path, data, sizeof(data)), |
| static_cast<int>(sizeof(data))); |
| } else { |
| base::DeleteFile(panicinfo_path); |
| } |
| } |
| |
| base::ScopedTempDir temp_dir_generator_; |
| |
| ECCollectorMock collector_; |
| |
| private: |
| void SetUp() override { |
| EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return()); |
| |
| collector_.Initialize(false); |
| |
| ASSERT_TRUE(temp_dir_generator_.CreateUniqueTempDir()); |
| |
| collector_.set_crash_directory_for_test(temp_dir_generator_.GetPath()); |
| |
| FilePath debugfs_path = |
| temp_dir_generator_.GetPath().Append(kDevCoredumpDirectory); |
| ASSERT_TRUE(base::CreateDirectory(debugfs_path)); |
| collector_.debugfs_path_ = debugfs_path; |
| } |
| }; |
| |
| TEST_F(ECCollectorTest, TestNoCrash) { |
| PreparePanicInfo(false, false); |
| ASSERT_FALSE(collector_.Collect(/*use_saved_lsb=*/true)); |
| EXPECT_EQ(collector_.get_bytes_written(), 0); |
| } |
| |
| TEST_F(ECCollectorTest, TestStale) { |
| PreparePanicInfo(true, true); |
| ASSERT_FALSE(collector_.Collect(/*use_saved_lsb=*/true)); |
| ASSERT_TRUE(FindLog("Stale EC crash")); |
| EXPECT_EQ(collector_.get_bytes_written(), 0); |
| } |
| |
| TEST_F(ECCollectorTest, TestGood) { |
| PreparePanicInfo(true, false); |
| ASSERT_TRUE(collector_.Collect(/*use_saved_lsb=*/true)); |
| ASSERT_TRUE(FindLog("(handling)")); |
| EXPECT_TRUE(test_util::DirectoryHasFileWithPatternAndContents( |
| temp_dir_generator_.GetPath(), "embedded_controller.*.meta", |
| "upload_var_collector=ec")); |
| /* TODO(drinkcat): Test crash file content */ |
| } |
| |
| TEST_F(ECCollectorTest, TestInvalid) { |
| PreparePanicInfo(true, false, false); |
| ASSERT_FALSE(collector_.Collect(/*use_saved_lsb=*/true)); |
| } |
| |
| TEST_F(ECCollectorTest, ComputeSeverity) { |
| CrashCollector::ComputedCrashSeverity computed_severity = |
| collector_.ComputeSeverity("any executable"); |
| |
| EXPECT_EQ(computed_severity.crash_severity, |
| CrashCollector::CrashSeverity::kFatal); |
| EXPECT_EQ(computed_severity.product_group, |
| CrashCollector::Product::kPlatform); |
| } |
| |
| class ECCollectorSavedLsbTest : public ECCollectorTest, |
| public ::testing::WithParamInterface<bool> {}; |
| |
| TEST_P(ECCollectorSavedLsbTest, UsesSavedLsb) { |
| FilePath lsb_release = temp_dir_generator_.GetPath().Append("lsb-release"); |
| collector_.set_lsb_release_for_test(lsb_release); |
| const char kLsbContents[] = |
| "CHROMEOS_RELEASE_BOARD=lumpy\n" |
| "CHROMEOS_RELEASE_VERSION=6727.0.2015_01_26_0853\n" |
| "CHROMEOS_RELEASE_NAME=Chromium OS\n" |
| "CHROMEOS_RELEASE_CHROME_MILESTONE=82\n" |
| "CHROMEOS_RELEASE_TRACK=testimage-channel\n" |
| "CHROMEOS_RELEASE_DESCRIPTION=6727.0.2015_01_26_0853 (Test Build - foo)"; |
| ASSERT_TRUE(test_util::CreateFile(lsb_release, kLsbContents)); |
| |
| FilePath saved_lsb_dir = |
| temp_dir_generator_.GetPath().Append("crash-reporter-state"); |
| ASSERT_TRUE(base::CreateDirectory(saved_lsb_dir)); |
| collector_.set_reporter_state_directory_for_test(saved_lsb_dir); |
| |
| const char kSavedLsbContents[] = |
| "CHROMEOS_RELEASE_BOARD=lumpy\n" |
| "CHROMEOS_RELEASE_VERSION=12345.0.2015_01_26_0853\n" |
| "CHROMEOS_RELEASE_NAME=Chromium OS\n" |
| "CHROMEOS_RELEASE_CHROME_MILESTONE=81\n" |
| "CHROMEOS_RELEASE_TRACK=beta-channel\n" |
| "CHROMEOS_RELEASE_DESCRIPTION=12345.0.2015_01_26_0853 (Test Build - foo)"; |
| base::FilePath saved_lsb = saved_lsb_dir.Append("lsb-release"); |
| ASSERT_TRUE(test_util::CreateFile(saved_lsb, kSavedLsbContents)); |
| |
| PreparePanicInfo(true, false); |
| ASSERT_TRUE(collector_.Collect(/*use_saved_lsb=*/GetParam())); |
| |
| if (GetParam()) { |
| EXPECT_TRUE(test_util::DirectoryHasFileWithPatternAndContents( |
| temp_dir_generator_.GetPath(), "*.meta", |
| "ver=12345.0.2015_01_26_0853\n")); |
| } else { |
| EXPECT_TRUE(test_util::DirectoryHasFileWithPatternAndContents( |
| temp_dir_generator_.GetPath(), "*.meta", |
| "ver=6727.0.2015_01_26_0853\n")); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(ECCollectorSavedLsbTest, |
| ECCollectorSavedLsbTest, |
| testing::Bool()); |