| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 1 | #include "pid/ec/pid.hpp" | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 2 | #include "pid/zone.hpp" | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 3 | #include "sensors/manager.hpp" | 
|  | 4 | #include "test/controller_mock.hpp" | 
|  | 5 | #include "test/helpers.hpp" | 
|  | 6 | #include "test/sensor_mock.hpp" | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 7 |  | 
| Patrick Venture | a83a3ec | 2020-08-04 09:52:05 -0700 | [diff] [blame] | 8 | #include <sdbusplus/test/sdbus_mock.hpp> | 
|  | 9 |  | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 10 | #include <chrono> | 
|  | 11 | #include <cstring> | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 12 | #include <vector> | 
|  | 13 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 14 | #include <gmock/gmock.h> | 
|  | 15 | #include <gtest/gtest.h> | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 16 |  | 
| Patrick Venture | a076487 | 2020-08-08 07:48:43 -0700 | [diff] [blame] | 17 | namespace pid_control | 
|  | 18 | { | 
|  | 19 | namespace | 
|  | 20 | { | 
|  | 21 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 22 | using ::testing::_; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 23 | using ::testing::IsNull; | 
|  | 24 | using ::testing::Return; | 
|  | 25 | using ::testing::StrEq; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 26 |  | 
|  | 27 | static std::string modeInterface = "xyz.openbmc_project.Control.Mode"; | 
|  | 28 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 29 | namespace | 
|  | 30 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 31 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 32 | TEST(PidZoneConstructorTest, BoringConstructorTest) | 
|  | 33 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 34 | // Build a PID Zone. | 
|  | 35 |  | 
|  | 36 | sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode; | 
|  | 37 | auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive); | 
|  | 38 | auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host); | 
|  | 39 | auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode); | 
|  | 40 |  | 
|  | 41 | EXPECT_CALL(sdbus_mock_host, | 
|  | 42 | sd_bus_add_object_manager( | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 43 | IsNull(), _, StrEq("/xyz/openbmc_project/extsensors"))) | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 44 | .WillOnce(Return(0)); | 
|  | 45 |  | 
| James Feist | 1fe0895 | 2019-05-07 09:17:16 -0700 | [diff] [blame] | 46 | SensorManager m(bus_mock_passive, bus_mock_host); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 47 |  | 
|  | 48 | bool defer = true; | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 49 | const char* objPath = "/path/"; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 50 | int64_t zone = 1; | 
| James Feist | 3484bed | 2019-02-25 13:28:18 -0800 | [diff] [blame] | 51 | double minThermalOutput = 1000.0; | 
| Patrick Venture | 5f59c0f | 2018-11-11 12:55:14 -0800 | [diff] [blame] | 52 | double failSafePercent = 0.75; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 53 |  | 
| James Feist | 0709e2f | 2020-07-08 10:59:45 -0700 | [diff] [blame] | 54 | double d; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 55 | std::vector<std::string> properties; | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 56 | SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, properties, | 
| James Feist | 0709e2f | 2020-07-08 10:59:45 -0700 | [diff] [blame] | 57 | &d); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 58 |  | 
| Patrick Venture | 597ebd6 | 2020-08-11 08:48:19 -0700 | [diff] [blame] | 59 | DbusPidZone p(zone, minThermalOutput, failSafePercent, m, bus_mock_mode, | 
|  | 60 | objPath, defer); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 61 | // Success. | 
|  | 62 | } | 
|  | 63 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 64 | } // namespace | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 65 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 66 | class PidZoneTest : public ::testing::Test | 
|  | 67 | { | 
|  | 68 | protected: | 
|  | 69 | PidZoneTest() : | 
|  | 70 | property_index(), properties(), sdbus_mock_passive(), sdbus_mock_host(), | 
|  | 71 | sdbus_mock_mode() | 
|  | 72 | { | 
|  | 73 | EXPECT_CALL(sdbus_mock_host, | 
|  | 74 | sd_bus_add_object_manager( | 
|  | 75 | IsNull(), _, StrEq("/xyz/openbmc_project/extsensors"))) | 
|  | 76 | .WillOnce(Return(0)); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 77 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 78 | auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive); | 
|  | 79 | auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host); | 
|  | 80 | auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 81 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 82 | // Compiler weirdly not happy about just instantiating mgr(...); | 
| James Feist | 1fe0895 | 2019-05-07 09:17:16 -0700 | [diff] [blame] | 83 | SensorManager m(bus_mock_passive, bus_mock_host); | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 84 | mgr = std::move(m); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 85 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 86 | SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, | 
|  | 87 | properties, &property_index); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 88 |  | 
| Patrick Venture | 597ebd6 | 2020-08-11 08:48:19 -0700 | [diff] [blame] | 89 | zone = std::make_unique<DbusPidZone>(zoneId, minThermalOutput, | 
|  | 90 | failSafePercent, mgr, | 
|  | 91 | bus_mock_mode, objPath, defer); | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 92 | } | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 93 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 94 | // unused | 
| James Feist | 0709e2f | 2020-07-08 10:59:45 -0700 | [diff] [blame] | 95 | double property_index; | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 96 | std::vector<std::string> properties; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 97 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 98 | sdbusplus::SdBusMock sdbus_mock_passive; | 
|  | 99 | sdbusplus::SdBusMock sdbus_mock_host; | 
|  | 100 | sdbusplus::SdBusMock sdbus_mock_mode; | 
|  | 101 | int64_t zoneId = 1; | 
| James Feist | 3484bed | 2019-02-25 13:28:18 -0800 | [diff] [blame] | 102 | double minThermalOutput = 1000.0; | 
| Patrick Venture | 5f59c0f | 2018-11-11 12:55:14 -0800 | [diff] [blame] | 103 | double failSafePercent = 0.75; | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 104 | bool defer = true; | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 105 | const char* objPath = "/path/"; | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 106 | SensorManager mgr; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 107 |  | 
| Patrick Venture | 597ebd6 | 2020-08-11 08:48:19 -0700 | [diff] [blame] | 108 | std::unique_ptr<DbusPidZone> zone; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 109 | }; | 
|  | 110 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 111 | TEST_F(PidZoneTest, GetZoneId_ReturnsExpected) | 
|  | 112 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 113 | // Verifies the zoneId returned is what we expect. | 
|  | 114 |  | 
| Patrick Venture | 0bbeaf8 | 2018-10-30 18:50:31 -0700 | [diff] [blame] | 115 | EXPECT_EQ(zoneId, zone->getZoneID()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 116 | } | 
|  | 117 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 118 | TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected) | 
|  | 119 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 120 | // Verifies that the zone starts in manual mode.  Verifies that one can set | 
|  | 121 | // the mode. | 
|  | 122 | EXPECT_FALSE(zone->getManualMode()); | 
|  | 123 |  | 
|  | 124 | zone->setManualMode(true); | 
|  | 125 | EXPECT_TRUE(zone->getManualMode()); | 
|  | 126 | } | 
|  | 127 |  | 
| Josh Lehan | a4146eb | 2020-10-01 11:49:09 -0700 | [diff] [blame] | 128 | TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode) | 
|  | 129 | { | 
|  | 130 | // Tests adding a fan PID controller to the zone, and verifies it's | 
|  | 131 | // touched during processing. | 
|  | 132 |  | 
|  | 133 | std::unique_ptr<PIDController> tpid = | 
|  | 134 | std::make_unique<ControllerMock>("fan1", zone.get()); | 
|  | 135 | ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); | 
|  | 136 |  | 
|  | 137 | // Access the internal pid configuration to clear it out (unrelated to the | 
|  | 138 | // test). | 
|  | 139 | ec::pid_info_t* info = tpid->getPIDInfo(); | 
|  | 140 | std::memset(info, 0x00, sizeof(ec::pid_info_t)); | 
|  | 141 |  | 
|  | 142 | zone->addFanPID(std::move(tpid)); | 
|  | 143 |  | 
|  | 144 | EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); | 
|  | 145 | EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); | 
|  | 146 | EXPECT_CALL(*tmock, outputProc(_)); | 
|  | 147 |  | 
|  | 148 | // while zone is in auto mode redundant writes should be disabled | 
|  | 149 | EXPECT_FALSE(zone->getRedundantWrite()); | 
|  | 150 |  | 
|  | 151 | // but switching from manual to auto enables a single redundant write | 
|  | 152 | zone->setManualMode(true); | 
|  | 153 | zone->setManualMode(false); | 
|  | 154 | EXPECT_TRUE(zone->getRedundantWrite()); | 
|  | 155 |  | 
|  | 156 | // after one iteration of a pid loop redundant write should be cleared | 
|  | 157 | zone->processFans(); | 
|  | 158 | EXPECT_FALSE(zone->getRedundantWrite()); | 
|  | 159 | } | 
|  | 160 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 161 | TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected) | 
|  | 162 | { | 
| Patrick Venture | f7a2dd5 | 2019-07-16 14:31:13 -0700 | [diff] [blame] | 163 | // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest | 
| Nirav Shah | ccc8bb6 | 2022-02-17 21:06:51 -0800 | [diff] [blame] | 164 | // and getMinThermalSetPoint. | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 165 |  | 
|  | 166 | // At least one value must be above the minimum thermal setpoint used in | 
|  | 167 | // the constructor otherwise it'll choose that value | 
| Patrick Venture | 5f59c0f | 2018-11-11 12:55:14 -0800 | [diff] [blame] | 168 | std::vector<double> values = {100, 200, 300, 400, 500, 5000}; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 169 | for (auto v : values) | 
|  | 170 | { | 
| Nirav Shah | ccc8bb6 | 2022-02-17 21:06:51 -0800 | [diff] [blame] | 171 | zone->addSetPoint(v, ""); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 172 | } | 
|  | 173 |  | 
|  | 174 | // This will pull the maximum RPM setpoint request. | 
| Patrick Venture | f7a2dd5 | 2019-07-16 14:31:13 -0700 | [diff] [blame] | 175 | zone->determineMaxSetPointRequest(); | 
|  | 176 | EXPECT_EQ(5000, zone->getMaxSetPointRequest()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 177 |  | 
|  | 178 | // Clear the values, so it'll choose the minimum thermal setpoint. | 
| Patrick Venture | 9bbf333 | 2019-07-16 10:50:37 -0700 | [diff] [blame] | 179 | zone->clearSetPoints(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 180 |  | 
|  | 181 | // This will go through the RPM set point values and grab the maximum. | 
| Patrick Venture | f7a2dd5 | 2019-07-16 14:31:13 -0700 | [diff] [blame] | 182 | zone->determineMaxSetPointRequest(); | 
| Nirav Shah | ccc8bb6 | 2022-02-17 21:06:51 -0800 | [diff] [blame] | 183 | EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 184 | } | 
|  | 185 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 186 | TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected) | 
|  | 187 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 188 | // Tests adding several RPM setpoints, however, they're all lower than the | 
| Patrick Venture | 7280e27 | 2019-02-11 10:45:32 -0800 | [diff] [blame] | 189 | // configured minimal thermal setpoint RPM value. | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 190 |  | 
| Patrick Venture | 5f59c0f | 2018-11-11 12:55:14 -0800 | [diff] [blame] | 191 | std::vector<double> values = {100, 200, 300, 400, 500}; | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 192 | for (auto v : values) | 
|  | 193 | { | 
| Nirav Shah | ccc8bb6 | 2022-02-17 21:06:51 -0800 | [diff] [blame] | 194 | zone->addSetPoint(v, ""); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
|  | 197 | // This will pull the maximum RPM setpoint request. | 
| Patrick Venture | f7a2dd5 | 2019-07-16 14:31:13 -0700 | [diff] [blame] | 198 | zone->determineMaxSetPointRequest(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 199 |  | 
|  | 200 | // Verifies the value returned in the minimal thermal rpm set point. | 
| Nirav Shah | ccc8bb6 | 2022-02-17 21:06:51 -0800 | [diff] [blame] | 201 | EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 202 | } | 
|  | 203 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 204 | TEST_F(PidZoneTest, GetFailSafePercent_ReturnsExpected) | 
|  | 205 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 206 | // Verify the value used to create the object is stored. | 
|  | 207 | EXPECT_EQ(failSafePercent, zone->getFailSafePercent()); | 
|  | 208 | } | 
|  | 209 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 210 | TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors) | 
|  | 211 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 212 | // This test will add a couple thermal inputs, and verify that the zone | 
|  | 213 | // initializes into failsafe mode, and will read each sensor. | 
|  | 214 |  | 
|  | 215 | std::string name1 = "temp1"; | 
|  | 216 | int64_t timeout = 1; | 
|  | 217 |  | 
|  | 218 | std::unique_ptr<Sensor> sensor1 = | 
|  | 219 | std::make_unique<SensorMock>(name1, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 220 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 221 |  | 
|  | 222 | std::string name2 = "temp2"; | 
|  | 223 | std::unique_ptr<Sensor> sensor2 = | 
|  | 224 | std::make_unique<SensorMock>(name2, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 225 | SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 226 |  | 
|  | 227 | std::string type = "unchecked"; | 
|  | 228 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 229 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 230 | mgr.addSensor(type, name2, std::move(sensor2)); | 
|  | 231 | EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); | 
|  | 232 |  | 
|  | 233 | // Now that the sensors exist, add them to the zone. | 
|  | 234 | zone->addThermalInput(name1); | 
|  | 235 | zone->addThermalInput(name2); | 
|  | 236 |  | 
|  | 237 | // Initialize Zone | 
|  | 238 | zone->initializeCache(); | 
|  | 239 |  | 
|  | 240 | // Verify now in failsafe mode. | 
|  | 241 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 242 |  | 
|  | 243 | ReadReturn r1; | 
|  | 244 | r1.value = 10.0; | 
|  | 245 | r1.updated = std::chrono::high_resolution_clock::now(); | 
|  | 246 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 247 |  | 
|  | 248 | ReadReturn r2; | 
|  | 249 | r2.value = 11.0; | 
|  | 250 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 251 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 252 |  | 
|  | 253 | // Read the sensors, this will put the values into the cache. | 
|  | 254 | zone->updateSensors(); | 
|  | 255 |  | 
|  | 256 | // We should no longer be in failsafe mode. | 
|  | 257 | EXPECT_FALSE(zone->getFailSafeMode()); | 
|  | 258 |  | 
|  | 259 | EXPECT_EQ(r1.value, zone->getCachedValue(name1)); | 
|  | 260 | EXPECT_EQ(r2.value, zone->getCachedValue(name2)); | 
|  | 261 | } | 
|  | 262 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 263 | TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached) | 
|  | 264 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 265 | // This will add a couple fan inputs, and verify the values are cached. | 
|  | 266 |  | 
|  | 267 | std::string name1 = "fan1"; | 
|  | 268 | int64_t timeout = 2; | 
|  | 269 |  | 
|  | 270 | std::unique_ptr<Sensor> sensor1 = | 
|  | 271 | std::make_unique<SensorMock>(name1, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 272 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 273 |  | 
|  | 274 | std::string name2 = "fan2"; | 
|  | 275 | std::unique_ptr<Sensor> sensor2 = | 
|  | 276 | std::make_unique<SensorMock>(name2, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 277 | SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 278 |  | 
|  | 279 | std::string type = "unchecked"; | 
|  | 280 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 281 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 282 | mgr.addSensor(type, name2, std::move(sensor2)); | 
|  | 283 | EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); | 
|  | 284 |  | 
|  | 285 | // Now that the sensors exist, add them to the zone. | 
|  | 286 | zone->addFanInput(name1); | 
|  | 287 | zone->addFanInput(name2); | 
|  | 288 |  | 
|  | 289 | // Initialize Zone | 
|  | 290 | zone->initializeCache(); | 
|  | 291 |  | 
|  | 292 | ReadReturn r1; | 
|  | 293 | r1.value = 10.0; | 
|  | 294 | r1.updated = std::chrono::high_resolution_clock::now(); | 
|  | 295 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 296 |  | 
|  | 297 | ReadReturn r2; | 
|  | 298 | r2.value = 11.0; | 
|  | 299 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 300 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 301 |  | 
|  | 302 | // Method under test will read through each fan sensor for the zone and | 
|  | 303 | // cache the values. | 
|  | 304 | zone->updateFanTelemetry(); | 
|  | 305 |  | 
|  | 306 | EXPECT_EQ(r1.value, zone->getCachedValue(name1)); | 
|  | 307 | EXPECT_EQ(r2.value, zone->getCachedValue(name2)); | 
|  | 308 | } | 
|  | 309 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 310 | TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode) | 
|  | 311 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 312 | // On the second updateSensors call, the updated timestamp will be beyond | 
|  | 313 | // the timeout limit. | 
|  | 314 |  | 
|  | 315 | int64_t timeout = 1; | 
|  | 316 |  | 
|  | 317 | std::string name1 = "temp1"; | 
|  | 318 | std::unique_ptr<Sensor> sensor1 = | 
|  | 319 | std::make_unique<SensorMock>(name1, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 320 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 321 |  | 
|  | 322 | std::string name2 = "temp2"; | 
|  | 323 | std::unique_ptr<Sensor> sensor2 = | 
|  | 324 | std::make_unique<SensorMock>(name2, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 325 | SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 326 |  | 
|  | 327 | std::string type = "unchecked"; | 
|  | 328 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 329 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 330 | mgr.addSensor(type, name2, std::move(sensor2)); | 
|  | 331 | EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); | 
|  | 332 |  | 
|  | 333 | zone->addThermalInput(name1); | 
|  | 334 | zone->addThermalInput(name2); | 
|  | 335 |  | 
|  | 336 | // Initialize Zone | 
|  | 337 | zone->initializeCache(); | 
|  | 338 |  | 
|  | 339 | // Verify now in failsafe mode. | 
|  | 340 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 341 |  | 
|  | 342 | ReadReturn r1; | 
|  | 343 | r1.value = 10.0; | 
|  | 344 | r1.updated = std::chrono::high_resolution_clock::now(); | 
|  | 345 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 346 |  | 
|  | 347 | ReadReturn r2; | 
|  | 348 | r2.value = 11.0; | 
|  | 349 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 350 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 351 |  | 
|  | 352 | zone->updateSensors(); | 
|  | 353 | EXPECT_FALSE(zone->getFailSafeMode()); | 
|  | 354 |  | 
|  | 355 | // Ok, so we're not in failsafe mode, so let's set updated to the past. | 
|  | 356 | // sensor1 will have an updated field older than its timeout value, but | 
|  | 357 | // sensor2 will be fine. :D | 
|  | 358 | r1.updated -= std::chrono::seconds(3); | 
|  | 359 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 360 |  | 
|  | 361 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 362 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 363 |  | 
|  | 364 | // Method under test will read each sensor.  One sensor's value is older | 
|  | 365 | // than the timeout for that sensor and this triggers failsafe mode. | 
|  | 366 | zone->updateSensors(); | 
|  | 367 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 368 | } | 
|  | 369 |  | 
| Will Liang | ded0ab5 | 2019-05-15 17:10:06 +0800 | [diff] [blame] | 370 | TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors) | 
|  | 371 | { | 
|  | 372 | // This will add a couple fan inputs, and verify the values are cached. | 
|  | 373 |  | 
|  | 374 | std::string name1 = "fan1"; | 
|  | 375 | int64_t timeout = 2; | 
|  | 376 |  | 
|  | 377 | std::unique_ptr<Sensor> sensor1 = | 
|  | 378 | std::make_unique<SensorMock>(name1, timeout); | 
|  | 379 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
|  | 380 |  | 
|  | 381 | std::string name2 = "fan2"; | 
|  | 382 | std::unique_ptr<Sensor> sensor2 = | 
|  | 383 | std::make_unique<SensorMock>(name2, timeout); | 
|  | 384 | SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); | 
|  | 385 |  | 
|  | 386 | std::string type = "unchecked"; | 
|  | 387 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 388 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 389 | mgr.addSensor(type, name2, std::move(sensor2)); | 
|  | 390 | EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); | 
|  | 391 |  | 
|  | 392 | // Now that the sensors exist, add them to the zone. | 
|  | 393 | zone->addFanInput(name1); | 
|  | 394 | zone->addFanInput(name2); | 
|  | 395 |  | 
|  | 396 | // Initialize Zone | 
|  | 397 | zone->initializeCache(); | 
|  | 398 |  | 
|  | 399 | // Verify now in failsafe mode. | 
|  | 400 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 401 |  | 
|  | 402 | ReadReturn r1; | 
|  | 403 | r1.value = 10.0; | 
|  | 404 | r1.updated = std::chrono::high_resolution_clock::now(); | 
|  | 405 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 406 |  | 
|  | 407 | ReadReturn r2; | 
|  | 408 | r2.value = 11.0; | 
|  | 409 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 410 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 411 |  | 
|  | 412 | // Method under test will read through each fan sensor for the zone and | 
|  | 413 | // cache the values. | 
|  | 414 | zone->updateFanTelemetry(); | 
|  | 415 |  | 
|  | 416 | // We should no longer be in failsafe mode. | 
|  | 417 | EXPECT_FALSE(zone->getFailSafeMode()); | 
|  | 418 |  | 
|  | 419 | EXPECT_EQ(r1.value, zone->getCachedValue(name1)); | 
|  | 420 | EXPECT_EQ(r2.value, zone->getCachedValue(name2)); | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode) | 
|  | 424 | { | 
|  | 425 | // This will add a couple fan inputs, and verify the values are cached. | 
|  | 426 |  | 
|  | 427 | std::string name1 = "fan1"; | 
|  | 428 | int64_t timeout = 2; | 
|  | 429 |  | 
|  | 430 | std::unique_ptr<Sensor> sensor1 = | 
|  | 431 | std::make_unique<SensorMock>(name1, timeout); | 
|  | 432 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
|  | 433 |  | 
|  | 434 | std::string name2 = "fan2"; | 
|  | 435 | std::unique_ptr<Sensor> sensor2 = | 
|  | 436 | std::make_unique<SensorMock>(name2, timeout); | 
|  | 437 | SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); | 
|  | 438 |  | 
|  | 439 | std::string type = "unchecked"; | 
|  | 440 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 441 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 442 | mgr.addSensor(type, name2, std::move(sensor2)); | 
|  | 443 | EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); | 
|  | 444 |  | 
|  | 445 | // Now that the sensors exist, add them to the zone. | 
|  | 446 | zone->addFanInput(name1); | 
|  | 447 | zone->addFanInput(name2); | 
|  | 448 |  | 
|  | 449 | // Initialize Zone | 
|  | 450 | zone->initializeCache(); | 
|  | 451 |  | 
|  | 452 | // Verify now in failsafe mode. | 
|  | 453 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 454 |  | 
|  | 455 | ReadReturn r1; | 
|  | 456 | r1.value = 10.0; | 
|  | 457 | r1.updated = std::chrono::high_resolution_clock::now(); | 
|  | 458 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 459 |  | 
|  | 460 | ReadReturn r2; | 
|  | 461 | r2.value = 11.0; | 
|  | 462 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 463 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 464 |  | 
|  | 465 | // Method under test will read through each fan sensor for the zone and | 
|  | 466 | // cache the values. | 
|  | 467 | zone->updateFanTelemetry(); | 
|  | 468 |  | 
|  | 469 | // We should no longer be in failsafe mode. | 
|  | 470 | EXPECT_FALSE(zone->getFailSafeMode()); | 
|  | 471 |  | 
|  | 472 | r1.updated -= std::chrono::seconds(3); | 
|  | 473 | r2.updated = std::chrono::high_resolution_clock::now(); | 
|  | 474 |  | 
|  | 475 | EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); | 
|  | 476 | EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); | 
|  | 477 |  | 
|  | 478 | zone->updateFanTelemetry(); | 
|  | 479 | EXPECT_TRUE(zone->getFailSafeMode()); | 
|  | 480 | } | 
|  | 481 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 482 | TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected) | 
|  | 483 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 484 | // One can grab a sensor from the manager through the zone. | 
|  | 485 |  | 
|  | 486 | int64_t timeout = 1; | 
|  | 487 |  | 
|  | 488 | std::string name1 = "temp1"; | 
|  | 489 | std::unique_ptr<Sensor> sensor1 = | 
|  | 490 | std::make_unique<SensorMock>(name1, timeout); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 491 | SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 492 |  | 
|  | 493 | std::string type = "unchecked"; | 
|  | 494 | mgr.addSensor(type, name1, std::move(sensor1)); | 
|  | 495 | EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); | 
|  | 496 |  | 
|  | 497 | zone->addThermalInput(name1); | 
|  | 498 |  | 
|  | 499 | // Verify method under test returns the pointer we expect. | 
|  | 500 | EXPECT_EQ(mgr.getSensor(name1), zone->getSensor(name1)); | 
|  | 501 | } | 
|  | 502 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 503 | TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed) | 
|  | 504 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 505 | // Tests adding a thermal PID controller to the zone, and verifies it's | 
|  | 506 | // touched during processing. | 
|  | 507 |  | 
|  | 508 | std::unique_ptr<PIDController> tpid = | 
|  | 509 | std::make_unique<ControllerMock>("thermal1", zone.get()); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 510 | ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 511 |  | 
|  | 512 | // Access the internal pid configuration to clear it out (unrelated to the | 
|  | 513 | // test). | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 514 | ec::pid_info_t* info = tpid->getPIDInfo(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 515 | std::memset(info, 0x00, sizeof(ec::pid_info_t)); | 
|  | 516 |  | 
|  | 517 | zone->addThermalPID(std::move(tpid)); | 
|  | 518 |  | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 519 | EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); | 
|  | 520 | EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); | 
|  | 521 | EXPECT_CALL(*tmock, outputProc(_)); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 522 |  | 
|  | 523 | // Method under test will, for each thermal PID, call setpt, input, and | 
|  | 524 | // output. | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 525 | zone->processThermals(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 526 | } | 
|  | 527 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 528 | TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed) | 
|  | 529 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 530 | // Tests adding a fan PID controller to the zone, and verifies it's | 
|  | 531 | // touched during processing. | 
|  | 532 |  | 
|  | 533 | std::unique_ptr<PIDController> tpid = | 
|  | 534 | std::make_unique<ControllerMock>("fan1", zone.get()); | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 535 | ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 536 |  | 
|  | 537 | // Access the internal pid configuration to clear it out (unrelated to the | 
|  | 538 | // test). | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 539 | ec::pid_info_t* info = tpid->getPIDInfo(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 540 | std::memset(info, 0x00, sizeof(ec::pid_info_t)); | 
|  | 541 |  | 
|  | 542 | zone->addFanPID(std::move(tpid)); | 
|  | 543 |  | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 544 | EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); | 
|  | 545 | EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); | 
|  | 546 | EXPECT_CALL(*tmock, outputProc(_)); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 547 |  | 
|  | 548 | // Method under test will, for each fan PID, call setpt, input, and output. | 
| Patrick Venture | 563a356 | 2018-10-30 09:31:26 -0700 | [diff] [blame] | 549 | zone->processFans(); | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 550 | } | 
|  | 551 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 552 | TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected) | 
|  | 553 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 554 | // The manual(bool) method is inherited from the dbus mode interface. | 
|  | 555 |  | 
|  | 556 | // Verifies that someone doesn't remove the internal call to the dbus | 
|  | 557 | // object from which we're inheriting. | 
|  | 558 | EXPECT_CALL(sdbus_mock_mode, | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 559 | sd_bus_emit_properties_changed_strv( | 
|  | 560 | IsNull(), StrEq(objPath), StrEq(modeInterface), NotNull())) | 
| Patrick Venture | e2ec0f6 | 2018-09-04 12:30:27 -0700 | [diff] [blame] | 561 | .WillOnce(Invoke([&](sd_bus* bus, const char* path, | 
| Hao Jiang | 841931d | 2021-02-24 14:45:40 -0800 | [diff] [blame] | 562 | const char* interface, const char** names) { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 563 | EXPECT_STREQ("Manual", names[0]); | 
|  | 564 | return 0; | 
|  | 565 | })); | 
|  | 566 |  | 
|  | 567 | // Method under test will set the manual mode to true and broadcast this | 
|  | 568 | // change on dbus. | 
|  | 569 | zone->manual(true); | 
|  | 570 | EXPECT_TRUE(zone->getManualMode()); | 
|  | 571 | } | 
|  | 572 |  | 
| Patrick Venture | da4a5dd | 2018-08-31 09:42:48 -0700 | [diff] [blame] | 573 | TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected) | 
|  | 574 | { | 
| Patrick Venture | a58197c | 2018-06-11 15:29:45 -0700 | [diff] [blame] | 575 | // This property is implemented by us as read-only, such that trying to | 
|  | 576 | // write to it will have no effect. | 
|  | 577 | EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode()); | 
|  | 578 | } | 
| Patrick Venture | a076487 | 2020-08-08 07:48:43 -0700 | [diff] [blame] | 579 |  | 
|  | 580 | } // namespace | 
|  | 581 | } // namespace pid_control |