1 #include "sensors/host.hpp" 2 3 #include <chrono> 4 #include <gmock/gmock.h> 5 #include <gtest/gtest.h> 6 #include <memory> 7 #include <sdbusplus/test/sdbus_mock.hpp> 8 #include <string> 9 #include <vector> 10 11 #include "test/helpers.hpp" 12 13 using ::testing::IsNull; 14 using ::testing::Return; 15 using ::testing::StrEq; 16 17 TEST(HostSensorTest, BoringConstructorTest) { 18 // WARN: The host sensor is not presently meant to be created this way, 19 // TODO: Can I move the constructor into private? 20 } 21 22 TEST(HostSensorTest, CreateHostTempSensorTest) { 23 // The normal case for this sensor is to be a temperature sensor, where 24 // the value is treated as a margin sensor. 25 26 sdbusplus::SdBusMock sdbus_mock; 27 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock); 28 std::string name = "fleeting0"; 29 int64_t timeout = 1; 30 const char *objPath = "/asdf/asdf0"; 31 bool defer = false; 32 std::string interface = "xyz.openbmc_project.Sensor.Value"; 33 34 // Scale is the only property we change in the code. Also, 35 // emit_object_added isn't called twice. 36 // Temperature is the default for type, and everything, so those aren't 37 // updated. 38 std::vector<std::string> properties = {"Scale"}; 39 int i; 40 41 // The CreateTemp updates all the properties, however, only Scale is set 42 // to non-default. 43 SetupDbusObject( 44 &sdbus_mock, 45 defer, 46 objPath, 47 interface, 48 properties, 49 &i); 50 51 // This is called during object destruction. 52 EXPECT_CALL(sdbus_mock, 53 sd_bus_emit_object_removed(IsNull(), StrEq(objPath))) 54 .WillOnce(Return(0)); 55 56 std::unique_ptr<Sensor> s = HostSensor::CreateTemp( 57 name, timeout, bus_mock, objPath, defer); 58 } 59 60 TEST(HostSensorTest, VerifyWriteThenReadMatches) { 61 // Verify that when value is updated, the information matches 62 // what we expect when read back. 63 64 sdbusplus::SdBusMock sdbus_mock; 65 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock); 66 std::string name = "fleeting0"; 67 int64_t timeout = 1; 68 const char *objPath = "/asdf/asdf0"; 69 bool defer = false; 70 std::string interface = "xyz.openbmc_project.Sensor.Value"; 71 72 // Scale is the only property we change in the code. Also, 73 // emit_object_added isn't called twice. 74 // Temperature is the default for type, and everything, so those aren't 75 // updated. 76 std::vector<std::string> properties = {"Scale"}; 77 int i; 78 79 SetupDbusObject( 80 &sdbus_mock, 81 defer, 82 objPath, 83 interface, 84 properties, 85 &i); 86 87 EXPECT_CALL(sdbus_mock, 88 sd_bus_emit_object_removed(IsNull(), StrEq(objPath))) 89 .WillOnce(Return(0)); 90 91 std::unique_ptr<Sensor> s = HostSensor::CreateTemp( 92 name, timeout, bus_mock, objPath, defer); 93 94 // Value is updated from dbus calls only (normally). 95 HostSensor *hs = static_cast<HostSensor *>(s.get()); 96 int64_t new_value = 2; 97 98 ReadReturn r = hs->read(); 99 EXPECT_EQ(r.value, 0); 100 101 EXPECT_CALL(sdbus_mock, 102 sd_bus_emit_properties_changed_strv( 103 IsNull(), 104 StrEq(objPath), 105 StrEq(interface), 106 NotNull())) 107 .WillOnce( 108 Invoke([=](sd_bus *bus, 109 const char *path, 110 const char *interface, 111 char **names) { 112 EXPECT_STREQ("Value", names[0]); 113 return 0; 114 }) 115 ); 116 117 std::chrono::high_resolution_clock::time_point t1 = 118 std::chrono::high_resolution_clock::now(); 119 120 hs->value(new_value); 121 r = hs->read(); 122 EXPECT_EQ(r.value, new_value * 0.001); 123 124 auto duration = std::chrono::duration_cast<std::chrono::seconds>( 125 t1 - r.updated).count(); 126 127 // Verify it was updated within the last second. 128 EXPECT_TRUE(duration < 1); 129 } 130