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