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<any_ns::any, any_ns::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 any_ns::any& value, const size_t ndx) 119 { 120 ASSERT_EQ(value.empty(), false); 121 ASSERT_EQ(any_ns::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<any_ns::any, 8> values = { 143 {any_ns::any(uint8_t(0)), any_ns::any(uint8_t(1)), 144 any_ns::any(uint8_t(2)), any_ns::any(uint8_t(3)), any_ns::any(), 145 any_ns::any(), any_ns::any(), any_ns::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<any_ns::any, 8> values = { 165 {any_ns::any(), any_ns::any(uint16_t(77)), 166 any_ns::any(uint16_t(66)), any_ns::any(uint16_t(55)), 167 any_ns::any(), any_ns::any(), any_ns::any(), any_ns::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<any_ns::any, 8> values = { 187 {any_ns::any(), any_ns::any(uint32_t(1)), any_ns::any(uint32_t(3)), 188 any_ns::any(), any_ns::any(uint32_t(5)), any_ns::any(uint32_t(7)), 189 any_ns::any(uint32_t(9)), any_ns::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<any_ns::any, 8> values = { 208 {any_ns::any(), any_ns::any(), any_ns::any(uint64_t(7)), 209 any_ns::any(), any_ns::any(), any_ns::any(), any_ns::any(), 210 any_ns::any()}}; 211 return values[i]; 212 } 213 }; 214 215 template <> 216 struct FilteredValues<std::string> 217 { 218 static auto& opFilters() 219 { 220 static std::unique_ptr<OperandFilters<std::string>> filters = 221 std::make_unique<OperandFilters<std::string>>( 222 std::vector<std::function<bool(std::string)>>{ 223 [](const auto& value) { return value != ""s; }, 224 [](const auto& value) { return value != "string"s; }}); 225 return filters; 226 } 227 static auto& expected(size_t i) 228 { 229 static const std::array<any_ns::any, 8> values = { 230 {any_ns::any(), any_ns::any("foo"s), any_ns::any("bar"s), 231 any_ns::any("baz"s), any_ns::any("hello"s), any_ns::any(), 232 any_ns::any("\x2\x3"s), any_ns::any("\\"s)}}; 233 return values[i]; 234 } 235 }; 236 237 template <typename T> 238 void filteredCheck(const any_ns::any& value, const size_t ndx) 239 { 240 ASSERT_EQ(value.empty(), FilteredValues<T>::expected(ndx).empty()); 241 if (!value.empty()) 242 { 243 ASSERT_EQ(any_ns::any_cast<T>(value), 244 any_ns::any_cast<T>(FilteredValues<T>::expected(ndx))); 245 } 246 } 247 248 template <typename T> 249 void testStart( 250 std::function<void(const any_ns::any&, const size_t)>&& checkState, 251 OperandFilters<T>* opFilters = nullptr) 252 { 253 using ::testing::_; 254 using ::testing::Return; 255 256 MockDBusInterface dbus; 257 MockDBusInterface::instance(dbus); 258 259 const std::vector<std::string> expectedMapperInterfaces; 260 PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex, opFilters); 261 262 auto ndx = static_cast<size_t>(0); 263 for (const auto& o : convert(watchIndex)) 264 { 265 const auto& path = o.first.get(); 266 const auto& interfaces = o.second; 267 std::vector<std::string> mapperResponse; 268 std::transform(interfaces.begin(), interfaces.end(), 269 std::back_inserter(mapperResponse), 270 // *INDENT-OFF* 271 [](const auto& item) { return item.first; }); 272 // *INDENT-ON* 273 EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH, 274 MAPPER_INTERFACE, "GetObject", path, 275 expectedMapperInterfaces)) 276 .WillOnce(Return(GetObject({{"", mapperResponse}}))); 277 EXPECT_CALL( 278 dbus, fwdAddMatch( 279 sdbusplus::bus::match::rules::interfacesAdded(path), _)); 280 for (const auto& i : interfaces) 281 { 282 const auto& interface = i.first.get(); 283 const auto& properties = i.second; 284 EXPECT_CALL( 285 dbus, 286 fwdAddMatch(sdbusplus::bus::match::rules::propertiesChanged( 287 path, interface), 288 _)); 289 290 PropertiesChanged<T> serviceResponse; 291 for (const auto& p : properties) 292 { 293 serviceResponse[p] = Values<T>::get(ndx); 294 ++ndx; 295 } 296 Expect<T>::getProperties(dbus, path, interface) 297 .WillOnce(Return(serviceResponse)); 298 } 299 } 300 301 watch.start(); 302 303 ndx = 0; 304 for (auto s : storage) 305 { 306 checkState(std::get<valueIndex>(s), ndx); 307 ++ndx; 308 } 309 310 // Make sure start logic only runs the first time. 311 watch.start(); 312 } 313 314 TEST(PropertyWatchTest, TestStart) 315 { 316 testStart<uint8_t>(nonFilteredCheck<uint8_t>); 317 testStart<uint16_t>(nonFilteredCheck<uint16_t>); 318 testStart<uint32_t>(nonFilteredCheck<uint32_t>); 319 testStart<uint64_t>(nonFilteredCheck<uint64_t>); 320 testStart<std::string>(nonFilteredCheck<std::string>); 321 } 322 323 TEST(PropertyWatchTest, TestFilters) 324 { 325 testStart<uint8_t>(filteredCheck<uint8_t>, 326 FilteredValues<uint8_t>::opFilters().get()); 327 testStart<uint16_t>(filteredCheck<uint16_t>, 328 FilteredValues<uint16_t>::opFilters().get()); 329 testStart<uint32_t>(filteredCheck<uint32_t>, 330 FilteredValues<uint32_t>::opFilters().get()); 331 testStart<uint64_t>(filteredCheck<uint64_t>, 332 FilteredValues<uint64_t>::opFilters().get()); 333 testStart<std::string>(filteredCheck<std::string>, 334 FilteredValues<std::string>::opFilters().get()); 335 } 336 337 MockDBusInterface* MockDBusInterface::ptr = nullptr; 338