conf: add ignoreDbusMinMax option

Add an optional field to the sensor configuration, s.t. it'll tell a
dbus passive sensor to ignore the MinValue and MaxValue properties from
dbus.

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: Ia6a8c802c2dc5bf41e5e860b21d7764cc09e6b6b
diff --git a/conf.hpp b/conf.hpp
index 95bdeaa..559afaa 100644
--- a/conf.hpp
+++ b/conf.hpp
@@ -24,6 +24,7 @@
     int64_t min;
     int64_t max;
     int64_t timeout;
+    bool ignoreDbusMinMax;
 };
 
 /*
diff --git a/configure.md b/configure.md
index f33ec92..7c713f8 100644
--- a/configure.md
+++ b/configure.md
@@ -18,7 +18,8 @@
         "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1",
         "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm1",
         "min": 0,
-        "max": 255
+        "max": 255,
+        "ignoreDbusMinMax": true
     },
     {
         "name": "fan2",
@@ -33,7 +34,7 @@
 ```
 
 A sensor has a `name`, a `type`, a `readPath`, a `writePath`, a `minimum` value,
-a `maximum` value, and a `timeout`.
+a `maximum` value, a `timeout`, and a `ignoreDbusMinMax` value.
 
 The `name` is used to reference the sensor in the zone portion of the
 configuration.
@@ -114,6 +115,11 @@
 to handle the case where it doesn't know what to do -- as it doesn't have all
 its inputs.
 
+The `ignoreDbusMinMax` value is optional and defaults to false.  The dbus
+passive sensors check for a `MinValue` and `MaxValue` and scale the incoming
+values via these.  Setting this property to true will ignore `MinValue` and
+`MaxValue` from dbus and therefore won't call any passive value scaling.
+
 ### Zones
 
 ```
diff --git a/dbus/dbuspassive.cpp b/dbus/dbuspassive.cpp
index c199563..806ef40 100644
--- a/dbus/dbuspassive.cpp
+++ b/dbus/dbuspassive.cpp
@@ -61,6 +61,13 @@
         return nullptr;
     }
 
+    /* if these values are zero, they're ignored. */
+    if (info->ignoreDbusMinMax)
+    {
+        settings.min = 0;
+        settings.max = 0;
+    }
+
     return std::make_unique<DbusPassive>(bus, type, id, helper, settings,
                                          failed, path, redundancy);
 }
diff --git a/sensors/buildjson.cpp b/sensors/buildjson.cpp
index 2dc5a37..482173d 100644
--- a/sensors/buildjson.cpp
+++ b/sensors/buildjson.cpp
@@ -42,9 +42,19 @@
         j.at("writePath").get_to(s.writePath);
     }
 
+    /* Default to not ignore dbus MinValue/MaxValue - only used by passive
+     * sensors.
+     */
+    s.ignoreDbusMinMax = false;
     s.min = 0;
     s.max = 0;
 
+    auto ignore = j.find("ignoreDbusMinMax");
+    if (ignore != j.end())
+    {
+        j.at("ignoreDbusMinMax").get_to(s.ignoreDbusMinMax);
+    }
+
     /* The min field is optional in a configuration. */
     auto min = j.find("min");
     if (min != j.end())
diff --git a/test/dbus_passive_unittest.cpp b/test/dbus_passive_unittest.cpp
index 84557ee..7b82c74 100644
--- a/test/dbus_passive_unittest.cpp
+++ b/test/dbus_passive_unittest.cpp
@@ -2,6 +2,7 @@
 #include "dbus/dbuspassive.hpp"
 #include "test/dbushelper_mock.hpp"
 
+#include <functional>
 #include <sdbusplus/test/sdbus_mock.hpp>
 #include <string>
 #include <variant>
@@ -72,6 +73,8 @@
                     prop->scale = _scale;
                     prop->value = _value;
                     prop->unit = "x";
+                    prop->min = 0;
+                    prop->max = 0;
                 }));
         EXPECT_CALL(helper, thresholdsAsserted(_, StrEq("asdf"), StrEq(path)))
             .WillOnce(Return(false));
@@ -131,6 +134,11 @@
     EXPECT_EQ(id, passive->getID());
 }
 
+TEST_F(DbusPassiveTestObj, GetMinValueReturnsExpectedValue)
+{
+    EXPECT_DOUBLE_EQ(0, passive->getMin());
+}
+
 TEST_F(DbusPassiveTestObj, VerifyHandlesDbusSignal)
 {
     // The dbus passive sensor listens for updates and if it's the Value
@@ -418,3 +426,105 @@
     bool failed = passive->getFailed();
     EXPECT_EQ(failed, false);
 }
+
+void GetPropertiesMax3k(sdbusplus::bus::bus& bus, const std::string& service,
+                        const std::string& path, SensorProperties* prop)
+{
+    prop->scale = -3;
+    prop->value = 10;
+    prop->unit = "x";
+    prop->min = 0;
+    prop->max = 3000;
+}
+
+using GetPropertiesFunction =
+    std::function<void(sdbusplus::bus::bus&, const std::string&,
+                       const std::string&, SensorProperties*)>;
+
+// TODO: There is definitely a cleaner way to do this.
+class DbusPassiveTest3kMaxObj : public ::testing::Test
+{
+  protected:
+    DbusPassiveTest3kMaxObj() :
+        sdbus_mock(),
+        bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), helper()
+    {
+        EXPECT_CALL(helper, getService(_, StrEq(SensorIntf), StrEq(path)))
+            .WillOnce(Return("asdf"));
+
+        EXPECT_CALL(helper,
+                    getProperties(_, StrEq("asdf"), StrEq(path), NotNull()))
+            .WillOnce(_getProps);
+        EXPECT_CALL(helper, thresholdsAsserted(_, StrEq("asdf"), StrEq(path)))
+            .WillOnce(Return(false));
+
+        auto info = conf::SensorConfig();
+        ri = DbusPassive::createDbusPassive(bus_mock, type, id, &helper, &info,
+                                            nullptr);
+        passive = reinterpret_cast<DbusPassive*>(ri.get());
+        EXPECT_FALSE(passive == nullptr);
+    }
+
+    sdbusplus::SdBusMock sdbus_mock;
+    sdbusplus::bus::bus bus_mock;
+    DbusHelperMock helper;
+    std::string type = "temp";
+    std::string id = "id";
+    std::string path = "/xyz/openbmc_project/sensors/temperature/id";
+    int64_t _scale = -3;
+    int64_t _value = 10;
+
+    std::unique_ptr<ReadInterface> ri;
+    DbusPassive* passive;
+    GetPropertiesFunction _getProps = &GetPropertiesMax3k;
+};
+
+TEST_F(DbusPassiveTest3kMaxObj, ReadMinAndMaxReturnsExpected)
+{
+    EXPECT_DOUBLE_EQ(0, passive->getMin());
+    EXPECT_DOUBLE_EQ(3, passive->getMax());
+}
+
+class DbusPassiveTest3kMaxIgnoredObj : public ::testing::Test
+{
+  protected:
+    DbusPassiveTest3kMaxIgnoredObj() :
+        sdbus_mock(),
+        bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), helper()
+    {
+        EXPECT_CALL(helper, getService(_, StrEq(SensorIntf), StrEq(path)))
+            .WillOnce(Return("asdf"));
+
+        EXPECT_CALL(helper,
+                    getProperties(_, StrEq("asdf"), StrEq(path), NotNull()))
+            .WillOnce(_getProps);
+        EXPECT_CALL(helper, thresholdsAsserted(_, StrEq("asdf"), StrEq(path)))
+            .WillOnce(Return(false));
+
+        auto info = conf::SensorConfig();
+        info.ignoreDbusMinMax = true;
+        ri = DbusPassive::createDbusPassive(bus_mock, type, id, &helper, &info,
+                                            nullptr);
+        passive = reinterpret_cast<DbusPassive*>(ri.get());
+        EXPECT_FALSE(passive == nullptr);
+    }
+
+    sdbusplus::SdBusMock sdbus_mock;
+    sdbusplus::bus::bus bus_mock;
+    DbusHelperMock helper;
+    std::string type = "temp";
+    std::string id = "id";
+    std::string path = "/xyz/openbmc_project/sensors/temperature/id";
+    int64_t _scale = -3;
+    int64_t _value = 10;
+
+    std::unique_ptr<ReadInterface> ri;
+    DbusPassive* passive;
+    GetPropertiesFunction _getProps = &GetPropertiesMax3k;
+};
+
+TEST_F(DbusPassiveTest3kMaxIgnoredObj, ReadMinAndMaxReturnsExpected)
+{
+    EXPECT_DOUBLE_EQ(0, passive->getMin());
+    EXPECT_DOUBLE_EQ(0, passive->getMax());
+}
diff --git a/test/sensors_json_unittest.cpp b/test/sensors_json_unittest.cpp
index 0e8ae71..4777ae3 100644
--- a/test/sensors_json_unittest.cpp
+++ b/test/sensors_json_unittest.cpp
@@ -47,11 +47,39 @@
     EXPECT_EQ(output["fan1"].max, 255);
     EXPECT_EQ(output["fan1"].timeout,
               Sensor::getDefaultTimeout(output["fan1"].type));
+    EXPECT_EQ(output["fan1"].ignoreDbusMinMax, false);
+}
+
+TEST(SensorsFromJson, IgnoreDbusSensor)
+{
+    auto j2 = R"(
+      {
+        "sensors": [{
+            "name": "fan1",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1",
+            "ignoreDbusMinMax": true
+        }]
+      }
+    )"_json;
+
+    auto output = buildSensorsFromJson(j2);
+    EXPECT_EQ(1, output.size());
+    EXPECT_EQ(output["fan1"].type, "fan");
+    EXPECT_EQ(output["fan1"].readPath,
+              "/xyz/openbmc_project/sensors/fan_tach/fan1");
+    EXPECT_EQ(output["fan1"].writePath, "");
+    EXPECT_EQ(output["fan1"].min, 0);
+    EXPECT_EQ(output["fan1"].max, 0);
+    EXPECT_EQ(output["fan1"].timeout,
+              Sensor::getDefaultTimeout(output["fan1"].type));
+    EXPECT_EQ(output["fan1"].ignoreDbusMinMax, true);
 }
 
 TEST(SensorsFromJson, validateOptionalFields)
 {
-    // The writePath, min, max, timeout fields are optional.
+    // The writePath, min, max, timeout, and ignoreDbusMinMax fields are
+    // optional.
 
     auto j2 = R"(
       {
@@ -73,6 +101,7 @@
     EXPECT_EQ(output["fan1"].max, 0);
     EXPECT_EQ(output["fan1"].timeout,
               Sensor::getDefaultTimeout(output["fan1"].type));
+    EXPECT_EQ(output["fan1"].ignoreDbusMinMax, false);
 }
 
 TEST(SensorsFromJson, twoSensors)