| // Copyright 2021 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <utility> |
| |
| #include <base/test/task_environment.h> |
| #include <brillo/dbus/dbus_object_test_helpers.h> |
| #include <brillo/message_loops/base_message_loop.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dbus/bus.h> |
| #include <dbus/mock_bus.h> |
| #include <dbus/mock_exported_object.h> |
| #include <dbus/mock_object_proxy.h> |
| #include <gmock/gmock.h> |
| #include <hps/daemon/dbus_adaptor.h> |
| #include <hps/hps.h> |
| |
| using brillo::dbus_utils::AsyncEventSequencer; |
| using testing::_; |
| using testing::InSequence; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::StrictMock; |
| |
| namespace hps { |
| |
| class MockHps : public HPS { |
| public: |
| MOCK_METHOD(void, |
| Init, |
| (uint32_t, const base::FilePath&, const base::FilePath&), |
| (override)); |
| MOCK_METHOD(bool, Boot, (), (override)); |
| MOCK_METHOD(void, SkipBoot, (), (override)); |
| MOCK_METHOD(bool, Enable, (uint8_t), (override)); |
| MOCK_METHOD(bool, Disable, (uint8_t), (override)); |
| MOCK_METHOD(int, Result, (int), (override)); |
| MOCK_METHOD(DevInterface*, Device, (), (override)); |
| MOCK_METHOD(bool, Download, (HpsBank, const base::FilePath&), (override)); |
| }; |
| |
| class HpsDaemonTest : public testing::Test { |
| public: |
| HpsDaemonTest() { |
| dbus::Bus::Options options; |
| mock_bus_ = base::MakeRefCounted<NiceMock<dbus::MockBus>>(options); |
| dbus::ObjectPath path(::hps::kHpsServicePath); |
| |
| mock_object_proxy_ = base::MakeRefCounted<NiceMock<dbus::MockObjectProxy>>( |
| mock_bus_.get(), kHpsServicePath, path); |
| |
| mock_exported_object_ = |
| base::MakeRefCounted<NiceMock<dbus::MockExportedObject>>( |
| mock_bus_.get(), path); |
| |
| ON_CALL(*mock_bus_, GetExportedObject(path)) |
| .WillByDefault(Return(mock_exported_object_.get())); |
| |
| ON_CALL(*mock_bus_, GetDBusTaskRunner()) |
| .WillByDefault( |
| Return(task_environment_.GetMainThreadTaskRunner().get())); |
| |
| EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _)) |
| .Times(testing::AnyNumber()); |
| |
| auto hps = std::make_unique<StrictMock<MockHps>>(); |
| mock_hps_ = hps.get(); |
| hps_daemon_.reset(new DBusAdaptor(mock_bus_, std::move(hps), kPollTimeMs)); |
| |
| brillo_loop_.SetAsCurrent(); |
| } |
| |
| protected: |
| bool CallEnableFeature(brillo::ErrorPtr* error_ptr, uint8_t feature) { |
| return hps_daemon_->EnableFeature(error_ptr, feature); |
| } |
| |
| bool CallDisableFeature(brillo::ErrorPtr* error_ptr, uint8_t feature) { |
| return hps_daemon_->DisableFeature(error_ptr, feature); |
| } |
| |
| bool CallGetFeatureResult(brillo::ErrorPtr* error_ptr, |
| uint8_t feature, |
| uint16_t* result) { |
| return hps_daemon_->GetFeatureResult(error_ptr, feature, result); |
| } |
| |
| base::test::SingleThreadTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| brillo::BaseMessageLoop brillo_loop_{ |
| task_environment_.GetMainThreadTaskRunner().get()}; |
| |
| scoped_refptr<dbus::MockBus> mock_bus_; |
| scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_; |
| scoped_refptr<dbus::MockExportedObject> mock_exported_object_; |
| StrictMock<MockHps>* mock_hps_; |
| std::unique_ptr<DBusAdaptor> hps_daemon_; |
| static constexpr uint32_t kPollTimeMs = 500; |
| }; |
| |
| TEST_F(HpsDaemonTest, EnableFeatureNotReady) { |
| EXPECT_CALL(*mock_hps_, Enable(0)).WillOnce(Return(false)); |
| brillo::ErrorPtr error; |
| bool result = CallEnableFeature(&error, 0); |
| EXPECT_FALSE(result); |
| EXPECT_EQ("hpsd: Unable to enable feature", error->GetMessage()); |
| } |
| |
| TEST_F(HpsDaemonTest, EnableFeatureReady) { |
| EXPECT_CALL(*mock_hps_, Enable(0)).WillOnce(Return(true)); |
| brillo::ErrorPtr error; |
| bool result = CallEnableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| } |
| |
| TEST_F(HpsDaemonTest, DisableFeatureNotReady) { |
| EXPECT_CALL(*mock_hps_, Disable(0)).WillOnce(Return(false)); |
| brillo::ErrorPtr error; |
| bool result = CallDisableFeature(&error, 0); |
| EXPECT_FALSE(result); |
| EXPECT_EQ("hpsd: Unable to disable feature", error->GetMessage()); |
| } |
| |
| TEST_F(HpsDaemonTest, DisableFeatureReady) { |
| EXPECT_CALL(*mock_hps_, Disable(0)).WillOnce(Return(true)); |
| brillo::ErrorPtr error; |
| bool result = CallDisableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| } |
| |
| TEST_F(HpsDaemonTest, GetFeatureResultNotReady) { |
| brillo::ErrorPtr error; |
| uint16_t result; |
| |
| EXPECT_CALL(*mock_hps_, Result(0)).WillOnce(Return(-1)); |
| bool call_result = CallGetFeatureResult(&error, 0, &result); |
| EXPECT_FALSE(call_result); |
| EXPECT_EQ("hpsd: Feature result not available", error->GetMessage()); |
| } |
| |
| TEST_F(HpsDaemonTest, GetFeatureResultReady) { |
| brillo::ErrorPtr error; |
| uint16_t result; |
| uint16_t expected_result = RFeat::kValid; |
| |
| EXPECT_CALL(*mock_hps_, Result(0)).WillOnce(Return(expected_result)); |
| bool call_result = CallGetFeatureResult(&error, 0, &result); |
| EXPECT_TRUE(call_result); |
| EXPECT_EQ(expected_result, result); |
| } |
| |
| TEST_F(HpsDaemonTest, TestPollTimer) { |
| { |
| InSequence sequence; |
| EXPECT_CALL(*mock_hps_, Enable(0)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Result(0)) |
| .Times(2) |
| .WillRepeatedly(Return(RFeat::kValid)); |
| EXPECT_CALL(*mock_hps_, Disable(0)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Result(0)).Times(0); |
| } |
| |
| brillo::ErrorPtr error; |
| bool result = CallEnableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| |
| // Advance timer far enough so that the poll timer should fire twice. |
| task_environment_.FastForwardBy( |
| base::TimeDelta::FromMilliseconds(kPollTimeMs * 2)); |
| |
| // Disable the feature, time should no longer fire. |
| result = CallDisableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| |
| // Poll task should no longer fire if we advance the timer. |
| task_environment_.FastForwardBy( |
| base::TimeDelta::FromMilliseconds(kPollTimeMs * 2)); |
| } |
| |
| TEST_F(HpsDaemonTest, TestPollTimerMultipleFeatures) { |
| { |
| InSequence sequence; |
| EXPECT_CALL(*mock_hps_, Enable(0)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Enable(1)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Result(0)).WillOnce(Return(RFeat::kValid)); |
| EXPECT_CALL(*mock_hps_, Result(1)).WillOnce(Return(RFeat::kValid)); |
| EXPECT_CALL(*mock_hps_, Disable(0)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Result(0)).Times(0); |
| EXPECT_CALL(*mock_hps_, Result(1)).WillOnce(Return(RFeat::kValid)); |
| EXPECT_CALL(*mock_hps_, Disable(1)).WillOnce(Return(true)); |
| EXPECT_CALL(*mock_hps_, Result(1)).Times(0); |
| } |
| |
| brillo::ErrorPtr error; |
| |
| // Enable features 0 & 1 |
| bool result = CallEnableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| result = CallEnableFeature(&error, 1); |
| EXPECT_TRUE(result); |
| |
| // Advance timer far enough so that the poll timer should fire. |
| task_environment_.FastForwardBy( |
| base::TimeDelta::FromMilliseconds(kPollTimeMs)); |
| |
| // Disable the feature, timer should no longer fire for feature 0. |
| result = CallDisableFeature(&error, 0); |
| EXPECT_TRUE(result); |
| |
| // Advance timer far enough so that the poll timer should fire. |
| task_environment_.FastForwardBy( |
| base::TimeDelta::FromMilliseconds(kPollTimeMs)); |
| |
| // Disable the feature, timer should no longer fire for feature 1. |
| result = CallDisableFeature(&error, 1); |
| EXPECT_TRUE(result); |
| |
| // Advance time to ensure no more features are firing. |
| task_environment_.FastForwardBy( |
| base::TimeDelta::FromMilliseconds(kPollTimeMs)); |
| } |
| |
| } // namespace hps |