xref: /openbmc/phosphor-dbus-monitor/src/test/propertywatchtest.cpp (revision 34ef1e526b8eedf5ce9a0396b2a2627218a39378)
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