blob: 1c4cc9a3df378477bce8c3bc7f4158238bc5256e [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/udev_bluetooth_util.h"
#include <vector>
#include <base/containers/span.h>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <brillo/strings/string_utils.h>
#include <gtest/gtest.h>
#include "crash-reporter/paths.h"
#include "crash-reporter/test_util.h"
namespace {
constexpr char kCoredumpFlagPath[] = "/run/bluetooth/coredump_disabled";
} // namespace
class UdevBluetoothUtilTest : public ::testing::Test {
protected:
void CreateTestFile(const base::FilePath file_path,
const std::vector<std::string>& data) {
std::string data_str = brillo::string_utils::Join("\n", data);
// Clear previous test files, if any
ASSERT_TRUE(base::DeleteFile(file_path));
ASSERT_EQ(base::WriteFile(file_path, data_str.c_str(), data_str.length()),
data_str.length());
}
base::FilePath dump_path_;
base::FilePath target_path_;
base::FilePath data_path_;
private:
void SetUp() override {
CHECK(tmp_dir_.CreateUniqueTempDir());
paths::SetPrefixForTesting(tmp_dir_.GetPath());
dump_path_ = tmp_dir_.GetPath().Append("bt_firmware.devcd");
target_path_ = tmp_dir_.GetPath().Append("bt_firmware.txt");
data_path_ = tmp_dir_.GetPath().Append("bt_firmware.data");
}
base::ScopedTempDir tmp_dir_;
};
// Test a failure case when reading the input coredump file fails.
TEST_F(UdevBluetoothUtilTest, TestInvalidPath) {
std::string sig;
EXPECT_FALSE(bluetooth_util::IsBluetoothCoredump(
dump_path_.ReplaceExtension("invalid")));
EXPECT_FALSE(bluetooth_util::ProcessBluetoothCoredump(
dump_path_.ReplaceExtension("invalid"), target_path_, &sig));
EXPECT_FALSE(bluetooth_util::ReadCrashSig(
target_path_.ReplaceExtension("invalid"), &sig));
}
// Test a failure case when the crash_sig parameter is NULL.
TEST_F(UdevBluetoothUtilTest, TestNullSig) {
EXPECT_FALSE(bluetooth_util::ProcessBluetoothCoredump(dump_path_,
target_path_, nullptr));
}
// Verify feature flag enabled/disabled. The flag name is coredump_disabled.
// So, when disabled is 0, the feature is enabled.
TEST_F(UdevBluetoothUtilTest, TestIsCoredumpEnabled) {
// Flag file not present, verify feature is disabled.
EXPECT_FALSE(bluetooth_util::IsCoredumpEnabled());
// Empty flag file, verify feature is disabled.
ASSERT_TRUE(test_util::CreateFile(paths::Get(kCoredumpFlagPath), ""));
EXPECT_FALSE(bluetooth_util::IsCoredumpEnabled());
// Verify flag disabled case.
std::vector<std::string> data = {
"1",
};
CreateTestFile(paths::Get(kCoredumpFlagPath), data);
EXPECT_FALSE(bluetooth_util::IsCoredumpEnabled());
// Verify flag enabled case.
data = {
"0",
};
CreateTestFile(paths::Get(kCoredumpFlagPath), data);
EXPECT_TRUE(bluetooth_util::IsCoredumpEnabled());
}
// Correct header is "Bluetooth devcoredump". Verify IsBluetoothCoredump()
// returns true only when the correct header is detected.
TEST_F(UdevBluetoothUtilTest, TestIsBluetoothCoredump) {
std::vector<std::string> data = {
"Bluetooth coredump",
};
CreateTestFile(dump_path_, data);
EXPECT_FALSE(bluetooth_util::IsBluetoothCoredump(dump_path_));
data = {
"Bluetooth devcoredumps",
};
CreateTestFile(dump_path_, data);
EXPECT_FALSE(bluetooth_util::IsBluetoothCoredump(dump_path_));
data = {
"Bluetooth devcoredump header",
};
CreateTestFile(dump_path_, data);
EXPECT_FALSE(bluetooth_util::IsBluetoothCoredump(dump_path_));
data = {
"Bluetooth devcoredump",
};
CreateTestFile(dump_path_, data);
EXPECT_TRUE(bluetooth_util::IsBluetoothCoredump(dump_path_));
}
// In the parsed devcoredump, Driver, Vendor, Controller Name and a PC are
// the erquired fields to generate a crash signature. Verify that an error
// is reported if any of the required keys is missing.
TEST_F(UdevBluetoothUtilTest, TestMissingKeyValue) {
std::string sig;
std::vector<std::string> data = {
"Vendor=TestVen",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
data = {
"Driver=TestDrv",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
data = {
"Driver=TestDrv",
"Vendor=TestVen",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
data = {
"Driver=TestDrv",
"Vendor=TestVen",
"Controller Name=TestCon",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
}
// A key-value pair in the parsed devcoredump is of type "<key>=<value>".
// Verify that malformed key-value pairs are not parsed and an error is
// returned.
TEST_F(UdevBluetoothUtilTest, TestInvalidKeyValue) {
std::string sig;
// Test missing value in key-value pair
std::vector<std::string> data = {
"Driver=",
"Vendor=TestVen",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
// Test malformed key-value pair
data = {
"Driver TestDrv",
"Vendor=TestVen",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
// Test malformed key-value pair
data = {
"Driver:TestDrv",
"Vendor=TestVen",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_FALSE(bluetooth_util::ReadCrashSig(target_path_, &sig));
}
// Verify if all the required key-value pairs are present and the correct
// crash signature is generated.
TEST_F(UdevBluetoothUtilTest, TestValidParsedData) {
std::string sig;
std::vector<std::string> data = {
"Driver=TestDrv",
"Vendor=TestVen",
"Controller Name=TestCon",
"PC=00000000",
};
CreateTestFile(target_path_, data);
EXPECT_TRUE(bluetooth_util::ReadCrashSig(target_path_, &sig));
EXPECT_EQ(sig, "bt_firmware-TestDrv-TestVen_TestCon-00000000");
}
// Verify ProcessBluetoothCoredump() invokes bluetooth_devcd_parser binary
// and input devcoredump is parsed successfully.
TEST_F(UdevBluetoothUtilTest, RunAsRoot_TestProcessDump) {
std::vector<std::string> data = {
"Bluetooth devcoredump",
"State: 2",
"Driver: TestDrv",
"Vendor: TestVen",
"Controller Name: TestCon",
"--- Start dump ---",
"TestData",
};
CreateTestFile(dump_path_, data);
// Create a file whose existence indicates that this is a developer image.
ASSERT_TRUE(test_util::CreateFile(paths::Get(paths::kLeaveCoreFile), ""));
std::string sig;
EXPECT_TRUE(
bluetooth_util::ProcessBluetoothCoredump(dump_path_, target_path_, &sig));
EXPECT_EQ(sig, "bt_firmware-TestDrv-TestVen_TestCon-00000000");
std::string line;
ASSERT_TRUE(base::ReadFileToString(data_path_, &line));
EXPECT_EQ(line, "TestData");
}