1 #include "dbus/dbuspassive.hpp" 2 #include "test/dbushelper_mock.hpp" 3 4 #include <sdbusplus/test/sdbus_mock.hpp> 5 #include <string> 6 7 #include <gmock/gmock.h> 8 #include <gtest/gtest.h> 9 10 using ::testing::_; 11 using ::testing::InSequence; 12 using ::testing::Invoke; 13 using ::testing::IsNull; 14 using ::testing::NotNull; 15 using ::testing::Return; 16 using ::testing::StrEq; 17 18 std::string SensorIntf = "xyz.openbmc_project.Sensor.Value"; 19 20 TEST(DbusPassiveTest, FactoryFailsWithInvalidType) 21 { 22 // Verify the type is checked by the factory. 23 24 sdbusplus::SdBusMock sdbus_mock; 25 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock); 26 std::string type = "invalid"; 27 std::string id = "id"; 28 29 DbusHelperMock helper; 30 31 std::unique_ptr<ReadInterface> ri = 32 DbusPassive::CreateDbusPassive(bus_mock, type, id, &helper); 33 34 EXPECT_EQ(ri, nullptr); 35 } 36 37 TEST(DbusPassiveTest, BoringConstructorTest) 38 { 39 // Just build the object, which should be avoided as this does no error 40 // checking at present. 41 42 sdbusplus::SdBusMock sdbus_mock; 43 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock); 44 std::string type = "invalid"; 45 std::string id = "id"; 46 std::string path = "/xyz/openbmc_project/sensors/unknown/id"; 47 48 DbusHelperMock helper; 49 EXPECT_CALL(helper, GetService(_, StrEq(SensorIntf), StrEq(path))) 50 .WillOnce(Return("asdf")); 51 52 EXPECT_CALL(helper, GetProperties(_, StrEq("asdf"), StrEq(path), NotNull())) 53 .WillOnce( 54 Invoke([&](sdbusplus::bus::bus& bus, const std::string& service, 55 const std::string& path, struct SensorProperties* prop) { 56 prop->scale = -3; 57 prop->value = 10; 58 prop->unit = "x"; 59 })); 60 61 DbusPassive(bus_mock, type, id, &helper); 62 // Success 63 } 64 65 class DbusPassiveTestObj : public ::testing::Test 66 { 67 protected: 68 DbusPassiveTestObj() : 69 sdbus_mock(), 70 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), helper() 71 { 72 EXPECT_CALL(helper, GetService(_, StrEq(SensorIntf), StrEq(path))) 73 .WillOnce(Return("asdf")); 74 75 EXPECT_CALL(helper, 76 GetProperties(_, StrEq("asdf"), StrEq(path), NotNull())) 77 .WillOnce(Invoke( 78 [&](sdbusplus::bus::bus& bus, const std::string& service, 79 const std::string& path, struct SensorProperties* prop) { 80 prop->scale = _scale; 81 prop->value = _value; 82 prop->unit = "x"; 83 })); 84 85 ri = DbusPassive::CreateDbusPassive(bus_mock, type, id, &helper); 86 passive = reinterpret_cast<DbusPassive*>(ri.get()); 87 EXPECT_FALSE(passive == nullptr); 88 } 89 90 sdbusplus::SdBusMock sdbus_mock; 91 sdbusplus::bus::bus bus_mock; 92 DbusHelperMock helper; 93 std::string type = "temp"; 94 std::string id = "id"; 95 std::string path = "/xyz/openbmc_project/sensors/temperature/id"; 96 int64_t _scale = -3; 97 int64_t _value = 10; 98 99 std::unique_ptr<ReadInterface> ri; 100 DbusPassive* passive; 101 }; 102 103 TEST_F(DbusPassiveTestObj, ReadReturnsExpectedValues) 104 { 105 // Verify read is returning the values. 106 ReadReturn v; 107 v.value = 0.01; 108 // TODO: updated is set when the value is created, so we can range check 109 // it. 110 ReadReturn r = passive->read(); 111 EXPECT_EQ(v.value, r.value); 112 } 113 114 TEST_F(DbusPassiveTestObj, SetValueUpdatesValue) 115 { 116 // Verify setvalue does as advertised. 117 118 double value = 0.01; 119 passive->setValue(value); 120 121 // TODO: updated is set when the value is set, so we can range check it. 122 ReadReturn r = passive->read(); 123 EXPECT_EQ(value, r.value); 124 } 125 126 TEST_F(DbusPassiveTestObj, GetScaleReturnsExpectedValue) 127 { 128 // Verify the scale is returned as expected. 129 EXPECT_EQ(_scale, passive->getScale()); 130 } 131 132 TEST_F(DbusPassiveTestObj, GetIdReturnsExpectedValue) 133 { 134 // Verify getId returns the expected value. 135 EXPECT_EQ(id, passive->getId()); 136 } 137 138 TEST_F(DbusPassiveTestObj, VerifyHandlesDbusSignal) 139 { 140 // The dbus passive sensor listens for updates and if it's the Value 141 // property, it needs to handle it. 142 143 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull())) 144 .WillOnce(Return(nullptr)); 145 sdbusplus::message::message msg(nullptr, &sdbus_mock); 146 147 const char* Value = "Value"; 148 int64_t xValue = 10000; 149 const char* intf = "xyz.openbmc_project.Sensor.Value"; 150 // string, std::map<std::string, sdbusplus::message::variant<int64_t>> 151 // msg.read(msgSensor, msgData); 152 153 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull())) 154 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 155 const char** s = static_cast<const char**>(p); 156 // Read the first parameter, the string. 157 *s = intf; 158 return 0; 159 })) 160 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 161 const char** s = static_cast<const char**>(p); 162 *s = Value; 163 // Read the string in the pair (dictionary). 164 return 0; 165 })); 166 167 // std::map 168 EXPECT_CALL(sdbus_mock, 169 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}"))) 170 .WillOnce(Return(0)); 171 172 // while !at_end() 173 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0)) 174 .WillOnce(Return(0)) 175 .WillOnce(Return(1)); // So it exits the loop after reading one pair. 176 177 // std::pair 178 EXPECT_CALL(sdbus_mock, 179 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv"))) 180 .WillOnce(Return(0)); 181 182 EXPECT_CALL(sdbus_mock, 183 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x"))) 184 .WillOnce(Return(1)); 185 EXPECT_CALL(sdbus_mock, 186 sd_bus_message_enter_container(IsNull(), 'v', StrEq("x"))) 187 .WillOnce(Return(0)); 188 189 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull())) 190 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 191 int64_t* s = static_cast<int64_t*>(p); 192 *s = xValue; 193 return 0; 194 })); 195 196 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull())) 197 .WillOnce(Return(0)) /* variant. */ 198 .WillOnce(Return(0)) /* std::pair */ 199 .WillOnce(Return(0)); /* std::map */ 200 201 int rv = HandleSensorValue(msg, passive); 202 EXPECT_EQ(rv, 0); // It's always 0. 203 204 ReadReturn r = passive->read(); 205 EXPECT_EQ(10, r.value); 206 } 207 208 TEST_F(DbusPassiveTestObj, VerifyIgnoresOtherPropertySignal) 209 { 210 // The dbus passive sensor listens for updates and if it's the Value 211 // property, it needs to handle it. In this case, it won't be. 212 213 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull())) 214 .WillOnce(Return(nullptr)); 215 sdbusplus::message::message msg(nullptr, &sdbus_mock); 216 217 const char* Scale = "Scale"; 218 int64_t xScale = -6; 219 const char* intf = "xyz.openbmc_project.Sensor.Value"; 220 // string, std::map<std::string, sdbusplus::message::variant<int64_t>> 221 // msg.read(msgSensor, msgData); 222 223 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull())) 224 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 225 const char** s = static_cast<const char**>(p); 226 // Read the first parameter, the string. 227 *s = intf; 228 return 0; 229 })) 230 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 231 const char** s = static_cast<const char**>(p); 232 *s = Scale; 233 // Read the string in the pair (dictionary). 234 return 0; 235 })); 236 237 // std::map 238 EXPECT_CALL(sdbus_mock, 239 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}"))) 240 .WillOnce(Return(0)); 241 242 // while !at_end() 243 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0)) 244 .WillOnce(Return(0)) 245 .WillOnce(Return(1)); // So it exits the loop after reading one pair. 246 247 // std::pair 248 EXPECT_CALL(sdbus_mock, 249 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv"))) 250 .WillOnce(Return(0)); 251 252 EXPECT_CALL(sdbus_mock, 253 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x"))) 254 .WillOnce(Return(1)); 255 EXPECT_CALL(sdbus_mock, 256 sd_bus_message_enter_container(IsNull(), 'v', StrEq("x"))) 257 .WillOnce(Return(0)); 258 259 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull())) 260 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 261 int64_t* s = static_cast<int64_t*>(p); 262 *s = xScale; 263 return 0; 264 })); 265 266 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull())) 267 .WillOnce(Return(0)) /* variant. */ 268 .WillOnce(Return(0)) /* std::pair */ 269 .WillOnce(Return(0)); /* std::map */ 270 271 int rv = HandleSensorValue(msg, passive); 272 EXPECT_EQ(rv, 0); // It's always 0. 273 274 ReadReturn r = passive->read(); 275 EXPECT_EQ(0.01, r.value); 276 } 277