#include "propertywatchtest.hpp" #include "propertywatchimpl.hpp" #include #include using namespace std::string_literals; using namespace phosphor::dbus::monitoring; const std::array paths = { "/xyz/openbmc_project/testing/inst1"s, "/xyz/openbmc_project/testing/inst2"s, "/xyz/openbmc_project/testing/inst3"s, "/xyz/openbmc_project/testing/inst4"s, }; const std::array interfaces = { "xyz.openbmc_project.Iface1"s, "xyz.openbmc_project.Iface2"s, }; const std::array properties = { "Value1"s, "Value2"s, }; const std::string meta; std::array, 8> storage = {}; const PropertyIndex watchIndex = { { {PropertyIndex::key_type{paths[0], interfaces[0], properties[0]}, PropertyIndex::mapped_type{meta, meta, storage[0]}}, {PropertyIndex::key_type{paths[0], interfaces[1], properties[1]}, PropertyIndex::mapped_type{meta, meta, storage[1]}}, {PropertyIndex::key_type{paths[1], interfaces[0], properties[0]}, PropertyIndex::mapped_type{meta, meta, storage[2]}}, {PropertyIndex::key_type{paths[1], interfaces[1], properties[1]}, PropertyIndex::mapped_type{meta, meta, storage[3]}}, {PropertyIndex::key_type{paths[2], interfaces[0], properties[0]}, PropertyIndex::mapped_type{meta, meta, storage[4]}}, {PropertyIndex::key_type{paths[2], interfaces[1], properties[1]}, PropertyIndex::mapped_type{meta, meta, storage[5]}}, {PropertyIndex::key_type{paths[3], interfaces[0], properties[0]}, PropertyIndex::mapped_type{meta, meta, storage[6]}}, {PropertyIndex::key_type{paths[3], interfaces[1], properties[1]}, PropertyIndex::mapped_type{meta, meta, storage[7]}}, }, }; template struct Values {}; template <> struct Values { static auto& get(size_t i) { static const std::array values = { {0, 1, 2, 3, 4, 5, 6, 7}, }; return values[i]; } }; template <> struct Values { static auto& get(size_t i) { static const std::array values = { {88, 77, 66, 55, 44, 33, 22, 11}, }; return values[i]; } }; template <> struct Values { static auto& get(size_t i) { static const std::array values = { {0xffffffff, 1, 3, 0, 5, 7, 9, 0xffffffff}, }; return values[i]; } }; template <> struct Values { static auto& get(size_t i) { static const std::array values = { {0xffffffffffffffff, 3, 7, 12234, 0, 3, 9, 0xffffffff}, }; return values[i]; } }; template <> struct Values { static auto& get(size_t i) { static const std::array values = { {""s, "foo"s, "bar"s, "baz"s, "hello"s, "string", "\x2\x3", "\\"}, }; return values[i]; } }; template void nonFilteredCheck(const std::any& value, const size_t ndx) { ASSERT_EQ(value.has_value(), true); ASSERT_EQ(std::any_cast(value), Values::get(ndx)); } template struct FilteredValues {}; template <> struct FilteredValues { static auto& opFilters() { static std::unique_ptr> filters = std::make_unique>( std::vector>{ [](const auto& value) { return value < 4; }}); return filters; } static auto& expected(size_t i) { static const std::array values = { {std::any(uint8_t(0)), std::any(uint8_t(1)), std::any(uint8_t(2)), std::any(uint8_t(3)), std::any(), std::any(), std::any(), std::any()}}; return values[i]; } }; template <> struct FilteredValues { static auto& opFilters() { static std::unique_ptr> filters = std::make_unique>( std::vector>{ [](const auto& value) { return value > 44; }, [](const auto& value) { return value != 88; }}); return filters; } static auto& expected(size_t i) { static const std::array values = { {std::any(), std::any(uint16_t(77)), std::any(uint16_t(66)), std::any(uint16_t(55)), std::any(), std::any(), std::any(), std::any()}}; return values[i]; } }; template <> struct FilteredValues { static auto& opFilters() { static std::unique_ptr> filters = std::make_unique>( std::vector>{ [](const auto& value) { return value != 0xffffffff; }, [](const auto& value) { return value != 0; }}); return filters; } static auto& expected(size_t i) { static const std::array values = { {std::any(), std::any(uint32_t(1)), std::any(uint32_t(3)), std::any(), std::any(uint32_t(5)), std::any(uint32_t(7)), std::any(uint32_t(9)), std::any()}}; return values[i]; } }; template <> struct FilteredValues { static auto& opFilters() { static std::unique_ptr> filters = std::make_unique>( std::vector>{ [](const auto& value) { return (value % 3) != 0; }}); return filters; } static auto& expected(size_t i) { static const std::array values = { {std::any(), std::any(), std::any(uint64_t(7)), std::any(), std::any(), std::any(), std::any(), std::any()}}; return values[i]; } }; template <> struct FilteredValues { static auto& opFilters() { static std::unique_ptr> filters = std::make_unique>( std::vector>{ [](const auto& value) { return value != ""s; }, [](const auto& value) { return value != "string"s; }}); return filters; } static auto& expected(size_t i) { static const std::array values = { {std::any(), std::any("foo"s), std::any("bar"s), std::any("baz"s), std::any("hello"s), std::any(), std::any("\x2\x3"s), std::any("\\"s)}}; return values[i]; } }; template void filteredCheck(const std::any& value, const size_t ndx) { ASSERT_EQ(value.has_value(), FilteredValues::expected(ndx).has_value()); if (value.has_value()) { ASSERT_EQ(std::any_cast(value), std::any_cast(FilteredValues::expected(ndx))); } } template void testStart(std::function&& checkState, OperandFilters* opFilters = nullptr) { using ::testing::_; using ::testing::Return; MockDBusInterface dbus; MockDBusInterface::instance(dbus); const std::vector expectedMapperInterfaces; PropertyWatchOfType watch(watchIndex, false, opFilters); auto ndx = static_cast(0); for (const auto& o : convert(watchIndex)) { const auto& path = o.first.get(); const auto& tmpInterfaces = o.second; std::vector mapperResponse; std::transform(tmpInterfaces.begin(), tmpInterfaces.end(), std::back_inserter(mapperResponse), // *INDENT-OFF* [](const auto& item) { return item.first; }); // *INDENT-ON* EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject", path, expectedMapperInterfaces)) .WillOnce(Return(GetObject({{"", mapperResponse}}))); EXPECT_CALL( dbus, fwdAddMatch( sdbusplus::bus::match::rules::interfacesAdded(path), _)); for (const auto& i : tmpInterfaces) { const auto& interface = i.first.get(); const auto& tmpProperties = i.second; EXPECT_CALL( dbus, fwdAddMatch(sdbusplus::bus::match::rules::propertiesChanged( path, interface), _)); PropertiesChanged serviceResponse; for (const auto& p : tmpProperties) { serviceResponse[p] = Values::get(ndx); ++ndx; } Expect::getProperties(dbus, path, interface) .WillOnce(Return(serviceResponse)); } } watch.start(); ndx = 0; for (auto s : storage) { checkState(std::get(s), ndx); ++ndx; } // Make sure start logic only runs the first time. watch.start(); } TEST(PropertyWatchTest, TestStart) { testStart(nonFilteredCheck); testStart(nonFilteredCheck); testStart(nonFilteredCheck); testStart(nonFilteredCheck); testStart(nonFilteredCheck); } TEST(PropertyWatchTest, TestFilters) { testStart(filteredCheck, FilteredValues::opFilters().get()); testStart(filteredCheck, FilteredValues::opFilters().get()); testStart(filteredCheck, FilteredValues::opFilters().get()); testStart(filteredCheck, FilteredValues::opFilters().get()); testStart(filteredCheck, FilteredValues::opFilters().get()); } MockDBusInterface* MockDBusInterface::ptr = nullptr;