blob: 85316bb66382def232772b15716772498c626c99 [file] [log] [blame]
// Copyright 2025 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fbpreprocessor/platform_features_client.h"
#include <memory>
#include <string>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/test/task_environment.h>
#include <brillo/files/file_util.h>
#include <dbus/mock_bus.h>
#include <featured/fake_platform_features.h>
#include <featured/feature_library.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::_;
using ::testing::Return;
namespace fbpreprocessor {
namespace {
constexpr char kAllowFirmwareDumpsFlagPath[] = "allow_firmware_dumps";
constexpr char kAllowFirmwareDumpsFeatureName[] =
"CrOSLateBootAllowFirmwareDumps";
class PlatformFeaturesClientTest : public testing::Test {
protected:
void SetUp() override {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = base::MakeRefCounted<dbus::MockBus>(options);
CHECK(test_dir_.CreateUniqueTempDir());
fake_platform_features_ =
std::make_unique<feature::FakePlatformFeatures>(bus_);
EXPECT_CALL(*bus_, GetOriginTaskRunner())
.WillRepeatedly(
Return(base::SequencedTaskRunner::GetCurrentDefault().get()));
client_.set_base_dir_for_test(test_dir_.GetPath());
client_.Start(fake_platform_features_.get());
task_environment_.RunUntilIdle();
}
void TearDown() override { fake_platform_features_->ShutdownBus(); }
void SetIsFeatureEnabledWithRefetch(bool enabled) {
fake_platform_features_->SetEnabled(kAllowFirmwareDumpsFeatureName,
enabled);
fake_platform_features_->TriggerRefetchSignal();
task_environment_.RunUntilIdle();
}
base::FilePath GetAllowFirmwareDumpsFlagPath() const {
return test_dir_.GetPath().Append(
base::FilePath(kAllowFirmwareDumpsFlagPath));
}
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
scoped_refptr<dbus::MockBus> bus_;
base::ScopedTempDir test_dir_;
std::unique_ptr<feature::FakePlatformFeatures> fake_platform_features_;
PlatformFeaturesClient client_;
};
class MockObserver : public PlatformFeaturesClient::Observer {
public:
MOCK_METHOD(void, OnFeatureChanged, (bool allowed));
};
TEST_F(PlatformFeaturesClientTest, FeatureAllowed) {
SetIsFeatureEnabledWithRefetch(true);
EXPECT_TRUE(client_.FirmwareDumpsAllowedByFinch());
std::string file_content;
EXPECT_TRUE(
base::ReadFileToString(GetAllowFirmwareDumpsFlagPath(), &file_content));
EXPECT_EQ(file_content, "1");
}
TEST_F(PlatformFeaturesClientTest, FeatureAllowedByDefault) {
EXPECT_TRUE(client_.FirmwareDumpsAllowedByFinch());
std::string file_content;
EXPECT_TRUE(
base::ReadFileToString(GetAllowFirmwareDumpsFlagPath(), &file_content));
EXPECT_EQ(file_content, "1");
}
TEST_F(PlatformFeaturesClientTest, FeatureAllowedFlagFileUpdated) {
// Delete the file to avoid being tricked by leftover state from the init
// phase.
EXPECT_TRUE(brillo::DeleteFile(GetAllowFirmwareDumpsFlagPath()));
SetIsFeatureEnabledWithRefetch(true);
std::string file_content;
EXPECT_TRUE(
base::ReadFileToString(GetAllowFirmwareDumpsFlagPath(), &file_content));
EXPECT_EQ(file_content, "1");
}
TEST_F(PlatformFeaturesClientTest, FeatureDisallowed) {
SetIsFeatureEnabledWithRefetch(false);
EXPECT_FALSE(client_.FirmwareDumpsAllowedByFinch());
std::string file_content;
EXPECT_TRUE(
base::ReadFileToString(GetAllowFirmwareDumpsFlagPath(), &file_content));
EXPECT_EQ(file_content, "0");
}
TEST_F(PlatformFeaturesClientTest, ObserverCalled) {
MockObserver observer;
client_.AddObserver(&observer);
EXPECT_CALL(observer, OnFeatureChanged(true));
SetIsFeatureEnabledWithRefetch(true);
}
TEST_F(PlatformFeaturesClientTest, ObserverNotCalledAfterRemoval) {
MockObserver observer;
client_.AddObserver(&observer);
EXPECT_CALL(observer, OnFeatureChanged(true));
SetIsFeatureEnabledWithRefetch(true);
client_.RemoveObserver(&observer);
// The observer has been removed, |OnFeatureChanged()| should not be called
// anymore.
EXPECT_CALL(observer, OnFeatureChanged(_)).Times(0);
SetIsFeatureEnabledWithRefetch(true);
}
TEST_F(PlatformFeaturesClientTest, ObserverCalledAfterRefetch) {
MockObserver observer;
client_.AddObserver(&observer);
EXPECT_CALL(observer, OnFeatureChanged(true)).Times(1);
SetIsFeatureEnabledWithRefetch(true);
}
TEST_F(PlatformFeaturesClientTest, ObserverCalledMultipleTimes) {
MockObserver observer;
client_.AddObserver(&observer);
// First fetch, enabled.
EXPECT_CALL(observer, OnFeatureChanged(true)).Times(1);
SetIsFeatureEnabledWithRefetch(true);
// Second fetch, disabled. This simulates the feature changing while
// the program is running.
EXPECT_CALL(observer, OnFeatureChanged(false)).Times(1);
SetIsFeatureEnabledWithRefetch(false);
// Third fetch, enabled again.
EXPECT_CALL(observer, OnFeatureChanged(true)).Times(1);
SetIsFeatureEnabledWithRefetch(true);
}
TEST_F(PlatformFeaturesClientTest, MultipleObservers) {
MockObserver observer1;
MockObserver observer2;
client_.AddObserver(&observer1);
client_.AddObserver(&observer2);
EXPECT_CALL(observer1, OnFeatureChanged(true)).Times(1);
EXPECT_CALL(observer2, OnFeatureChanged(true)).Times(1);
SetIsFeatureEnabledWithRefetch(true);
}
} // namespace
} // namespace fbpreprocessor