1 #include <array> 2 #include "propertywatchimpl.hpp" 3 #include "propertywatchtest.hpp" 4 5 using namespace std::string_literals; 6 using namespace phosphor::dbus::monitoring; 7 8 const std::array<std::string, 4> paths = { 9 "/xyz/openbmc_project/testing/inst1"s, 10 "/xyz/openbmc_project/testing/inst2"s, 11 "/xyz/openbmc_project/testing/inst3"s, 12 "/xyz/openbmc_project/testing/inst4"s, 13 }; 14 15 const std::array<std::string, 2> interfaces = { 16 "xyz.openbmc_project.Iface1"s, 17 "xyz.openbmc_project.Iface2"s, 18 }; 19 20 const std::array<std::string, 2> properties = { 21 "Value1"s, 22 "Value2"s, 23 }; 24 25 const std::string meta; 26 27 std::array<std::tuple<any_ns::any, any_ns::any>, 8> storage = {}; 28 29 const PropertyIndex watchIndex = { 30 { 31 {PropertyIndex::key_type{paths[0], interfaces[0], properties[0]}, 32 PropertyIndex::mapped_type{meta, meta, storage[0]}}, 33 {PropertyIndex::key_type{paths[0], interfaces[1], properties[1]}, 34 PropertyIndex::mapped_type{meta, meta, storage[1]}}, 35 {PropertyIndex::key_type{paths[1], interfaces[0], properties[0]}, 36 PropertyIndex::mapped_type{meta, meta, storage[2]}}, 37 {PropertyIndex::key_type{paths[1], interfaces[1], properties[1]}, 38 PropertyIndex::mapped_type{meta, meta, storage[3]}}, 39 {PropertyIndex::key_type{paths[2], interfaces[0], properties[0]}, 40 PropertyIndex::mapped_type{meta, meta, storage[4]}}, 41 {PropertyIndex::key_type{paths[2], interfaces[1], properties[1]}, 42 PropertyIndex::mapped_type{meta, meta, storage[5]}}, 43 {PropertyIndex::key_type{paths[3], interfaces[0], properties[0]}, 44 PropertyIndex::mapped_type{meta, meta, storage[6]}}, 45 {PropertyIndex::key_type{paths[3], interfaces[1], properties[1]}, 46 PropertyIndex::mapped_type{meta, meta, storage[7]}}, 47 }, 48 }; 49 50 template <typename T> struct ExpectedValues 51 { 52 }; 53 template <> struct ExpectedValues<uint8_t> 54 { 55 static auto& get(size_t i) 56 { 57 static const std::array<uint8_t, 8> values = { 58 {0, 1, 2, 3, 4, 5, 6, 7}, 59 }; 60 return values[i]; 61 } 62 }; 63 64 template <> struct ExpectedValues<uint16_t> 65 { 66 static auto& get(size_t i) 67 { 68 static const std::array<uint16_t, 8> values = { 69 {88, 77, 66, 55, 44, 33, 22, 11}, 70 }; 71 return values[i]; 72 } 73 }; 74 75 template <> struct ExpectedValues<uint32_t> 76 { 77 static auto& get(size_t i) 78 { 79 static const std::array<uint32_t, 8> values = { 80 {0xffffffff, 1, 3, 0, 5, 7, 9, 0xffffffff}, 81 }; 82 return values[i]; 83 } 84 }; 85 86 template <> struct ExpectedValues<uint64_t> 87 { 88 static auto& get(size_t i) 89 { 90 static const std::array<uint64_t, 8> values = { 91 {0xffffffffffffffff, 3, 7, 12234, 0, 3, 9, 0xffffffff}, 92 }; 93 return values[i]; 94 } 95 }; 96 97 template <> struct ExpectedValues<std::string> 98 { 99 static auto& get(size_t i) 100 { 101 static const std::array<std::string, 8> values = { 102 {""s, "foo"s, "bar"s, "baz"s, "hello"s, "string", "\x2\x3", "\\"}, 103 }; 104 return values[i]; 105 } 106 }; 107 108 template <typename T> void testStart() 109 { 110 using ::testing::Return; 111 using ::testing::_; 112 113 MockDBusInterface dbus; 114 MockDBusInterface::instance(dbus); 115 116 const std::vector<std::string> expectedMapperInterfaces; 117 PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex); 118 119 auto ndx = static_cast<size_t>(0); 120 for (const auto& o : convert(watchIndex)) 121 { 122 const auto& path = o.first.get(); 123 const auto& interfaces = o.second; 124 std::vector<std::string> mapperResponse; 125 std::transform(interfaces.begin(), interfaces.end(), 126 std::back_inserter(mapperResponse), 127 // *INDENT-OFF* 128 [](const auto& item) { return item.first; }); 129 // *INDENT-ON* 130 EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH, 131 MAPPER_INTERFACE, "GetObject", path, 132 expectedMapperInterfaces)) 133 .WillOnce(Return(GetObject({{"", mapperResponse}}))); 134 EXPECT_CALL( 135 dbus, fwdAddMatch( 136 sdbusplus::bus::match::rules::member("InterfacesAdded") + 137 sdbusplus::bus::match::rules::path(path) + 138 sdbusplus::bus::match::rules::interface( 139 "org.freedesktop.DBus.ObjectManager"), 140 _)); 141 for (const auto& i : interfaces) 142 { 143 const auto& interface = i.first.get(); 144 const auto& properties = i.second; 145 EXPECT_CALL( 146 dbus, 147 fwdAddMatch( 148 sdbusplus::bus::match::rules::member("PropertiesChanged") + 149 sdbusplus::bus::match::rules::path(path) + 150 sdbusplus::bus::match::rules::argN(0, interface) + 151 sdbusplus::bus::match::rules::interface( 152 "org.freedesktop.DBus.Properties"), 153 _)); 154 155 PropertiesChanged<T> serviceResponse; 156 for (const auto& p : properties) 157 { 158 serviceResponse[p] = ExpectedValues<T>::get(ndx); 159 ++ndx; 160 } 161 Expect<T>::getProperties(dbus, path, interface) 162 .WillOnce(Return(serviceResponse)); 163 } 164 } 165 166 watch.start(); 167 168 ndx = 0; 169 for (auto s : storage) 170 { 171 ASSERT_EQ(std::get<0>(s).empty(), false); 172 ASSERT_EQ(any_ns::any_cast<T>(s), ExpectedValues<T>::get(ndx)); 173 ++ndx; 174 } 175 176 // Make sure start logic only runs the first time. 177 watch.start(); 178 } 179 180 TEST(PropertyWatchTest, TestStart) 181 { 182 testStart<uint8_t>(); 183 testStart<uint16_t>(); 184 testStart<uint32_t>(); 185 testStart<uint64_t>(); 186 testStart<std::string>(); 187 } 188 189 MockDBusInterface* MockDBusInterface::ptr = nullptr; 190