1 #include "propertywatchtest.hpp" 2 3 #include "propertywatchimpl.hpp" 4 5 #include <array> 6 #include <functional> 7 8 using namespace std::string_literals; 9 using namespace phosphor::dbus::monitoring; 10 11 const std::array<std::string, 4> paths = { 12 "/xyz/openbmc_project/testing/inst1"s, 13 "/xyz/openbmc_project/testing/inst2"s, 14 "/xyz/openbmc_project/testing/inst3"s, 15 "/xyz/openbmc_project/testing/inst4"s, 16 }; 17 18 const std::array<std::string, 2> interfaces = { 19 "xyz.openbmc_project.Iface1"s, 20 "xyz.openbmc_project.Iface2"s, 21 }; 22 23 const std::array<std::string, 2> properties = { 24 "Value1"s, 25 "Value2"s, 26 }; 27 28 const std::string meta; 29 30 std::array<std::tuple<std::any, std::any>, 8> storage = {}; 31 32 const PropertyIndex watchIndex = { 33 { 34 {PropertyIndex::key_type{paths[0], interfaces[0], properties[0]}, 35 PropertyIndex::mapped_type{meta, meta, storage[0]}}, 36 {PropertyIndex::key_type{paths[0], interfaces[1], properties[1]}, 37 PropertyIndex::mapped_type{meta, meta, storage[1]}}, 38 {PropertyIndex::key_type{paths[1], interfaces[0], properties[0]}, 39 PropertyIndex::mapped_type{meta, meta, storage[2]}}, 40 {PropertyIndex::key_type{paths[1], interfaces[1], properties[1]}, 41 PropertyIndex::mapped_type{meta, meta, storage[3]}}, 42 {PropertyIndex::key_type{paths[2], interfaces[0], properties[0]}, 43 PropertyIndex::mapped_type{meta, meta, storage[4]}}, 44 {PropertyIndex::key_type{paths[2], interfaces[1], properties[1]}, 45 PropertyIndex::mapped_type{meta, meta, storage[5]}}, 46 {PropertyIndex::key_type{paths[3], interfaces[0], properties[0]}, 47 PropertyIndex::mapped_type{meta, meta, storage[6]}}, 48 {PropertyIndex::key_type{paths[3], interfaces[1], properties[1]}, 49 PropertyIndex::mapped_type{meta, meta, storage[7]}}, 50 }, 51 }; 52 53 template <typename T> 54 struct Values 55 { 56 }; 57 template <> 58 struct Values<uint8_t> 59 { 60 static auto& get(size_t i) 61 { 62 static const std::array<uint8_t, 8> values = { 63 {0, 1, 2, 3, 4, 5, 6, 7}, 64 }; 65 return values[i]; 66 } 67 }; 68 69 template <> 70 struct Values<uint16_t> 71 { 72 static auto& get(size_t i) 73 { 74 static const std::array<uint16_t, 8> values = { 75 {88, 77, 66, 55, 44, 33, 22, 11}, 76 }; 77 return values[i]; 78 } 79 }; 80 81 template <> 82 struct Values<uint32_t> 83 { 84 static auto& get(size_t i) 85 { 86 static const std::array<uint32_t, 8> values = { 87 {0xffffffff, 1, 3, 0, 5, 7, 9, 0xffffffff}, 88 }; 89 return values[i]; 90 } 91 }; 92 93 template <> 94 struct Values<uint64_t> 95 { 96 static auto& get(size_t i) 97 { 98 static const std::array<uint64_t, 8> values = { 99 {0xffffffffffffffff, 3, 7, 12234, 0, 3, 9, 0xffffffff}, 100 }; 101 return values[i]; 102 } 103 }; 104 105 template <> 106 struct Values<std::string> 107 { 108 static auto& get(size_t i) 109 { 110 static const std::array<std::string, 8> values = { 111 {""s, "foo"s, "bar"s, "baz"s, "hello"s, "string", "\x2\x3", "\\"}, 112 }; 113 return values[i]; 114 } 115 }; 116 117 template <typename T> 118 void nonFilteredCheck(const std::any& value, const size_t ndx) 119 { 120 ASSERT_EQ(value.has_value(), true); 121 ASSERT_EQ(std::any_cast<T>(value), Values<T>::get(ndx)); 122 } 123 124 template <typename T> 125 struct FilteredValues 126 { 127 }; 128 129 template <> 130 struct FilteredValues<uint8_t> 131 { 132 static auto& opFilters() 133 { 134 static std::unique_ptr<OperandFilters<uint8_t>> filters = 135 std::make_unique<OperandFilters<uint8_t>>( 136 std::vector<std::function<bool(uint8_t)>>{ 137 [](const auto& value) { return value < 4; }}); 138 return filters; 139 } 140 static auto& expected(size_t i) 141 { 142 static const std::array<std::any, 8> values = { 143 {std::any(uint8_t(0)), std::any(uint8_t(1)), std::any(uint8_t(2)), 144 std::any(uint8_t(3)), std::any(), std::any(), std::any(), 145 std::any()}}; 146 return values[i]; 147 } 148 }; 149 150 template <> 151 struct FilteredValues<uint16_t> 152 { 153 static auto& opFilters() 154 { 155 static std::unique_ptr<OperandFilters<uint16_t>> filters = 156 std::make_unique<OperandFilters<uint16_t>>( 157 std::vector<std::function<bool(uint16_t)>>{ 158 [](const auto& value) { return value > 44; }, 159 [](const auto& value) { return value != 88; }}); 160 return filters; 161 } 162 static auto& expected(size_t i) 163 { 164 static const std::array<std::any, 8> values = { 165 {std::any(), std::any(uint16_t(77)), std::any(uint16_t(66)), 166 std::any(uint16_t(55)), std::any(), std::any(), std::any(), 167 std::any()}}; 168 return values[i]; 169 } 170 }; 171 172 template <> 173 struct FilteredValues<uint32_t> 174 { 175 static auto& opFilters() 176 { 177 static std::unique_ptr<OperandFilters<uint32_t>> filters = 178 std::make_unique<OperandFilters<uint32_t>>( 179 std::vector<std::function<bool(uint32_t)>>{ 180 [](const auto& value) { return value != 0xffffffff; }, 181 [](const auto& value) { return value != 0; }}); 182 return filters; 183 } 184 static auto& expected(size_t i) 185 { 186 static const std::array<std::any, 8> values = { 187 {std::any(), std::any(uint32_t(1)), std::any(uint32_t(3)), 188 std::any(), std::any(uint32_t(5)), std::any(uint32_t(7)), 189 std::any(uint32_t(9)), std::any()}}; 190 return values[i]; 191 } 192 }; 193 194 template <> 195 struct FilteredValues<uint64_t> 196 { 197 static auto& opFilters() 198 { 199 static std::unique_ptr<OperandFilters<uint64_t>> filters = 200 std::make_unique<OperandFilters<uint64_t>>( 201 std::vector<std::function<bool(uint64_t)>>{ 202 [](const auto& value) { return (value % 3) != 0; }}); 203 return filters; 204 } 205 static auto& expected(size_t i) 206 { 207 static const std::array<std::any, 8> values = { 208 {std::any(), std::any(), std::any(uint64_t(7)), std::any(), 209 std::any(), std::any(), std::any(), std::any()}}; 210 return values[i]; 211 } 212 }; 213 214 template <> 215 struct FilteredValues<std::string> 216 { 217 static auto& opFilters() 218 { 219 static std::unique_ptr<OperandFilters<std::string>> filters = 220 std::make_unique<OperandFilters<std::string>>( 221 std::vector<std::function<bool(std::string)>>{ 222 [](const auto& value) { return value != ""s; }, 223 [](const auto& value) { return value != "string"s; }}); 224 return filters; 225 } 226 static auto& expected(size_t i) 227 { 228 static const std::array<std::any, 8> values = { 229 {std::any(), std::any("foo"s), std::any("bar"s), std::any("baz"s), 230 std::any("hello"s), std::any(), std::any("\x2\x3"s), 231 std::any("\\"s)}}; 232 return values[i]; 233 } 234 }; 235 236 template <typename T> 237 void filteredCheck(const std::any& value, const size_t ndx) 238 { 239 ASSERT_EQ(value.has_value(), FilteredValues<T>::expected(ndx).has_value()); 240 if (value.has_value()) 241 { 242 ASSERT_EQ(std::any_cast<T>(value), 243 std::any_cast<T>(FilteredValues<T>::expected(ndx))); 244 } 245 } 246 247 template <typename T> 248 void testStart(std::function<void(const std::any&, const size_t)>&& checkState, 249 OperandFilters<T>* opFilters = nullptr) 250 { 251 using ::testing::_; 252 using ::testing::Return; 253 254 MockDBusInterface dbus; 255 MockDBusInterface::instance(dbus); 256 257 const std::vector<std::string> expectedMapperInterfaces; 258 PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex, false, 259 opFilters); 260 261 auto ndx = static_cast<size_t>(0); 262 for (const auto& o : convert(watchIndex)) 263 { 264 const auto& path = o.first.get(); 265 const auto& interfaces = o.second; 266 std::vector<std::string> mapperResponse; 267 std::transform(interfaces.begin(), interfaces.end(), 268 std::back_inserter(mapperResponse), 269 // *INDENT-OFF* 270 [](const auto& item) { return item.first; }); 271 // *INDENT-ON* 272 EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH, 273 MAPPER_INTERFACE, "GetObject", path, 274 expectedMapperInterfaces)) 275 .WillOnce(Return(GetObject({{"", mapperResponse}}))); 276 EXPECT_CALL( 277 dbus, fwdAddMatch( 278 sdbusplus::bus::match::rules::interfacesAdded(path), _)); 279 for (const auto& i : interfaces) 280 { 281 const auto& interface = i.first.get(); 282 const auto& properties = i.second; 283 EXPECT_CALL( 284 dbus, 285 fwdAddMatch(sdbusplus::bus::match::rules::propertiesChanged( 286 path, interface), 287 _)); 288 289 PropertiesChanged<T> serviceResponse; 290 for (const auto& p : properties) 291 { 292 serviceResponse[p] = Values<T>::get(ndx); 293 ++ndx; 294 } 295 Expect<T>::getProperties(dbus, path, interface) 296 .WillOnce(Return(serviceResponse)); 297 } 298 } 299 300 watch.start(); 301 302 ndx = 0; 303 for (auto s : storage) 304 { 305 checkState(std::get<valueIndex>(s), ndx); 306 ++ndx; 307 } 308 309 // Make sure start logic only runs the first time. 310 watch.start(); 311 } 312 313 TEST(PropertyWatchTest, TestStart) 314 { 315 testStart<uint8_t>(nonFilteredCheck<uint8_t>); 316 testStart<uint16_t>(nonFilteredCheck<uint16_t>); 317 testStart<uint32_t>(nonFilteredCheck<uint32_t>); 318 testStart<uint64_t>(nonFilteredCheck<uint64_t>); 319 testStart<std::string>(nonFilteredCheck<std::string>); 320 } 321 322 TEST(PropertyWatchTest, TestFilters) 323 { 324 testStart<uint8_t>(filteredCheck<uint8_t>, 325 FilteredValues<uint8_t>::opFilters().get()); 326 testStart<uint16_t>(filteredCheck<uint16_t>, 327 FilteredValues<uint16_t>::opFilters().get()); 328 testStart<uint32_t>(filteredCheck<uint32_t>, 329 FilteredValues<uint32_t>::opFilters().get()); 330 testStart<uint64_t>(filteredCheck<uint64_t>, 331 FilteredValues<uint64_t>::opFilters().get()); 332 testStart<std::string>(filteredCheck<std::string>, 333 FilteredValues<std::string>::opFilters().get()); 334 } 335 336 MockDBusInterface* MockDBusInterface::ptr = nullptr; 337