test: pid: zone
Add unit-tests for the PID zone module.
Add zone_mock.
Tested: Ran on quanta-q71l board and it behaved as expected.
Change-Id: I51185b2d2daacea6ffb687e8f38c4fe2b2a1bed3
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/pid/controller.hpp b/pid/controller.hpp
index d02f9cc..fa89ad1 100644
--- a/pid/controller.hpp
+++ b/pid/controller.hpp
@@ -6,7 +6,7 @@
#include "fan.hpp"
#include "ec/pid.hpp"
-class PIDZone;
+class ZoneInterface;
/*
* Base class for PID controllers. Each PID that implements this needs to
@@ -15,7 +15,7 @@
class PIDController
{
public:
- PIDController(const std::string& id, PIDZone* owner)
+ PIDController(const std::string& id, ZoneInterface* owner)
: _owner(owner),
_id(id)
{ }
@@ -47,7 +47,7 @@
}
protected:
- PIDZone* _owner;
+ ZoneInterface* _owner;
private:
// parameters
diff --git a/pid/fancontroller.cpp b/pid/fancontroller.cpp
index 340c6d0..c2dee74 100644
--- a/pid/fancontroller.cpp
+++ b/pid/fancontroller.cpp
@@ -22,7 +22,7 @@
#include "zone.hpp"
std::unique_ptr<PIDController> FanController::CreateFanPid(
- PIDZone* owner,
+ ZoneInterface* owner,
const std::string& id,
std::vector<std::string>& inputs,
ec::pidinfo initial)
@@ -133,7 +133,7 @@
// PidSensorMap for writing.
for (auto& it : _inputs)
{
- auto& sensor = _owner->getSensor(it);
+ auto sensor = _owner->getSensor(it);
sensor->write(static_cast<double>(percent));
}
diff --git a/pid/fancontroller.hpp b/pid/fancontroller.hpp
index b627915..b9b015c 100644
--- a/pid/fancontroller.hpp
+++ b/pid/fancontroller.hpp
@@ -18,14 +18,14 @@
{
public:
static std::unique_ptr<PIDController> CreateFanPid(
- PIDZone* owner,
+ ZoneInterface* owner,
const std::string& id,
std::vector<std::string>& inputs,
ec::pidinfo initial);
FanController(const std::string& id,
std::vector<std::string>& inputs,
- PIDZone* owner)
+ ZoneInterface* owner)
: PIDController(id, owner),
_inputs(inputs),
_direction(FanSpeedDirection::NEUTRAL)
diff --git a/pid/thermalcontroller.cpp b/pid/thermalcontroller.cpp
index 61e5ca9..dee2d4e 100644
--- a/pid/thermalcontroller.cpp
+++ b/pid/thermalcontroller.cpp
@@ -20,7 +20,7 @@
std::unique_ptr<PIDController> ThermalController::CreateThermalPid(
- PIDZone* owner,
+ ZoneInterface* owner,
const std::string& id,
std::vector<std::string>& inputs,
float setpoint,
diff --git a/pid/thermalcontroller.hpp b/pid/thermalcontroller.hpp
index dbfcfc9..32d4a7f 100644
--- a/pid/thermalcontroller.hpp
+++ b/pid/thermalcontroller.hpp
@@ -16,7 +16,7 @@
{
public:
static std::unique_ptr<PIDController> CreateThermalPid(
- PIDZone* owner,
+ ZoneInterface* owner,
const std::string& id,
std::vector<std::string>& inputs,
float setpoint,
@@ -24,7 +24,7 @@
ThermalController(const std::string& id,
std::vector<std::string>& inputs,
- PIDZone* owner)
+ ZoneInterface* owner)
: PIDController(id, owner),
_inputs(inputs)
{ }
diff --git a/pid/zone.cpp b/pid/zone.cpp
index 26bff6a..fdf16fc 100644
--- a/pid/zone.cpp
+++ b/pid/zone.cpp
@@ -208,7 +208,7 @@
for (auto& f : _fanInputs)
{
- auto& sensor = _mgr.getSensor(f);
+ auto sensor = _mgr.getSensor(f);
ReadReturn r = sensor->read();
_cachedValuesByName[f] = r.value;
@@ -240,7 +240,7 @@
for (auto& t : _thermalInputs)
{
- auto& sensor = _mgr.getSensor(t);
+ auto sensor = _mgr.getSensor(t);
ReadReturn r = sensor->read();
int64_t timeout = sensor->GetTimeout();
@@ -316,7 +316,7 @@
}
}
-const std::unique_ptr<Sensor>& PIDZone::getSensor(std::string name)
+Sensor* PIDZone::getSensor(std::string name)
{
return _mgr.getSensor(name);
}
diff --git a/pid/zone.hpp b/pid/zone.hpp
index f6ee5e8..1934a66 100644
--- a/pid/zone.hpp
+++ b/pid/zone.hpp
@@ -23,12 +23,25 @@
sdbusplus::xyz::openbmc_project::Control::server::Mode;
using ModeObject = ServerObject<ModeInterface>;
+class ZoneInterface
+{
+ public:
+ virtual ~ZoneInterface() = default;
+
+ virtual double getCachedValue(const std::string& name) = 0;
+ virtual void addRPMSetPoint(float setpoint) = 0;
+ virtual float getMaxRPMRequest() const = 0;
+ virtual bool getFailSafeMode() const = 0;
+ virtual float getFailSafePercent() const = 0;
+ virtual Sensor* getSensor(std::string name) = 0;
+};
+
/*
* The PIDZone inherits from the Mode object so that it can listen for control
* mode changes. It primarily holds all PID loops and holds the sensor value
* cache that's used per iteration of the PID loops.
*/
-class PIDZone : public ModeObject
+class PIDZone : public ZoneInterface, public ModeObject
{
public:
PIDZone(int64_t zone,
@@ -50,21 +63,21 @@
#endif
}
- float getMaxRPMRequest(void) const;
+ float getMaxRPMRequest(void) const override;
bool getManualMode(void) const;
/* Could put lock around this since it's accessed from two threads, but
* only one reader/one writer.
*/
void setManualMode(bool mode);
- bool getFailSafeMode(void) const;
+ bool getFailSafeMode(void) const override;
int64_t getZoneId(void) const;
- void addRPMSetPoint(float setpoint);
+ void addRPMSetPoint(float setpoint) override;
void clearRPMSetPoints(void);
- float getFailSafePercent(void) const;
+ float getFailSafePercent(void) const override;
float getMinThermalRpmSetPt(void) const;
- const std::unique_ptr<Sensor>& getSensor(std::string name);
+ Sensor* getSensor(std::string name) override;
void determineMaxRPMRequest(void);
void updateFanTelemetry(void);
void updateSensors(void);
@@ -75,7 +88,7 @@
void addFanPID(std::unique_ptr<PIDController> pid);
void addThermalPID(std::unique_ptr<PIDController> pid);
- double getCachedValue(const std::string& name);
+ double getCachedValue(const std::string& name) override;
void addFanInput(std::string fan);
void addThermalInput(std::string therm);
diff --git a/sensors/manager.hpp b/sensors/manager.hpp
index d37787a..ebf4962 100644
--- a/sensors/manager.hpp
+++ b/sensors/manager.hpp
@@ -46,9 +46,9 @@
std::unique_ptr<Sensor> sensor);
// TODO(venture): Should implement read/write by name.
- const std::unique_ptr<Sensor>& getSensor(const std::string& name) const
+ Sensor* getSensor(const std::string& name) const
{
- return _sensorMap.at(name);
+ return _sensorMap.at(name).get();
}
sdbusplus::bus::bus& getPassiveBus(void)
diff --git a/test/Makefile.am b/test/Makefile.am
index 7fdbaf5..ec40421 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -12,7 +12,7 @@
# Run all 'check' test programs
check_PROGRAMS = sensor_manager_unittest sensor_pluggable_unittest \
- sensor_host_unittest util_unittest
+ sensor_host_unittest util_unittest pid_zone_unittest
TESTS = $(check_PROGRAMS)
# Until libconfig is mocked out or replaced, include it.
@@ -27,3 +27,8 @@
util_unittest_SOURCES = util_unittest.cpp
util_unittest_LDADD = $(top_builddir)/util.o
+
+pid_zone_unittest_SOURCES = pid_zone_unittest.cpp
+pid_zone_unittest_LDADD = $(top_builddir)/pid/ec/pid.o \
+ $(top_builddir)/sensors/manager.o $(top_builddir)/pid/controller.o \
+ $(top_builddir)/pid/zone.o
diff --git a/test/helpers.hpp b/test/helpers.hpp
index 931a39e..74c969f 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -49,17 +49,7 @@
.WillOnce(Return(0));
}
- if (properties.empty())
- {
- // We always expect one, but in this case we're not concerned with the
- // output. If there is more than one property update, we should care
- // and the test writer can add the code to trigger the below case.
- EXPECT_CALL(*sdbus_mock,
- sd_bus_emit_properties_changed_strv(IsNull(), StrEq(path),
- StrEq(intf), NotNull()))
- .WillOnce(Return(0));
- }
- else
+ if (!properties.empty())
{
(*index) = 0;
EXPECT_CALL(*sdbus_mock,
diff --git a/test/pid_zone_unittest.cpp b/test/pid_zone_unittest.cpp
new file mode 100644
index 0000000..c511b3c
--- /dev/null
+++ b/test/pid_zone_unittest.cpp
@@ -0,0 +1,422 @@
+#include "pid/zone.hpp"
+
+#include <chrono>
+#include <cstring>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <sdbusplus/test/sdbus_mock.hpp>
+#include <vector>
+
+#include "pid/ec/pid.hpp"
+#include "sensors/manager.hpp"
+#include "test/controller_mock.hpp"
+#include "test/sensor_mock.hpp"
+#include "test/helpers.hpp"
+
+using ::testing::IsNull;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::_;
+
+static std::string modeInterface = "xyz.openbmc_project.Control.Mode";
+
+namespace {
+
+TEST(PidZoneConstructorTest, BoringConstructorTest) {
+ // Build a PID Zone.
+
+ sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode;
+ auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
+ auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
+ auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
+
+ EXPECT_CALL(sdbus_mock_host,
+ sd_bus_add_object_manager(
+ IsNull(),
+ _,
+ StrEq("/xyz/openbmc_project/extsensors")))
+ .WillOnce(Return(0));
+
+ SensorManager m(std::move(bus_mock_passive),
+ std::move(bus_mock_host));
+
+ bool defer = true;
+ const char *objPath = "/path/";
+ int64_t zone = 1;
+ float minThermalRpm = 1000.0;
+ float failSafePercent = 0.75;
+
+ int i;
+ std::vector<std::string> properties;
+ SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface,
+ properties, &i);
+
+ PIDZone p(zone, minThermalRpm, failSafePercent, m, bus_mock_mode, objPath,
+ defer);
+ // Success.
+}
+
+}
+
+class PidZoneTest : public ::testing::Test {
+ protected:
+ PidZoneTest()
+ : property_index(),
+ properties(),
+ sdbus_mock_passive(),
+ sdbus_mock_host(),
+ sdbus_mock_mode()
+ {
+ EXPECT_CALL(sdbus_mock_host,
+ sd_bus_add_object_manager(
+ IsNull(),
+ _,
+ StrEq("/xyz/openbmc_project/extsensors")))
+ .WillOnce(Return(0));
+
+ auto bus_mock_passive =
+ sdbusplus::get_mocked_new(&sdbus_mock_passive);
+ auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
+ auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
+
+ // Compiler weirdly not happy about just instantiating mgr(...);
+ SensorManager m(std::move(bus_mock_passive),
+ std::move(bus_mock_host));
+ mgr = std::move(m);
+
+ SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface,
+ properties, &property_index);
+
+ zone = std::make_unique<PIDZone>(zoneId, minThermalRpm,
+ failSafePercent, mgr,
+ bus_mock_mode, objPath, defer);
+ }
+
+ // unused
+ int property_index;
+ std::vector<std::string> properties;
+
+ sdbusplus::SdBusMock sdbus_mock_passive;
+ sdbusplus::SdBusMock sdbus_mock_host;
+ sdbusplus::SdBusMock sdbus_mock_mode;
+ int64_t zoneId = 1;
+ float minThermalRpm = 1000.0;
+ float failSafePercent = 0.75;
+ bool defer = true;
+ const char *objPath = "/path/";
+ SensorManager mgr;
+
+ std::unique_ptr<PIDZone> zone;
+};
+
+TEST_F(PidZoneTest, GetZoneId_ReturnsExpected) {
+ // Verifies the zoneId returned is what we expect.
+
+ EXPECT_EQ(zoneId, zone->getZoneId());
+}
+
+TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected) {
+ // Verifies that the zone starts in manual mode. Verifies that one can set
+ // the mode.
+ EXPECT_FALSE(zone->getManualMode());
+
+ zone->setManualMode(true);
+ EXPECT_TRUE(zone->getManualMode());
+}
+
+TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected) {
+ // Tests addRPMSetPoint, clearRPMSetPoints, determineMaxRPMRequest
+ // and getMinThermalRpmSetPt.
+
+ // At least one value must be above the minimum thermal setpoint used in
+ // the constructor otherwise it'll choose that value
+ std::vector<float> values = {100, 200, 300, 400, 500, 5000};
+ for (auto v : values)
+ {
+ zone->addRPMSetPoint(v);
+ }
+
+ // This will pull the maximum RPM setpoint request.
+ zone->determineMaxRPMRequest();
+ EXPECT_EQ(5000, zone->getMaxRPMRequest());
+
+ // Clear the values, so it'll choose the minimum thermal setpoint.
+ zone->clearRPMSetPoints();
+
+ // This will go through the RPM set point values and grab the maximum.
+ zone->determineMaxRPMRequest();
+ EXPECT_EQ(zone->getMinThermalRpmSetPt(), zone->getMaxRPMRequest());
+}
+
+TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected) {
+ // Tests adding several RPM setpoints, however, they're all lower than the
+ // configured minimal thermal set-point RPM value.
+
+ std::vector<float> values = {100, 200, 300, 400, 500};
+ for (auto v : values)
+ {
+ zone->addRPMSetPoint(v);
+ }
+
+ // This will pull the maximum RPM setpoint request.
+ zone->determineMaxRPMRequest();
+
+ // Verifies the value returned in the minimal thermal rpm set point.
+ EXPECT_EQ(zone->getMinThermalRpmSetPt(), zone->getMaxRPMRequest());
+}
+
+TEST_F(PidZoneTest, GetFailSafePercent_ReturnsExpected) {
+ // Verify the value used to create the object is stored.
+ EXPECT_EQ(failSafePercent, zone->getFailSafePercent());
+}
+
+TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors) {
+ // This test will add a couple thermal inputs, and verify that the zone
+ // initializes into failsafe mode, and will read each sensor.
+
+ std::string name1 = "temp1";
+ int64_t timeout = 1;
+
+ std::unique_ptr<Sensor> sensor1 =
+ std::make_unique<SensorMock>(name1, timeout);
+ SensorMock *sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
+
+ std::string name2 = "temp2";
+ std::unique_ptr<Sensor> sensor2 =
+ std::make_unique<SensorMock>(name2, timeout);
+ SensorMock *sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
+
+ std::string type = "unchecked";
+ mgr.addSensor(type, name1, std::move(sensor1));
+ EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
+ mgr.addSensor(type, name2, std::move(sensor2));
+ EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
+
+ // Now that the sensors exist, add them to the zone.
+ zone->addThermalInput(name1);
+ zone->addThermalInput(name2);
+
+ // Initialize Zone
+ zone->initializeCache();
+
+ // Verify now in failsafe mode.
+ EXPECT_TRUE(zone->getFailSafeMode());
+
+ ReadReturn r1;
+ r1.value = 10.0;
+ r1.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
+
+ ReadReturn r2;
+ r2.value = 11.0;
+ r2.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
+
+ // Read the sensors, this will put the values into the cache.
+ zone->updateSensors();
+
+ // We should no longer be in failsafe mode.
+ EXPECT_FALSE(zone->getFailSafeMode());
+
+ EXPECT_EQ(r1.value, zone->getCachedValue(name1));
+ EXPECT_EQ(r2.value, zone->getCachedValue(name2));
+}
+
+TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached) {
+ // This will add a couple fan inputs, and verify the values are cached.
+
+ std::string name1 = "fan1";
+ int64_t timeout = 2;
+
+ std::unique_ptr<Sensor> sensor1 =
+ std::make_unique<SensorMock>(name1, timeout);
+ SensorMock *sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
+
+ std::string name2 = "fan2";
+ std::unique_ptr<Sensor> sensor2 =
+ std::make_unique<SensorMock>(name2, timeout);
+ SensorMock *sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
+
+ std::string type = "unchecked";
+ mgr.addSensor(type, name1, std::move(sensor1));
+ EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
+ mgr.addSensor(type, name2, std::move(sensor2));
+ EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
+
+ // Now that the sensors exist, add them to the zone.
+ zone->addFanInput(name1);
+ zone->addFanInput(name2);
+
+ // Initialize Zone
+ zone->initializeCache();
+
+ ReadReturn r1;
+ r1.value = 10.0;
+ r1.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
+
+ ReadReturn r2;
+ r2.value = 11.0;
+ r2.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
+
+ // Method under test will read through each fan sensor for the zone and
+ // cache the values.
+ zone->updateFanTelemetry();
+
+ EXPECT_EQ(r1.value, zone->getCachedValue(name1));
+ EXPECT_EQ(r2.value, zone->getCachedValue(name2));
+}
+
+TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode) {
+ // On the second updateSensors call, the updated timestamp will be beyond
+ // the timeout limit.
+
+ int64_t timeout = 1;
+
+ std::string name1 = "temp1";
+ std::unique_ptr<Sensor> sensor1 =
+ std::make_unique<SensorMock>(name1, timeout);
+ SensorMock *sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
+
+ std::string name2 = "temp2";
+ std::unique_ptr<Sensor> sensor2 =
+ std::make_unique<SensorMock>(name2, timeout);
+ SensorMock *sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
+
+ std::string type = "unchecked";
+ mgr.addSensor(type, name1, std::move(sensor1));
+ EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
+ mgr.addSensor(type, name2, std::move(sensor2));
+ EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
+
+ zone->addThermalInput(name1);
+ zone->addThermalInput(name2);
+
+ // Initialize Zone
+ zone->initializeCache();
+
+ // Verify now in failsafe mode.
+ EXPECT_TRUE(zone->getFailSafeMode());
+
+ ReadReturn r1;
+ r1.value = 10.0;
+ r1.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
+
+ ReadReturn r2;
+ r2.value = 11.0;
+ r2.updated = std::chrono::high_resolution_clock::now();
+ EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
+
+ zone->updateSensors();
+ EXPECT_FALSE(zone->getFailSafeMode());
+
+ // Ok, so we're not in failsafe mode, so let's set updated to the past.
+ // sensor1 will have an updated field older than its timeout value, but
+ // sensor2 will be fine. :D
+ r1.updated -= std::chrono::seconds(3);
+ r2.updated = std::chrono::high_resolution_clock::now();
+
+ EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
+ EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
+
+ // Method under test will read each sensor. One sensor's value is older
+ // than the timeout for that sensor and this triggers failsafe mode.
+ zone->updateSensors();
+ EXPECT_TRUE(zone->getFailSafeMode());
+}
+
+TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected) {
+ // One can grab a sensor from the manager through the zone.
+
+ int64_t timeout = 1;
+
+ std::string name1 = "temp1";
+ std::unique_ptr<Sensor> sensor1 =
+ std::make_unique<SensorMock>(name1, timeout);
+ SensorMock *sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
+
+ std::string type = "unchecked";
+ mgr.addSensor(type, name1, std::move(sensor1));
+ EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
+
+ zone->addThermalInput(name1);
+
+ // Verify method under test returns the pointer we expect.
+ EXPECT_EQ(mgr.getSensor(name1), zone->getSensor(name1));
+}
+
+TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed) {
+ // Tests adding a thermal PID controller to the zone, and verifies it's
+ // touched during processing.
+
+ std::unique_ptr<PIDController> tpid =
+ std::make_unique<ControllerMock>("thermal1", zone.get());
+ ControllerMock *tmock = reinterpret_cast<ControllerMock*>(tpid.get());
+
+ // Access the internal pid configuration to clear it out (unrelated to the
+ // test).
+ ec::pid_info_t* info = tpid->get_pid_info();
+ std::memset(info, 0x00, sizeof(ec::pid_info_t));
+
+ zone->addThermalPID(std::move(tpid));
+
+ EXPECT_CALL(*tmock, setpt_proc()).WillOnce(Return(10.0));
+ EXPECT_CALL(*tmock, input_proc()).WillOnce(Return(11.0));
+ EXPECT_CALL(*tmock, output_proc(_));
+
+ // Method under test will, for each thermal PID, call setpt, input, and
+ // output.
+ zone->process_thermals();
+}
+
+TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed) {
+ // Tests adding a fan PID controller to the zone, and verifies it's
+ // touched during processing.
+
+ std::unique_ptr<PIDController> tpid =
+ std::make_unique<ControllerMock>("fan1", zone.get());
+ ControllerMock *tmock = reinterpret_cast<ControllerMock*>(tpid.get());
+
+ // Access the internal pid configuration to clear it out (unrelated to the
+ // test).
+ ec::pid_info_t* info = tpid->get_pid_info();
+ std::memset(info, 0x00, sizeof(ec::pid_info_t));
+
+ zone->addFanPID(std::move(tpid));
+
+ EXPECT_CALL(*tmock, setpt_proc()).WillOnce(Return(10.0));
+ EXPECT_CALL(*tmock, input_proc()).WillOnce(Return(11.0));
+ EXPECT_CALL(*tmock, output_proc(_));
+
+ // Method under test will, for each fan PID, call setpt, input, and output.
+ zone->process_fans();
+}
+
+TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected) {
+ // The manual(bool) method is inherited from the dbus mode interface.
+
+ // Verifies that someone doesn't remove the internal call to the dbus
+ // object from which we're inheriting.
+ EXPECT_CALL(sdbus_mock_mode,
+ sd_bus_emit_properties_changed_strv(IsNull(), StrEq(objPath),
+ StrEq(modeInterface),
+ NotNull()))
+ .WillOnce(Invoke([&](sd_bus *bus, const char *path,
+ const char *interface, char **names) {
+ EXPECT_STREQ("Manual", names[0]);
+ return 0;
+ }));
+
+ // Method under test will set the manual mode to true and broadcast this
+ // change on dbus.
+ zone->manual(true);
+ EXPECT_TRUE(zone->getManualMode());
+}
+
+TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected) {
+ // This property is implemented by us as read-only, such that trying to
+ // write to it will have no effect.
+ EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode());
+}
diff --git a/test/sensor_manager_unittest.cpp b/test/sensor_manager_unittest.cpp
index b873886..eed26cd 100644
--- a/test/sensor_manager_unittest.cpp
+++ b/test/sensor_manager_unittest.cpp
@@ -23,7 +23,7 @@
IsNull(),
_,
StrEq("/xyz/openbmc_project/extsensors")))
- .WillOnce(Return(0));
+ .WillOnce(Return(0));
SensorManager s(std::move(bus_mock_passive), std::move(bus_mock_host));
// Success
@@ -43,7 +43,7 @@
IsNull(),
_,
StrEq("/xyz/openbmc_project/extsensors")))
- .WillOnce(Return(0));
+ .WillOnce(Return(0));
SensorManager s(std::move(bus_mock_passive), std::move(bus_mock_host));
@@ -55,5 +55,5 @@
Sensor *sensor_ptr = sensor.get();
s.addSensor(type, name, std::move(sensor));
- EXPECT_EQ(s.getSensor(name).get(), sensor_ptr);
+ EXPECT_EQ(s.getSensor(name), sensor_ptr);
}
diff --git a/test/zone_mock.hpp b/test/zone_mock.hpp
new file mode 100644
index 0000000..f08c68f
--- /dev/null
+++ b/test/zone_mock.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <gmock/gmock.h>
+#include <string>
+
+#include "pid/zone.hpp"
+
+class ZoneMock : public ZoneInterface
+{
+ public:
+ virtual ~ZoneMock() = default;
+
+ MOCK_METHOD1(getCachedValue, double(const std::string&));
+ MOCK_METHOD1(addRPMSetPoint, void(float));
+ MOCK_CONST_METHOD0(getMaxRPMRequest, float());
+ MOCK_CONST_METHOD0(getFailSafeMode, bool());
+ MOCK_CONST_METHOD0(getFailSafePercent, float());
+ MOCK_METHOD1(getSensor, Sensor*(std::string));
+};