1 #include "propertywatchtest.hpp"
2 
3 #include "propertywatchimpl.hpp"
4 
5 #include <array>
6 
7 using namespace std::string_literals;
8 using namespace phosphor::dbus::monitoring;
9 
10 const std::array<std::string, 4> paths = {
11     "/xyz/openbmc_project/testing/inst1"s,
12     "/xyz/openbmc_project/testing/inst2"s,
13     "/xyz/openbmc_project/testing/inst3"s,
14     "/xyz/openbmc_project/testing/inst4"s,
15 };
16 
17 const std::array<std::string, 2> interfaces = {
18     "xyz.openbmc_project.Iface1"s,
19     "xyz.openbmc_project.Iface2"s,
20 };
21 
22 const std::array<std::string, 2> properties = {
23     "Value1"s,
24     "Value2"s,
25 };
26 
27 const std::string meta;
28 
29 std::array<std::tuple<any_ns::any, any_ns::any>, 8> storage = {};
30 
31 const PropertyIndex watchIndex = {
32     {
33         {PropertyIndex::key_type{paths[0], interfaces[0], properties[0]},
34          PropertyIndex::mapped_type{meta, meta, storage[0]}},
35         {PropertyIndex::key_type{paths[0], interfaces[1], properties[1]},
36          PropertyIndex::mapped_type{meta, meta, storage[1]}},
37         {PropertyIndex::key_type{paths[1], interfaces[0], properties[0]},
38          PropertyIndex::mapped_type{meta, meta, storage[2]}},
39         {PropertyIndex::key_type{paths[1], interfaces[1], properties[1]},
40          PropertyIndex::mapped_type{meta, meta, storage[3]}},
41         {PropertyIndex::key_type{paths[2], interfaces[0], properties[0]},
42          PropertyIndex::mapped_type{meta, meta, storage[4]}},
43         {PropertyIndex::key_type{paths[2], interfaces[1], properties[1]},
44          PropertyIndex::mapped_type{meta, meta, storage[5]}},
45         {PropertyIndex::key_type{paths[3], interfaces[0], properties[0]},
46          PropertyIndex::mapped_type{meta, meta, storage[6]}},
47         {PropertyIndex::key_type{paths[3], interfaces[1], properties[1]},
48          PropertyIndex::mapped_type{meta, meta, storage[7]}},
49     },
50 };
51 
52 template <typename T>
53 struct ExpectedValues
54 {
55 };
56 template <>
57 struct ExpectedValues<uint8_t>
58 {
59     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 ExpectedValues<uint16_t>
70 {
71     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 ExpectedValues<uint32_t>
82 {
83     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 ExpectedValues<uint64_t>
94 {
95     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 ExpectedValues<std::string>
106 {
107     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>
117 void testStart()
118 {
119     using ::testing::_;
120     using ::testing::Return;
121 
122     MockDBusInterface dbus;
123     MockDBusInterface::instance(dbus);
124 
125     const std::vector<std::string> expectedMapperInterfaces;
126     PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex);
127 
128     auto ndx = static_cast<size_t>(0);
129     for (const auto& o : convert(watchIndex))
130     {
131         const auto& path = o.first.get();
132         const auto& interfaces = o.second;
133         std::vector<std::string> mapperResponse;
134         std::transform(interfaces.begin(), interfaces.end(),
135                        std::back_inserter(mapperResponse),
136                        // *INDENT-OFF*
137                        [](const auto& item) { return item.first; });
138         // *INDENT-ON*
139         EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH,
140                                           MAPPER_INTERFACE, "GetObject", path,
141                                           expectedMapperInterfaces))
142             .WillOnce(Return(GetObject({{"", mapperResponse}})));
143         EXPECT_CALL(
144             dbus, fwdAddMatch(
145                       sdbusplus::bus::match::rules::member("InterfacesAdded") +
146                           sdbusplus::bus::match::rules::path(path) +
147                           sdbusplus::bus::match::rules::interface(
148                               "org.freedesktop.DBus.ObjectManager"),
149                       _));
150         for (const auto& i : interfaces)
151         {
152             const auto& interface = i.first.get();
153             const auto& properties = i.second;
154             EXPECT_CALL(
155                 dbus,
156                 fwdAddMatch(
157                     sdbusplus::bus::match::rules::member("PropertiesChanged") +
158                         sdbusplus::bus::match::rules::path(path) +
159                         sdbusplus::bus::match::rules::argN(0, interface) +
160                         sdbusplus::bus::match::rules::interface(
161                             "org.freedesktop.DBus.Properties"),
162                     _));
163 
164             PropertiesChanged<T> serviceResponse;
165             for (const auto& p : properties)
166             {
167                 serviceResponse[p] = ExpectedValues<T>::get(ndx);
168                 ++ndx;
169             }
170             Expect<T>::getProperties(dbus, path, interface)
171                 .WillOnce(Return(serviceResponse));
172         }
173     }
174 
175     watch.start();
176 
177     ndx = 0;
178     for (auto s : storage)
179     {
180         ASSERT_EQ(std::get<0>(s).empty(), false);
181         ASSERT_EQ(any_ns::any_cast<T>(s), ExpectedValues<T>::get(ndx));
182         ++ndx;
183     }
184 
185     // Make sure start logic only runs the first time.
186     watch.start();
187 }
188 
189 TEST(PropertyWatchTest, TestStart)
190 {
191     testStart<uint8_t>();
192     testStart<uint16_t>();
193     testStart<uint32_t>();
194     testStart<uint64_t>();
195     testStart<std::string>();
196 }
197 
198 MockDBusInterface* MockDBusInterface::ptr = nullptr;
199