xref: /openbmc/phosphor-dbus-monitor/src/test/propertywatchtest.cpp (revision ecef119120e31b5bdf0d316c7303a9ce48831464)
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 {
getValues59     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 {
getValues71     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 {
getValues83     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 {
getValues95     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 {
getValues107     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>
nonFilteredCheck(const std::any & value,const size_t ndx)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 {
opFiltersFilteredValues130     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     }
expectedFilteredValues138     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 {
opFiltersFilteredValues151     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     }
expectedFilteredValues160     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 {
opFiltersFilteredValues173     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     }
expectedFilteredValues182     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 {
opFiltersFilteredValues195     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     }
expectedFilteredValues203     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 {
opFiltersFilteredValues215     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     }
expectedFilteredValues224     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>
filteredCheck(const std::any & value,const size_t ndx)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>
testStart(std::function<void (const std::any &,const size_t)> && checkState,OperandFilters<T> * opFilters=nullptr)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 
TEST(PropertyWatchTest,TestStart)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 
TEST(PropertyWatchTest,TestFilters)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