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